зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to fx-team
This commit is contained in:
Коммит
e929ac9097
3
CLOBBER
3
CLOBBER
|
@ -22,5 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Bug 1014976 - Windows debug bustage from linking changes.
|
||||
|
||||
Preemptive clobber for a vm/Xdr.h change to evade bug 1019955 (should it have otherwise arisen, which is unclear).
|
||||
|
|
|
@ -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="d2cfef555dabab415085e548ed44c48a99be5c32"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="8e4420c0c5c8e8c8e58a000278a7129403769f96"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d2cfef555dabab415085e548ed44c48a99be5c32"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="994fa9a1f7ce0e63c880a48d571c3ab3e01884a3"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="276ce45e78b09c4a4ee643646f691d22804754c1">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d2cfef555dabab415085e548ed44c48a99be5c32"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d2cfef555dabab415085e548ed44c48a99be5c32"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="8e4420c0c5c8e8c8e58a000278a7129403769f96"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d2cfef555dabab415085e548ed44c48a99be5c32"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="994fa9a1f7ce0e63c880a48d571c3ab3e01884a3"/>
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "7f0af1e164a39efb732c0c341c2a8e51f681d913",
|
||||
"revision": "c3d40600c0090c5ca6ca4427f3a870ff443a109d",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d2cfef555dabab415085e548ed44c48a99be5c32"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d2cfef555dabab415085e548ed44c48a99be5c32"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d2cfef555dabab415085e548ed44c48a99be5c32"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="994fa9a1f7ce0e63c880a48d571c3ab3e01884a3"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d2cfef555dabab415085e548ed44c48a99be5c32"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -2885,7 +2885,7 @@
|
|||
onget="return this.mCurrentBrowser.isSyntheticDocument;"
|
||||
readonly="true"/>
|
||||
|
||||
<method name="_handleKeyEvent">
|
||||
<method name="_handleKeyDownEvent">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
if (!aEvent.isTrusted) {
|
||||
|
@ -2896,21 +2896,44 @@
|
|||
if (aEvent.altKey)
|
||||
return;
|
||||
|
||||
// Don't check if the event was already consumed because tab
|
||||
// navigation should always work for better user experience.
|
||||
|
||||
if (aEvent.ctrlKey && aEvent.shiftKey && !aEvent.metaKey) {
|
||||
switch (aEvent.keyCode) {
|
||||
case aEvent.DOM_VK_PAGE_UP:
|
||||
this.moveTabBackward();
|
||||
aEvent.stopPropagation();
|
||||
aEvent.preventDefault();
|
||||
return;
|
||||
case aEvent.DOM_VK_PAGE_DOWN:
|
||||
this.moveTabForward();
|
||||
aEvent.stopPropagation();
|
||||
aEvent.preventDefault();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
if (aEvent.ctrlKey && !aEvent.shiftKey && !aEvent.metaKey &&
|
||||
aEvent.keyCode == KeyEvent.DOM_VK_F4 &&
|
||||
!this.mCurrentTab.pinned) {
|
||||
this.removeCurrentTab({animate: true});
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
#endif
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_handleKeyPressEvent">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
if (!aEvent.isTrusted) {
|
||||
// Don't let untrusted events mess with tabs.
|
||||
return;
|
||||
}
|
||||
|
||||
if (aEvent.altKey)
|
||||
return;
|
||||
|
||||
// We need to take care of FAYT-watching as long as the findbar
|
||||
// isn't initialized. The checks on aEvent are copied from
|
||||
// _shouldFastFind (see findbar.xml).
|
||||
|
@ -2940,17 +2963,8 @@
|
|||
if (window.getComputedStyle(this, null).direction == "ltr")
|
||||
offset *= -1;
|
||||
this.tabContainer.advanceSelectedTab(offset, true);
|
||||
aEvent.stopPropagation();
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
#else
|
||||
if (aEvent.ctrlKey && !aEvent.shiftKey && !aEvent.metaKey &&
|
||||
aEvent.keyCode == KeyEvent.DOM_VK_F4 &&
|
||||
!this.mCurrentTab.pinned) {
|
||||
this.removeCurrentTab({animate: true});
|
||||
aEvent.stopPropagation();
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
#endif
|
||||
]]></body>
|
||||
</method>
|
||||
|
@ -2982,8 +2996,11 @@
|
|||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
switch (aEvent.type) {
|
||||
case "keydown":
|
||||
this._handleKeyDownEvent(aEvent);
|
||||
break;
|
||||
case "keypress":
|
||||
this._handleKeyEvent(aEvent);
|
||||
this._handleKeyPressEvent(aEvent);
|
||||
break;
|
||||
case "sizemodechange":
|
||||
if (aEvent.target == window) {
|
||||
|
@ -3050,7 +3067,9 @@
|
|||
this.mCurrentBrowser = document.getAnonymousElementByAttribute(this, "anonid", "initialBrowser");
|
||||
|
||||
this.mCurrentTab = this.tabContainer.firstChild;
|
||||
document.addEventListener("keypress", this, false);
|
||||
let els = Cc["@mozilla.org/eventlistenerservice;1"].getService(Ci.nsIEventListenerService);
|
||||
els.addSystemEventListener(document, "keydown", this, false);
|
||||
els.addSystemEventListener(document, "keypress", this, false);
|
||||
window.addEventListener("sizemodechange", this, false);
|
||||
|
||||
var uniqueId = this._generateUniquePanelID();
|
||||
|
@ -3128,7 +3147,9 @@
|
|||
this.mTabListeners[i].destroy();
|
||||
this.mTabListeners[i] = null;
|
||||
}
|
||||
document.removeEventListener("keypress", this, false);
|
||||
let els = Cc["@mozilla.org/eventlistenerservice;1"].getService(Ci.nsIEventListenerService);
|
||||
els.removeSystemEventListener(document, "keydown", this, false);
|
||||
els.removeSystemEventListener(document, "keypress", this, false);
|
||||
window.removeEventListener("sizemodechange", this, false);
|
||||
|
||||
if (gMultiProcessBrowser) {
|
||||
|
@ -4247,7 +4268,7 @@
|
|||
event.stopPropagation();
|
||||
]]></handler>
|
||||
|
||||
<handler event="keypress"><![CDATA[
|
||||
<handler event="keydown" group="system"><![CDATA[
|
||||
if (event.altKey || event.shiftKey ||
|
||||
#ifdef XP_MACOSX
|
||||
!event.metaKey)
|
||||
|
@ -4256,6 +4277,9 @@
|
|||
#endif
|
||||
return;
|
||||
|
||||
// Don't check if the event was already consumed because tab navigation
|
||||
// should work always for better user experience.
|
||||
|
||||
switch (event.keyCode) {
|
||||
case KeyEvent.DOM_VK_UP:
|
||||
this.tabbrowser.moveTabBackward();
|
||||
|
@ -4274,11 +4298,10 @@
|
|||
this.tabbrowser.moveTabToEnd();
|
||||
break;
|
||||
default:
|
||||
// Stop the keypress event for the above keyboard
|
||||
// Consume the keydown event for the above keyboard
|
||||
// shortcuts only.
|
||||
return;
|
||||
}
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
]]></handler>
|
||||
|
||||
|
|
|
@ -380,6 +380,7 @@ skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux
|
|||
# Disabled on OS X because of bug 967917
|
||||
[browser_tabfocus.js]
|
||||
skip-if = e10s # Bug 921935 - focusmanager issues with e10s (test calls getFocusedElementForWindow with a content window)
|
||||
[browser_tabkeynavigation.js]
|
||||
[browser_tabopen_reflows.js]
|
||||
skip-if = e10s # Bug ?????? - test needs to be updated for e10s (captures a stack that isn't correct in e10s)
|
||||
[browser_tabs_isActive.js]
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* This test checks that keyboard navigation for tabs isn't blocked by content
|
||||
*/
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let testPage1 = "data:text/html,<html id='tab1'><body><button id='button1'>Tab 1</button></body></html>";
|
||||
let testPage2 = "data:text/html,<html id='tab2'><body><button id='button2'>Tab 2</button><script>function preventDefault(event) { event.preventDefault(); event.stopImmediatePropagation(); } window.addEventListener('keydown', preventDefault, true); window.addEventListener('keypress', preventDefault, true);</script></body></html>";
|
||||
let testPage3 = "data:text/html,<html id='tab3'><body><button id='button3'>Tab 3</button></body></html>";
|
||||
|
||||
let tab1 = gBrowser.addTab();
|
||||
let browser1 = gBrowser.getBrowserForTab(tab1);
|
||||
|
||||
let tab2 = gBrowser.addTab();
|
||||
let browser2 = gBrowser.getBrowserForTab(tab2);
|
||||
|
||||
let tab3 = gBrowser.addTab();
|
||||
let browser3 = gBrowser.getBrowserForTab(tab3);
|
||||
|
||||
let loadCount = 0;
|
||||
function check()
|
||||
{
|
||||
// wait for all tabs to load
|
||||
if (++loadCount != 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
browser1.removeEventListener("load", check, true);
|
||||
browser2.removeEventListener("load", check, true);
|
||||
browser3.removeEventListener("load", check, true);
|
||||
executeSoon(_run_tab_keyboard_navigation_tests);
|
||||
}
|
||||
|
||||
function _run_tab_keyboard_navigation_tests()
|
||||
{
|
||||
// Kill the animation for simpler test.
|
||||
Services.prefs.setBoolPref("browser.tabs.animate", false);
|
||||
|
||||
gBrowser.selectedTab = tab1;
|
||||
browser1.contentWindow.focus();
|
||||
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated");
|
||||
EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true },
|
||||
browser1.contentWindow);
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+Tab on Tab1");
|
||||
|
||||
EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true },
|
||||
browser2.contentWindow);
|
||||
is(gBrowser.selectedTab, tab3,
|
||||
"Tab3 should be activated by pressing Ctrl+Tab on Tab2");
|
||||
|
||||
EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true, shiftKey: true },
|
||||
browser3.contentWindow);
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+Shift+Tab on Tab3");
|
||||
|
||||
EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true, shiftKey: true },
|
||||
browser2.contentWindow);
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated by pressing Ctrl+Shift+Tab on Tab2");
|
||||
|
||||
gBrowser.selectedTab = tab1;
|
||||
browser1.contentWindow.focus();
|
||||
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated");
|
||||
EventUtils.synthesizeKey("VK_PAGE_DOWN", { ctrlKey: true },
|
||||
browser1.contentWindow);
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+PageDown on Tab1");
|
||||
|
||||
EventUtils.synthesizeKey("VK_PAGE_DOWN", { ctrlKey: true },
|
||||
browser2.contentWindow);
|
||||
is(gBrowser.selectedTab, tab3,
|
||||
"Tab3 should be activated by pressing Ctrl+PageDown on Tab2");
|
||||
|
||||
EventUtils.synthesizeKey("VK_PAGE_UP", { ctrlKey: true },
|
||||
browser3.contentWindow);
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+PageUp on Tab3");
|
||||
|
||||
EventUtils.synthesizeKey("VK_PAGE_UP", { ctrlKey: true },
|
||||
browser2.contentWindow);
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated by pressing Ctrl+PageUp on Tab2");
|
||||
|
||||
if (gBrowser.mTabBox._handleMetaAltArrows) {
|
||||
gBrowser.selectedTab = tab1;
|
||||
browser1.contentWindow.focus();
|
||||
|
||||
let ltr =
|
||||
window.getComputedStyle(gBrowser.mTabBox, "").direction == "ltr";
|
||||
let advanceKey = ltr ? "VK_RIGHT" : "VK_LEFT";
|
||||
let reverseKey = ltr ? "VK_LEFT" : "VK_RIGHT";
|
||||
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated");
|
||||
EventUtils.synthesizeKey(advanceKey, { altKey: true, metaKey: true },
|
||||
browser1.contentWindow);
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+" + advanceKey + " on Tab1");
|
||||
|
||||
EventUtils.synthesizeKey(advanceKey, { altKey: true, metaKey: true },
|
||||
browser2.contentWindow);
|
||||
is(gBrowser.selectedTab, tab3,
|
||||
"Tab3 should be activated by pressing Ctrl+" + advanceKey + " on Tab2");
|
||||
|
||||
EventUtils.synthesizeKey(reverseKey, { altKey: true, metaKey: true },
|
||||
browser3.contentWindow);
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+" + reverseKey + " on Tab3");
|
||||
|
||||
EventUtils.synthesizeKey(reverseKey, { altKey: true, metaKey: true },
|
||||
browser2.contentWindow);
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated by pressing Ctrl+" + reverseKey + " on Tab2");
|
||||
}
|
||||
|
||||
gBrowser.selectedTab = tab2;
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated");
|
||||
is(gBrowser.tabContainer.selectedIndex, 2,
|
||||
"Tab2 index should be 2");
|
||||
|
||||
EventUtils.synthesizeKey("VK_PAGE_DOWN", { ctrlKey: true, shiftKey: true },
|
||||
browser2.contentWindow);
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated after Ctrl+Shift+PageDown");
|
||||
is(gBrowser.tabContainer.selectedIndex, 3,
|
||||
"Tab2 index should be 1 after Ctrl+Shift+PageDown");
|
||||
|
||||
EventUtils.synthesizeKey("VK_PAGE_UP", { ctrlKey: true, shiftKey: true },
|
||||
browser2.contentWindow);
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated after Ctrl+Shift+PageUp");
|
||||
is(gBrowser.tabContainer.selectedIndex, 2,
|
||||
"Tab2 index should be 2 after Ctrl+Shift+PageUp");
|
||||
|
||||
if (navigator.platform.indexOf("Mac") == 0) {
|
||||
gBrowser.selectedTab = tab1;
|
||||
browser1.contentWindow.focus();
|
||||
|
||||
// XXX Currently, Command + "{" and "}" don't work if keydown event is
|
||||
// consumed because following keypress event isn't fired.
|
||||
|
||||
let ltr =
|
||||
window.getComputedStyle(gBrowser.mTabBox, "").direction == "ltr";
|
||||
let advanceKey = ltr ? "}" : "{";
|
||||
let reverseKey = ltr ? "{" : "}";
|
||||
|
||||
is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated");
|
||||
EventUtils.synthesizeKey(advanceKey, { metaKey: true },
|
||||
browser1.contentWindow);
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+" + advanceKey + " on Tab1");
|
||||
|
||||
EventUtils.synthesizeKey(advanceKey, { metaKey: true },
|
||||
browser2.contentWindow);
|
||||
todo_is(gBrowser.selectedTab, tab3,
|
||||
"Tab3 should be activated by pressing Ctrl+" + advanceKey + " on Tab2");
|
||||
|
||||
if (gBrowser.selectedTab != tab3) {
|
||||
EventUtils.synthesizeKey(reverseKey, { metaKey: true },
|
||||
browser3.contentWindow);
|
||||
is(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be activated by pressing Ctrl+" + reverseKey + " on Tab3");
|
||||
}
|
||||
|
||||
EventUtils.synthesizeKey(reverseKey, { metaKey: true },
|
||||
browser2.contentWindow);
|
||||
todo_is(gBrowser.selectedTab, tab1,
|
||||
"Tab1 should be activated by pressing Ctrl+" + reverseKey + " on Tab2");
|
||||
} else {
|
||||
gBrowser.selectedTab = tab2;
|
||||
EventUtils.synthesizeKey("VK_F4", { type: "keydown", ctrlKey: true },
|
||||
browser2.contentWindow);
|
||||
|
||||
isnot(gBrowser.selectedTab, tab2,
|
||||
"Tab2 should be closed by pressing Ctrl+F4 on Tab2");
|
||||
is(gBrowser.tabs.length, 3,
|
||||
"The count of tabs should be 3 since tab2 should be closed");
|
||||
|
||||
let activeWindow =
|
||||
gBrowser.getBrowserForTab(gBrowser.selectedTab).contentWindow;
|
||||
// NOTE: keypress event shouldn't be fired since the keydown event should
|
||||
// be consumed by tab2.
|
||||
EventUtils.synthesizeKey("VK_F4", { type: "keyup", ctrlKey: true },
|
||||
activeWindow);
|
||||
is(gBrowser.tabs.length, 3,
|
||||
"The count of tabs should be 3 since renaming key events shouldn't close other tabs");
|
||||
}
|
||||
|
||||
gBrowser.selectedTab = tab3;
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
|
||||
Services.prefs.clearUserPref("browser.tabs.animate");
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
browser1.addEventListener("load", check, true);
|
||||
browser2.addEventListener("load", check, true);
|
||||
browser3.addEventListener("load", check, true);
|
||||
|
||||
browser1.contentWindow.location = testPage1;
|
||||
browser2.contentWindow.location = testPage2;
|
||||
browser3.contentWindow.location = testPage3;
|
||||
}
|
18
configure.in
18
configure.in
|
@ -9032,15 +9032,17 @@ dnl ========================================================
|
|||
dnl ICU Support
|
||||
dnl ========================================================
|
||||
|
||||
if test "$MOZ_BUILD_APP" = "browser"; then
|
||||
_INTL_API=yes
|
||||
else
|
||||
# Internationalization isn't built or exposed by default in non-desktop
|
||||
# builds. Bugs to enable:
|
||||
#
|
||||
# Android: bug 864843
|
||||
# B2G: bug 866301
|
||||
# Internationalization isn't built or exposed by default in non-desktop
|
||||
# builds. Bugs to enable:
|
||||
#
|
||||
# Android: bug 864843
|
||||
# B2G: bug 866301
|
||||
|
||||
if test "$MOZ_WIDGET_TOOLKIT" = "android" ||
|
||||
test "$MOZ_BUILD_APP" = "b2g"; then
|
||||
_INTL_API=no
|
||||
else
|
||||
_INTL_API=yes
|
||||
fi
|
||||
|
||||
MOZ_CONFIG_ICU()
|
||||
|
|
|
@ -2597,9 +2597,10 @@ Serialize(FragmentOrElement* aRoot, bool aDescendentsOnly, nsAString& aOut)
|
|||
|
||||
current = current->GetParentNode();
|
||||
|
||||
// Template case, if we are in a template's content, then the parent
|
||||
// should be the host template element.
|
||||
if (current->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
|
||||
// Handle template element. If the parent is a template's content,
|
||||
// then adjust the parent to be the template element.
|
||||
if (current != aRoot &&
|
||||
current->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
|
||||
DocumentFragment* frag = static_cast<DocumentFragment*>(current);
|
||||
nsIContent* fragHost = frag->GetHost();
|
||||
if (fragHost && nsNodeUtils::IsTemplateElement(fragHost)) {
|
||||
|
|
|
@ -231,8 +231,8 @@ nsCSPParser::port()
|
|||
|
||||
// Port must start with a number
|
||||
if (!accept(isNumberToken)) {
|
||||
const char16_t* params[] = { mCurValue.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "policyURIParseError",
|
||||
const char16_t* params[] = { mCurToken.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParsePort",
|
||||
params, ArrayLength(params));
|
||||
return false;
|
||||
}
|
||||
|
@ -260,6 +260,14 @@ nsCSPParser::subPath(nsCSPHostSrc* aCspHost)
|
|||
++charCounter;
|
||||
}
|
||||
if (accept(SLASH)) {
|
||||
// do not accept double slashes
|
||||
// see http://tools.ietf.org/html/rfc3986#section-3.3
|
||||
if (accept(SLASH)) {
|
||||
const char16_t* params[] = { mCurToken.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
|
||||
params, ArrayLength(params));
|
||||
return false;
|
||||
}
|
||||
aCspHost->appendPath(mCurValue);
|
||||
// Resetting current value since we are appending parts of the path
|
||||
// to aCspHost, e.g; "http://www.example.com/path1/path2" then the
|
||||
|
@ -289,12 +297,18 @@ nsCSPParser::path(nsCSPHostSrc* aCspHost)
|
|||
resetCurValue();
|
||||
|
||||
if (!accept(SLASH)) {
|
||||
const char16_t* params[] = { mCurToken.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
|
||||
params, ArrayLength(params));
|
||||
return false;
|
||||
}
|
||||
if (atEnd()) {
|
||||
return true;
|
||||
}
|
||||
if (!hostChar()) {
|
||||
const char16_t* params[] = { mCurToken.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
|
||||
params, ArrayLength(params));
|
||||
return false;
|
||||
}
|
||||
return subPath(aCspHost);
|
||||
|
@ -347,8 +361,8 @@ nsCSPParser::host()
|
|||
}
|
||||
// If the token is not only the "*", a "." must follow right after
|
||||
if (!accept(DOT)) {
|
||||
const char16_t* params[] = { mCurValue.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "policyURIParseError",
|
||||
const char16_t* params[] = { mCurToken.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidHost",
|
||||
params, ArrayLength(params));
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -356,16 +370,16 @@ nsCSPParser::host()
|
|||
|
||||
// Expecting at least one Character
|
||||
if (!accept(isCharacterToken)) {
|
||||
const char16_t* params[] = { mCurValue.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "policyURIParseError",
|
||||
const char16_t* params[] = { mCurToken.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidHost",
|
||||
params, ArrayLength(params));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// There might be several sub hosts defined.
|
||||
if (!subHost()) {
|
||||
const char16_t* params[] = { mCurValue.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "policyURIParseError",
|
||||
const char16_t* params[] = { mCurToken.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidHost",
|
||||
params, ArrayLength(params));
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -374,7 +388,7 @@ nsCSPParser::host()
|
|||
if (CSP_IsQuotelessKeyword(mCurValue)) {
|
||||
nsString keyword = mCurValue;
|
||||
ToLowerCase(keyword);
|
||||
const char16_t* params[] = { mCurValue.get(), keyword.get() };
|
||||
const char16_t* params[] = { mCurToken.get(), keyword.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "hostNameMightBeKeyword",
|
||||
params, ArrayLength(params));
|
||||
}
|
||||
|
@ -395,8 +409,8 @@ nsCSPParser::appHost()
|
|||
|
||||
// appHosts have to end with "}", otherwise we have to report an error
|
||||
if (!accept(CLOSE_CURL)) {
|
||||
const char16_t* params[] = { mCurValue.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "policyURIParseError",
|
||||
const char16_t* params[] = { mCurToken.get() };
|
||||
logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
|
||||
params, ArrayLength(params));
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -464,7 +478,11 @@ nsCSPParser::hostSource()
|
|||
// occurs, path() reports the error; handing cspHost as an argument
|
||||
// which simplifies parsing of several paths.
|
||||
if (!path(cspHost)) {
|
||||
return cspHost;
|
||||
// If the host [port] is followed by a path, it has to be a valid path,
|
||||
// otherwise we pass the nullptr, indicating an error, up the callstack.
|
||||
// see also http://www.w3.org/TR/CSP11/#source-list
|
||||
delete cspHost;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Calling fileAndArguments to see if there are any files to parse;
|
||||
|
|
|
@ -4513,6 +4513,11 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
|
|||
// doing the initial document load and don't want to fire the event for this
|
||||
// change.
|
||||
mVisibilityState = GetVisibilityState();
|
||||
|
||||
// The global in the template contents owner document should be the same.
|
||||
if (mTemplateContentsOwner && mTemplateContentsOwner != this) {
|
||||
mTemplateContentsOwner->SetScriptGlobalObject(aScriptGlobalObject);
|
||||
}
|
||||
}
|
||||
|
||||
nsIScriptGlobalObject*
|
||||
|
@ -9443,7 +9448,6 @@ nsDocument::GetTemplateContentsOwner()
|
|||
bool hasHadScriptObject = true;
|
||||
nsIScriptGlobalObject* scriptObject =
|
||||
GetScriptHandlingObject(hasHadScriptObject);
|
||||
NS_ENSURE_TRUE(scriptObject || !hasHadScriptObject, nullptr);
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domDocument;
|
||||
nsresult rv = NS_NewDOMDocument(getter_AddRefs(domDocument),
|
||||
|
@ -9461,12 +9465,16 @@ nsDocument::GetTemplateContentsOwner()
|
|||
mTemplateContentsOwner = do_QueryInterface(domDocument);
|
||||
NS_ENSURE_TRUE(mTemplateContentsOwner, nullptr);
|
||||
|
||||
mTemplateContentsOwner->SetScriptHandlingObject(scriptObject);
|
||||
nsDocument* doc = static_cast<nsDocument*>(mTemplateContentsOwner.get());
|
||||
doc->mHasHadScriptHandlingObject = hasHadScriptObject;
|
||||
|
||||
if (!scriptObject) {
|
||||
mTemplateContentsOwner->SetScopeObject(GetScopeObject());
|
||||
}
|
||||
|
||||
// Set |doc| as the template contents owner of itself so that
|
||||
// |doc| is the template contents owner of template elements created
|
||||
// by |doc|.
|
||||
nsDocument* doc = static_cast<nsDocument*>(mTemplateContentsOwner.get());
|
||||
doc->mTemplateContentsOwner = doc;
|
||||
}
|
||||
|
||||
|
|
|
@ -522,12 +522,12 @@ nsDocumentEncoder::SerializeToStringIterative(nsINode* aNode,
|
|||
{
|
||||
nsresult rv;
|
||||
|
||||
nsINode* node = aNode->GetFirstChild();
|
||||
nsINode* node = nsNodeUtils::GetFirstChildOfTemplateOrNode(aNode);
|
||||
while (node) {
|
||||
nsINode* current = node;
|
||||
rv = SerializeNodeStart(current, 0, -1, aStr, current);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
node = current->GetFirstChild();
|
||||
node = nsNodeUtils::GetFirstChildOfTemplateOrNode(current);
|
||||
while (!node && current && current != aNode) {
|
||||
rv = SerializeNodeEnd(current, aStr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -536,6 +536,17 @@ nsDocumentEncoder::SerializeToStringIterative(nsINode* aNode,
|
|||
if (!node) {
|
||||
// Perhaps parent node has siblings.
|
||||
current = current->GetParentNode();
|
||||
|
||||
// Handle template element. If the parent is a template's content,
|
||||
// then adjust the parent to be the template element.
|
||||
if (current && current != aNode &&
|
||||
current->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
|
||||
DocumentFragment* frag = static_cast<DocumentFragment*>(current);
|
||||
nsIContent* host = frag->GetHost();
|
||||
if (host && host->IsHTML(nsGkAtoms::_template)) {
|
||||
current = host;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2525,8 +2525,8 @@ GetRequestBody(nsIVariant* aBody, nsIInputStream** aResult, uint64_t* aContentLe
|
|||
nsresult rv = aBody->GetAsJSVal(&realVal);
|
||||
if (NS_SUCCEEDED(rv) && !realVal.isPrimitive()) {
|
||||
JS::Rooted<JSObject*> obj(cx, realVal.toObjectOrNull());
|
||||
if (JS_IsArrayBufferObject(obj)) {
|
||||
ArrayBuffer buf(obj);
|
||||
ArrayBuffer buf;
|
||||
if (buf.Init(obj)) {
|
||||
buf.ComputeLengthAndData();
|
||||
return GetRequestBody(buf.Data(), buf.Length(), aResult,
|
||||
aContentLength, aContentType, aCharset);
|
||||
|
|
|
@ -407,28 +407,6 @@ nsresult TestPoliciesThatLogWarning() {
|
|||
"script-src http://www.selfuri.com" },
|
||||
{ "script-src 'none' test.com; script-src example.com",
|
||||
"script-src http://test.com" },
|
||||
{ "script-src http://www.example.com//",
|
||||
"script-src http://www.example.com" },
|
||||
{ "script-src http://www.example.com/path-1//",
|
||||
"script-src http://www.example.com" },
|
||||
{ "script-src http://www.example.com/path-1//path_2",
|
||||
"script-src http://www.example.com" },
|
||||
{ "script-src http://www.example.com:88path-1/",
|
||||
"script-src http://www.example.com:88" },
|
||||
{ "script-src http://www.example.com:88//",
|
||||
"script-src http://www.example.com:88" },
|
||||
{ "script-src http://www.example.com:88//path-1",
|
||||
"script-src http://www.example.com:88" },
|
||||
{ "script-src http://www.example.com:88//path-1",
|
||||
"script-src http://www.example.com:88" },
|
||||
{ "script-src http://www.example.com:88/.js",
|
||||
"script-src http://www.example.com:88" },
|
||||
{ "script-src http://www.example.com:88.js",
|
||||
"script-src http://www.example.com:88" },
|
||||
{ "script-src http://www.example.com:*.js",
|
||||
"script-src http://www.example.com:*" },
|
||||
{ "script-src http://www.example.com:*.",
|
||||
"script-src http://www.example.com:*" }
|
||||
};
|
||||
|
||||
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
|
||||
|
@ -461,7 +439,18 @@ nsresult TestBadPolicies() {
|
|||
{ "img-src *::88", "" },
|
||||
{ "object-src http://localhost:", "" },
|
||||
{ "script-src test..com", "" },
|
||||
{ "script-src sub1.sub2.example+", "" }
|
||||
{ "script-src sub1.sub2.example+", "" },
|
||||
{ "script-src http://www.example.com//", "" },
|
||||
{ "script-src http://www.example.com/path-1//", "" },
|
||||
{ "script-src http://www.example.com/path-1//path_2", "" },
|
||||
{ "script-src http://www.example.com:88path-1/", "" },
|
||||
{ "script-src http://www.example.com:88//", "" },
|
||||
{ "script-src http://www.example.com:88//path-1", "" },
|
||||
{ "script-src http://www.example.com:88//path-1", "" },
|
||||
{ "script-src http://www.example.com:88/.js", "" },
|
||||
{ "script-src http://www.example.com:88.js", "" },
|
||||
{ "script-src http://www.example.com:*.js", "" },
|
||||
{ "script-src http://www.example.com:*.", "" },
|
||||
};
|
||||
|
||||
uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
|
||||
|
|
|
@ -27,6 +27,8 @@ support-files =
|
|||
[test_cspreports.js]
|
||||
[test_error_codes.js]
|
||||
run-sequentially = Hardcoded 4444 port.
|
||||
# Bug 1018414: hardcoded localhost doesn't work properly on some OS X installs
|
||||
skip-if = os == 'mac'
|
||||
[test_thirdpartyutil.js]
|
||||
[test_xhr_standalone.js]
|
||||
[test_xmlserializer.js]
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
#include "mozilla/Alignment.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ImageData.h"
|
||||
#include "mozilla/dom/PBrowserParent.h"
|
||||
|
@ -4006,7 +4007,9 @@ void
|
|||
CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
|
||||
double dy, ErrorResult& error)
|
||||
{
|
||||
dom::Uint8ClampedArray arr(imageData.GetDataObject());
|
||||
dom::Uint8ClampedArray arr;
|
||||
DebugOnly<bool> inited = arr.Init(imageData.GetDataObject());
|
||||
MOZ_ASSERT(inited);
|
||||
|
||||
error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
|
||||
imageData.Width(), imageData.Height(),
|
||||
|
@ -4020,7 +4023,9 @@ CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
|
|||
double dirtyHeight,
|
||||
ErrorResult& error)
|
||||
{
|
||||
dom::Uint8ClampedArray arr(imageData.GetDataObject());
|
||||
dom::Uint8ClampedArray arr;
|
||||
DebugOnly<bool> inited = arr.Init(imageData.GetDataObject());
|
||||
MOZ_ASSERT(inited);
|
||||
|
||||
error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
|
||||
imageData.Width(), imageData.Height(),
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "nsCocoaFeatures.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/ImageData.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
|
@ -3713,7 +3714,9 @@ WebGLContext::TexImage2D(GLenum target, GLint level,
|
|||
return ErrorInvalidValue("texImage2D: null ImageData");
|
||||
}
|
||||
|
||||
Uint8ClampedArray arr(pixels->GetDataObject());
|
||||
Uint8ClampedArray arr;
|
||||
DebugOnly<bool> inited = arr.Init(pixels->GetDataObject());
|
||||
MOZ_ASSERT(inited);
|
||||
arr.ComputeLengthAndData();
|
||||
|
||||
return TexImage2D_base(target, level, internalformat, pixels->Width(),
|
||||
|
@ -3846,7 +3849,9 @@ WebGLContext::TexSubImage2D(GLenum target, GLint level,
|
|||
if (!pixels)
|
||||
return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
|
||||
|
||||
Uint8ClampedArray arr(pixels->GetDataObject());
|
||||
Uint8ClampedArray arr;
|
||||
DebugOnly<bool> inited = arr.Init(pixels->GetDataObject());
|
||||
MOZ_ASSERT(inited);
|
||||
arr.ComputeLengthAndData();
|
||||
|
||||
return TexSubImage2D_base(target, level, xoffset, yoffset,
|
||||
|
|
|
@ -11,21 +11,7 @@
|
|||
#include "nsIAtom.h"
|
||||
#include "nsRuleData.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
nsGenericHTMLElement*
|
||||
NS_NewHTMLTemplateElement(already_AddRefed<nsINodeInfo>&& aNodeInfo,
|
||||
FromParser aFromParser)
|
||||
{
|
||||
HTMLTemplateElement* it = new HTMLTemplateElement(aNodeInfo);
|
||||
nsresult rv = it->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
delete it;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Template)
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -34,18 +20,14 @@ HTMLTemplateElement::HTMLTemplateElement(already_AddRefed<nsINodeInfo>& aNodeInf
|
|||
: nsGenericHTMLElement(aNodeInfo)
|
||||
{
|
||||
SetHasWeirdParserInsertionMode();
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLTemplateElement::Init()
|
||||
{
|
||||
nsIDocument* contentsOwner = OwnerDoc()->GetTemplateContentsOwner();
|
||||
NS_ENSURE_TRUE(contentsOwner, NS_ERROR_UNEXPECTED);
|
||||
if (!contentsOwner) {
|
||||
MOZ_CRASH("There should always be a template contents owner.");
|
||||
}
|
||||
|
||||
mContent = contentsOwner->CreateDocumentFragment();
|
||||
mContent->SetHost(this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
HTMLTemplateElement::~HTMLTemplateElement()
|
||||
|
@ -77,7 +59,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLTemplateElement)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE_WITH_INIT(HTMLTemplateElement)
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLTemplateElement)
|
||||
|
||||
JSObject*
|
||||
HTMLTemplateElement::WrapNode(JSContext *aCx)
|
||||
|
|
|
@ -28,8 +28,6 @@ public:
|
|||
|
||||
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
|
||||
|
||||
nsresult Init();
|
||||
|
||||
DocumentFragment* Content()
|
||||
{
|
||||
return mContent;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/Mutex.h"
|
||||
#include <algorithm>
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "soundtouch/SoundTouch.h"
|
||||
#include "Latency.h"
|
||||
|
||||
|
@ -72,6 +73,16 @@ bool AudioStream::sCubebLatencyPrefSet;
|
|||
}
|
||||
}
|
||||
|
||||
/*static*/ bool AudioStream::GetFirstStream()
|
||||
{
|
||||
static bool sFirstStream = true;
|
||||
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
bool result = sFirstStream;
|
||||
sFirstStream = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*static*/ double AudioStream::GetVolumeScale()
|
||||
{
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
|
@ -384,6 +395,9 @@ AudioStream::Init(int32_t aNumChannels, int32_t aRate,
|
|||
const dom::AudioChannel aAudioChannel,
|
||||
LatencyRequest aLatencyRequest)
|
||||
{
|
||||
mStartTime = TimeStamp::Now();
|
||||
mIsFirst = GetFirstStream();
|
||||
|
||||
if (!GetCubebContext() || aNumChannels < 0 || aRate < 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -494,6 +508,14 @@ AudioStream::OpenCubeb(cubeb_stream_params &aParams,
|
|||
}
|
||||
}
|
||||
|
||||
if (!mStartTime.IsNull()) {
|
||||
TimeDuration timeDelta = TimeStamp::Now() - mStartTime;
|
||||
LOG(("AudioStream creation time %sfirst: %u ms", mIsFirst ? "" : "not ",
|
||||
(uint32_t) timeDelta.ToMilliseconds()));
|
||||
Telemetry::Accumulate(mIsFirst ? Telemetry::AUDIOSTREAM_FIRST_OPEN_MS :
|
||||
Telemetry::AUDIOSTREAM_LATER_OPEN_MS, timeDelta.ToMilliseconds());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -307,6 +307,7 @@ private:
|
|||
|
||||
static void PrefChanged(const char* aPref, void* aClosure);
|
||||
static double GetVolumeScale();
|
||||
static bool GetFirstStream();
|
||||
static cubeb* GetCubebContext();
|
||||
static cubeb* GetCubebContextUnlocked();
|
||||
static uint32_t GetCubebLatency();
|
||||
|
@ -423,6 +424,7 @@ private:
|
|||
|
||||
StreamState mState;
|
||||
bool mNeedsStart; // needed in case Start() is called before cubeb is open
|
||||
bool mIsFirst;
|
||||
|
||||
// This mutex protects the static members below.
|
||||
static StaticMutex sMutex;
|
||||
|
|
|
@ -80,7 +80,7 @@ OMXCodecProxy::~OMXCodecProxy()
|
|||
IPCThreadState::self()->flushCommands();
|
||||
|
||||
if (mManagerService.get() && mClient.get()) {
|
||||
mManagerService->cancelClient(mClient);
|
||||
mManagerService->cancelClient(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER);
|
||||
}
|
||||
|
||||
mSource.clear();
|
||||
|
@ -126,7 +126,7 @@ void OMXCodecProxy::requestResource()
|
|||
return;
|
||||
}
|
||||
|
||||
mManagerService->requestMediaResource(mClient, MediaResourceManagerClient::HW_VIDEO_DECODER);
|
||||
mManagerService->requestMediaResource(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER, true /* will wait */);
|
||||
}
|
||||
|
||||
bool OMXCodecProxy::IsWaitingResources()
|
||||
|
|
|
@ -34,6 +34,32 @@ using namespace mozilla::layers;
|
|||
|
||||
namespace android {
|
||||
|
||||
bool
|
||||
OMXCodecReservation::ReserveOMXCodec()
|
||||
{
|
||||
if (!mManagerService.get()) {
|
||||
sp<MediaResourceManagerClient::EventListener> listener = this;
|
||||
mClient = new MediaResourceManagerClient(listener);
|
||||
|
||||
mManagerService = mClient->getMediaResourceManagerService();
|
||||
if (!mManagerService.get()) {
|
||||
mClient = nullptr;
|
||||
return true; // not really in use, but not usable
|
||||
}
|
||||
}
|
||||
return (mManagerService->requestMediaResource(mClient, mType, false) == OK); // don't wait
|
||||
}
|
||||
|
||||
void
|
||||
OMXCodecReservation::ReleaseOMXCodec()
|
||||
{
|
||||
if (!mManagerService.get() || !mClient.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mManagerService->cancelClient(mClient, mType);
|
||||
}
|
||||
|
||||
OMXAudioEncoder*
|
||||
OMXCodecWrapper::CreateAACEncoder()
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define OMXCodecWrapper_h_
|
||||
|
||||
#include <gui/Surface.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <stagefright/foundation/ABuffer.h>
|
||||
#include <stagefright/foundation/AMessage.h>
|
||||
#include <stagefright/MediaCodec.h>
|
||||
|
@ -15,10 +16,45 @@
|
|||
#include "GonkNativeWindow.h"
|
||||
#include "GonkNativeWindowClient.h"
|
||||
|
||||
#include "IMediaResourceManagerService.h"
|
||||
#include "MediaResourceManagerClient.h"
|
||||
|
||||
#include <speex/speex_resampler.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// Wrapper class for managing HW codec reservations
|
||||
class OMXCodecReservation : public MediaResourceManagerClient::EventListener
|
||||
{
|
||||
public:
|
||||
OMXCodecReservation(bool aEncoder)
|
||||
{
|
||||
mType = aEncoder ? IMediaResourceManagerService::HW_VIDEO_ENCODER :
|
||||
IMediaResourceManagerService::HW_VIDEO_DECODER;
|
||||
}
|
||||
|
||||
virtual ~OMXCodecReservation()
|
||||
{
|
||||
ReleaseOMXCodec();
|
||||
}
|
||||
|
||||
/** Reserve the Encode or Decode resource for this instance */
|
||||
virtual bool ReserveOMXCodec();
|
||||
|
||||
/** Release the Encode or Decode resource for this instance */
|
||||
virtual void ReleaseOMXCodec();
|
||||
|
||||
// MediaResourceManagerClient::EventListener
|
||||
virtual void statusChanged(int event) {}
|
||||
|
||||
private:
|
||||
IMediaResourceManagerService::ResourceType mType;
|
||||
|
||||
sp<MediaResourceManagerClient> mClient;
|
||||
sp<IMediaResourceManagerService> mManagerService;
|
||||
};
|
||||
|
||||
|
||||
class OMXAudioEncoder;
|
||||
class OMXVideoEncoder;
|
||||
|
||||
|
|
|
@ -34,20 +34,23 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
virtual void requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType)
|
||||
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
|
||||
data.writeStrongBinder(client->asBinder());
|
||||
data.writeInt32(resourceType);
|
||||
data.writeInt32(willWait ? 1 : 0);
|
||||
remote()->transact(REQUEST_MEDIA_RESOURCE, data, &reply);
|
||||
return reply.readInt32();
|
||||
}
|
||||
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client)
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
|
||||
data.writeStrongBinder(client->asBinder());
|
||||
data.writeInt32(resourceType);
|
||||
remote()->transact(DEREGISTER_CLIENT, data, &reply);
|
||||
return reply.readInt32();
|
||||
}
|
||||
|
@ -66,14 +69,17 @@ status_t BnMediaResourceManagerService::onTransact(
|
|||
CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
|
||||
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
|
||||
int resourceType = data.readInt32();
|
||||
requestMediaResource(client, resourceType);
|
||||
bool willWait = (data.readInt32() == 1);
|
||||
status_t result = requestMediaResource(client, resourceType, willWait);
|
||||
reply->writeInt32(result);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case DEREGISTER_CLIENT: {
|
||||
CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
|
||||
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
|
||||
cancelClient(client);
|
||||
reply->writeInt32(NO_ERROR);
|
||||
int resourceType = data.readInt32();
|
||||
status_t result = cancelClient(client, resourceType);
|
||||
reply->writeInt32(result);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
|
|
|
@ -22,10 +22,36 @@ class IMediaResourceManagerService : public IInterface
|
|||
public:
|
||||
DECLARE_META_INTERFACE(MediaResourceManagerService);
|
||||
|
||||
// Enumeration for the resource types
|
||||
enum ResourceType {
|
||||
HW_VIDEO_DECODER = 0,
|
||||
HW_AUDIO_DECODER, // Not supported currently.
|
||||
HW_VIDEO_ENCODER,
|
||||
HW_CAMERA, // Not supported currently.
|
||||
NUM_OF_RESOURCE_TYPES,
|
||||
INVALID_RESOURCE_TYPE = -1
|
||||
};
|
||||
|
||||
enum ErrorCode {
|
||||
RESOURCE_NOT_AVAILABLE = -EAGAIN
|
||||
};
|
||||
|
||||
// Request a media resource for IMediaResourceManagerClient.
|
||||
virtual void requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType) = 0;
|
||||
// client is the binder that service will notify (through
|
||||
// IMediaResourceManagerClient::statusChanged()) when request status changed.
|
||||
// resourceType is type of resource that client would like to request.
|
||||
// willWait indicates that, when the resource is not currently available
|
||||
// (i.e., already in use by another client), if the client wants to wait. If
|
||||
// true, client will be put into a (FIFO) waiting list and be notified when
|
||||
// resource is available.
|
||||
// For unsupported types, this function returns BAD_TYPE. For supported
|
||||
// types, it always returns OK when willWait is true; otherwise it will
|
||||
// return true when resouce is available, or RESOURCE_NOT_AVAILABLE when
|
||||
// resouce is in use.
|
||||
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait) = 0;
|
||||
// Cancel a media resource request and a resource allocated to IMediaResourceManagerClient.
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client) = 0;
|
||||
// Client must call this function after it's done with the media resource requested.
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -22,12 +22,6 @@ public:
|
|||
CLIENT_STATE_RESOURCE_ASSIGNED,
|
||||
CLIENT_STATE_SHUTDOWN
|
||||
};
|
||||
// Enumeration for the resource types
|
||||
enum ResourceType {
|
||||
HW_VIDEO_DECODER,
|
||||
HW_AUDIO_DECODER,
|
||||
HW_CAMERA
|
||||
};
|
||||
|
||||
struct EventListener : public virtual RefBase {
|
||||
// Notifies a change of media resource request status.
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "MediaResourceManagerService"
|
||||
|
||||
#include <mozilla/Assertions.h>
|
||||
|
||||
#include <binder/IServiceManager.h>
|
||||
#include <media/stagefright/foundation/AMessage.h>
|
||||
#include <utils/Log.h>
|
||||
|
@ -16,14 +18,16 @@
|
|||
|
||||
namespace android {
|
||||
|
||||
const char* MediaResourceManagerService::kMsgKeyResourceType = "res-type";
|
||||
|
||||
/* static */
|
||||
void MediaResourceManagerService::instantiate() {
|
||||
defaultServiceManager()->addService(
|
||||
String16("media.resource_manager"), new MediaResourceManagerService());
|
||||
String16("media.resource_manager"),
|
||||
new MediaResourceManagerService());
|
||||
}
|
||||
|
||||
MediaResourceManagerService::MediaResourceManagerService()
|
||||
: mVideoDecoderCount(VIDEO_DECODER_COUNT)
|
||||
{
|
||||
mLooper = new ALooper;
|
||||
mLooper->setName("MediaResourceManagerService");
|
||||
|
@ -49,99 +53,319 @@ void MediaResourceManagerService::binderDied(const wp<IBinder>& who)
|
|||
Mutex::Autolock autoLock(mLock);
|
||||
sp<IBinder> binder = who.promote();
|
||||
if (binder != NULL) {
|
||||
cancelClientLocked(binder);
|
||||
mResources.forgetClient(binder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MediaResourceManagerService::requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType)
|
||||
status_t MediaResourceManagerService::requestMediaResource(const sp<IMediaResourceManagerClient>& client,
|
||||
int resourceType, bool willWait)
|
||||
{
|
||||
if (resourceType != MediaResourceManagerClient::HW_VIDEO_DECODER) {
|
||||
// Support only HW_VIDEO_DECODER
|
||||
return;
|
||||
ResourceType type = static_cast<ResourceType>(resourceType);
|
||||
// Support only HW_VIDEO_DECODER and HW_VIDEO_ENCODER.
|
||||
switch (type) {
|
||||
case HW_VIDEO_DECODER:
|
||||
case HW_VIDEO_ENCODER:
|
||||
break;
|
||||
default:
|
||||
// Type not supported.
|
||||
return BAD_TYPE;
|
||||
}
|
||||
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
sp<IBinder> binder = client->asBinder();
|
||||
mVideoCodecRequestQueue.push_back(binder);
|
||||
binder->linkToDeath(this);
|
||||
}
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
sp<AMessage> notify =
|
||||
new AMessage(kNotifyRequest, mReflector->id());
|
||||
// Must know if it will be granted or not - if there are enough unfufilled requests to
|
||||
// use up the resource, fail. Otherwise we know that enqueuing under lock will succeed.
|
||||
if (!willWait &&
|
||||
(mResources.findAvailableResource(type, mResources.countRequests(type) + 1) ==
|
||||
NAME_NOT_FOUND)) {
|
||||
return RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
// We could early-return here without enqueuing IF we can do the rest of
|
||||
// the allocation safely here. However, enqueuing ensures there's only
|
||||
// one copy of that code, and that any callbacks are made from the same
|
||||
// context.
|
||||
|
||||
sp<IBinder> binder = client->asBinder();
|
||||
mResources.enqueueRequest(binder, type);
|
||||
binder->linkToDeath(this);
|
||||
|
||||
sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
|
||||
notify->setInt32(kMsgKeyResourceType, resourceType);
|
||||
// Post AMessage to MediaResourceManagerService via ALooper.
|
||||
notify->post();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::cancelClient(const sp<IMediaResourceManagerClient>& client)
|
||||
status_t MediaResourceManagerService::cancelClient(const sp<IMediaResourceManagerClient>& client,
|
||||
int resourceType)
|
||||
{
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
sp<IBinder> binder = client->asBinder();
|
||||
cancelClientLocked(binder);
|
||||
}
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
sp<AMessage> notify =
|
||||
new AMessage(kNotifyRequest, mReflector->id());
|
||||
// Post AMessage to MediaResourceManagerService via ALooper.
|
||||
sp<IBinder> binder = client->asBinder();
|
||||
cancelClientLocked(binder, static_cast<ResourceType>(resourceType));
|
||||
|
||||
sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
|
||||
notify->setInt32(kMsgKeyResourceType, resourceType);
|
||||
// Next!
|
||||
// Note: since we held the lock while releasing and then posting, if there is
|
||||
// a queue, no willWait==false entries can jump into the queue thinking they'll
|
||||
// get the resource.
|
||||
notify->post();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// Extract resource type from message.
|
||||
static int32_t getResourceType(const sp<AMessage>& message)
|
||||
{
|
||||
int32_t resourceType = MediaResourceManagerService::INVALID_RESOURCE_TYPE;
|
||||
return message->findInt32(MediaResourceManagerService::kMsgKeyResourceType, &resourceType) ?
|
||||
resourceType : MediaResourceManagerService::INVALID_RESOURCE_TYPE;
|
||||
}
|
||||
|
||||
// Called on ALooper thread.
|
||||
void MediaResourceManagerService::onMessageReceived(const sp<AMessage> &msg)
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
ResourceType type = static_cast<ResourceType>(getResourceType(msg));
|
||||
|
||||
// Exit if no request.
|
||||
if (mVideoCodecRequestQueue.empty()) {
|
||||
// Note: a message is sent both for "I added an entry to the queue"
|
||||
// (which may succeed, typically if the queue is empty), and for "I gave
|
||||
// up the resource", in which case it's "give to the next waiting client,
|
||||
// or no one".
|
||||
|
||||
// Exit if no resource is available, but leave the client in the waiting
|
||||
// list.
|
||||
int found = mResources.findAvailableResource(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if resource is available
|
||||
int found = -1;
|
||||
for (int i=0 ; i<mVideoDecoderCount ; i++) {
|
||||
if (!mVideoDecoderSlots[i].mClient.get()) {
|
||||
// Exit if no request.
|
||||
if (!mResources.hasRequest(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sp<IBinder>& req = mResources.nextRequest(type);
|
||||
mResources.aquireResource(req, type, found);
|
||||
// Notify resource assignment to the client.
|
||||
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(req);
|
||||
client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED);
|
||||
mResources.dequeueRequest(type);
|
||||
}
|
||||
|
||||
void MediaResourceManagerService::cancelClientLocked(const sp<IBinder>& binder,
|
||||
ResourceType resourceType)
|
||||
{
|
||||
mResources.forgetClient(binder, resourceType);
|
||||
binder->unlinkToDeath(this);
|
||||
}
|
||||
|
||||
MediaResourceManagerService::ResourceTable::ResourceTable()
|
||||
{
|
||||
// Populate types of resources.
|
||||
for (int type = 0; type < NUM_OF_RESOURCE_TYPES; type++) {
|
||||
ssize_t index = mMap.add(static_cast<ResourceType>(type), Resources());
|
||||
Resources& resources = mMap.editValueAt(index);
|
||||
int available;
|
||||
switch (type) {
|
||||
case HW_VIDEO_DECODER:
|
||||
available = VIDEO_DECODER_COUNT;
|
||||
break;
|
||||
case HW_VIDEO_ENCODER:
|
||||
available = VIDEO_ENCODER_COUNT;
|
||||
break;
|
||||
default:
|
||||
available = 0;
|
||||
break;
|
||||
}
|
||||
resources.mSlots.insertAt(0, available);
|
||||
}
|
||||
}
|
||||
|
||||
MediaResourceManagerService::ResourceTable::~ResourceTable() {
|
||||
// Remove resouces.
|
||||
mMap.clear();
|
||||
}
|
||||
|
||||
bool MediaResourceManagerService::ResourceTable::supportsType(ResourceType type)
|
||||
{
|
||||
return mMap.indexOfKey(type) != NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
ssize_t MediaResourceManagerService::ResourceTable::findAvailableResource(ResourceType type,
|
||||
size_t numberNeeded)
|
||||
{
|
||||
MOZ_ASSERT(numberNeeded > 0);
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return found;
|
||||
}
|
||||
const Slots& slots = mMap.valueAt(found).mSlots;
|
||||
|
||||
found = NAME_NOT_FOUND;
|
||||
for (size_t i = 0; i < slots.size(); i++) {
|
||||
if (slots[i].mClient != nullptr) {
|
||||
// Already in use.
|
||||
continue;
|
||||
}
|
||||
if (--numberNeeded == 0) {
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Exit if no resource is available.
|
||||
if (found == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Assign resource to IMediaResourceManagerClient
|
||||
Fifo::iterator front(mVideoCodecRequestQueue.begin());
|
||||
mVideoDecoderSlots[found].mClient = *front;
|
||||
mVideoCodecRequestQueue.erase(front);
|
||||
// Notify resource assignment to the client.
|
||||
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(mVideoDecoderSlots[found].mClient);
|
||||
client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED);
|
||||
return found;
|
||||
}
|
||||
|
||||
void MediaResourceManagerService::cancelClientLocked(const sp<IBinder>& binder)
|
||||
bool MediaResourceManagerService::ResourceTable::isOwnedByClient(const sp<IBinder>& client,
|
||||
ResourceType type,
|
||||
size_t index)
|
||||
{
|
||||
// Clear the request from request queue.
|
||||
Fifo::iterator it(mVideoCodecRequestQueue.begin());
|
||||
while (it != mVideoCodecRequestQueue.end()) {
|
||||
if ((*it).get() == binder.get()) {
|
||||
mVideoCodecRequestQueue.erase(it);
|
||||
ResourceSlot* slot = resourceOfTypeAt(type, index);
|
||||
return slot && slot->mClient == client;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::aquireResource(const sp<IBinder>& client,
|
||||
ResourceType type,
|
||||
size_t index)
|
||||
{
|
||||
ResourceSlot* slot = resourceOfTypeAt(type, index);
|
||||
// Resouce should not be in use.
|
||||
MOZ_ASSERT(slot && slot->mClient == nullptr);
|
||||
if (!slot) {
|
||||
return NAME_NOT_FOUND;
|
||||
} else if (slot->mClient != nullptr) {
|
||||
// Resource already in use by other client.
|
||||
return PERMISSION_DENIED;
|
||||
}
|
||||
|
||||
slot->mClient = client;
|
||||
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
MediaResourceManagerService::ResourceSlot*
|
||||
MediaResourceManagerService::ResourceTable::resourceOfTypeAt(ResourceType type,
|
||||
size_t index)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Slots& slots = mMap.editValueAt(found).mSlots;
|
||||
MOZ_ASSERT(index < slots.size());
|
||||
if (index >= slots.size()) {
|
||||
// Index out of range.
|
||||
return nullptr;
|
||||
}
|
||||
return &(slots.editItemAt(index));
|
||||
}
|
||||
|
||||
bool MediaResourceManagerService::ResourceTable::hasRequest(ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
|
||||
return !queue.empty();
|
||||
}
|
||||
|
||||
uint32_t MediaResourceManagerService::ResourceTable::countRequests(ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
|
||||
return queue.size();
|
||||
}
|
||||
|
||||
const sp<IBinder>& MediaResourceManagerService::ResourceTable::nextRequest(ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
|
||||
return *(queue.begin());
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::enqueueRequest(const sp<IBinder>& client,
|
||||
ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return found;
|
||||
}
|
||||
|
||||
mMap.editValueAt(found).mRequestQueue.push_back(client);
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::dequeueRequest(ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return found;
|
||||
}
|
||||
|
||||
Fifo& queue = mMap.editValueAt(found).mRequestQueue;
|
||||
queue.erase(queue.begin());
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client)
|
||||
{
|
||||
// Traverse all resources.
|
||||
for (int i = 0; i < mMap.size(); i++) {
|
||||
forgetClient(client, mMap.keyAt(i));
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client, ResourceType type)
|
||||
{
|
||||
MOZ_ASSERT(supportsType(type));
|
||||
|
||||
Resources& resources = mMap.editValueFor(type);
|
||||
|
||||
// Remove pending requests for given client.
|
||||
Fifo& queue = resources.mRequestQueue;
|
||||
Fifo::iterator it(queue.begin());
|
||||
while (it != queue.end()) {
|
||||
if ((*it).get() == client.get()) {
|
||||
queue.erase(it);
|
||||
break;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
// Clear the client from the resource
|
||||
for (int i=0 ; i<mVideoDecoderCount ; i++) {
|
||||
if (mVideoDecoderSlots[i].mClient.get() == binder.get()) {
|
||||
mVideoDecoderSlots[i].mClient = NULL;
|
||||
// Revoke ownership for given client.
|
||||
Slots& slots = resources.mSlots;
|
||||
for (int i = 0; i < slots.size(); i++) {
|
||||
ResourceSlot& slot = slots.editItemAt(i);
|
||||
if (client.get() == slot.mClient.get()) {
|
||||
slot.mClient = nullptr;
|
||||
}
|
||||
}
|
||||
binder->unlinkToDeath(this);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
#include <media/stagefright/foundation/ABase.h>
|
||||
#include <media/stagefright/foundation/AHandlerReflector.h>
|
||||
#include <media/stagefright/foundation/ALooper.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/List.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
#include "IMediaResourceManagerClient.h"
|
||||
#include "IMediaResourceManagerService.h"
|
||||
|
@ -20,20 +22,27 @@ namespace android {
|
|||
|
||||
/**
|
||||
* Manage permissions of using media resources(hw decoder, hw encoder, camera)
|
||||
* XXX Current implementaion support only one hw video decoder.
|
||||
* XXX Current implementation supports only one hw video codec.
|
||||
* Need to extend to support multiple instance and other resources.
|
||||
*/
|
||||
class MediaResourceManagerService: public BnMediaResourceManagerService,
|
||||
public IBinder::DeathRecipient
|
||||
{
|
||||
public:
|
||||
// The maximum number of hardware decoders available.
|
||||
enum { VIDEO_DECODER_COUNT = 1 };
|
||||
|
||||
enum {
|
||||
kNotifyRequest = 'noti'
|
||||
// The maximum number of hardware resoureces available.
|
||||
enum
|
||||
{
|
||||
VIDEO_DECODER_COUNT = 1,
|
||||
VIDEO_ENCODER_COUNT = 1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kNotifyRequest = 'noti',
|
||||
};
|
||||
|
||||
static const char* kMsgKeyResourceType;
|
||||
|
||||
// Instantiate MediaResourceManagerService and register to service manager.
|
||||
// If service manager is not present, wait until service manager becomes present.
|
||||
static void instantiate();
|
||||
|
@ -42,8 +51,10 @@ public:
|
|||
virtual void binderDied(const wp<IBinder>& who);
|
||||
|
||||
// derived from IMediaResourceManagerService
|
||||
virtual void requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType);
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client);
|
||||
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client,
|
||||
int resourceType, bool willWait);
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client,
|
||||
int resourceType);
|
||||
|
||||
// Receive a message from AHandlerReflector.
|
||||
// Called on ALooper thread.
|
||||
|
@ -53,30 +64,54 @@ protected:
|
|||
MediaResourceManagerService();
|
||||
virtual ~MediaResourceManagerService();
|
||||
|
||||
protected:
|
||||
private:
|
||||
// Represent a media resouce.
|
||||
// Hold a IMediaResourceManagerClient that got a media resource as IBinder.
|
||||
struct ResourceSlot {
|
||||
ResourceSlot ()
|
||||
{
|
||||
}
|
||||
sp<IBinder> mClient;
|
||||
};
|
||||
struct ResourceSlot
|
||||
{
|
||||
sp<IBinder> mClient;
|
||||
};
|
||||
typedef Vector<ResourceSlot> Slots;
|
||||
|
||||
void cancelClientLocked(const sp<IBinder>& binder);
|
||||
|
||||
// mVideoDecoderSlots is the array of slots that represent a media resource.
|
||||
ResourceSlot mVideoDecoderSlots[VIDEO_DECODER_COUNT];
|
||||
// The maximum number of hardware decoders available on the device.
|
||||
int mVideoDecoderCount;
|
||||
|
||||
// The lock protects mVideoDecoderSlots and mVideoCodecRequestQueue called
|
||||
// from multiple threads.
|
||||
Mutex mLock;
|
||||
typedef List<sp<IBinder> > Fifo;
|
||||
// Queue of media resource requests.
|
||||
// Hold IMediaResourceManagerClient that requesting a media resource as IBinder.
|
||||
Fifo mVideoCodecRequestQueue;
|
||||
struct Resources
|
||||
{
|
||||
// Queue of media resource requests. Hold IMediaResourceManagerClient that
|
||||
// requesting a media resource as IBinder.
|
||||
Fifo mRequestQueue;
|
||||
// All resources that can be requested. Hold |ResourceSlot|s that track
|
||||
// their usage.
|
||||
Slots mSlots;
|
||||
};
|
||||
|
||||
typedef KeyedVector<ResourceType, Resources> ResourcesMap;
|
||||
// Manages requests from clients and availability of resources.
|
||||
class ResourceTable
|
||||
{
|
||||
ResourceTable();
|
||||
~ResourceTable();
|
||||
// Resource operations.
|
||||
bool supportsType(ResourceType type);
|
||||
ssize_t findAvailableResource(ResourceType type, size_t number_needed = 1);
|
||||
bool isOwnedByClient(const sp<IBinder>& client, ResourceType type, size_t index);
|
||||
status_t aquireResource(const sp<IBinder>& client, ResourceType type, size_t index);
|
||||
ResourceSlot* resourceOfTypeAt(ResourceType type, size_t index);
|
||||
// Request operations.
|
||||
bool hasRequest(ResourceType type);
|
||||
uint32_t countRequests(ResourceType type);
|
||||
const sp<IBinder>& nextRequest(ResourceType type);
|
||||
status_t enqueueRequest(const sp<IBinder>& client, ResourceType type);
|
||||
status_t dequeueRequest(ResourceType type);
|
||||
status_t forgetClient(const sp<IBinder>& client, ResourceType type);
|
||||
status_t forgetClient(const sp<IBinder>& client);
|
||||
|
||||
friend class MediaResourceManagerService;
|
||||
|
||||
// A map for all types of supported resources.
|
||||
ResourcesMap mMap;
|
||||
};
|
||||
|
||||
void cancelClientLocked(const sp<IBinder>& binder, ResourceType resourceType);
|
||||
|
||||
// ALooper is a message loop used in stagefright.
|
||||
// It creates a thread for messages and handles messages in the thread.
|
||||
|
@ -88,6 +123,11 @@ protected:
|
|||
// http://developer.android.com/reference/android/os/Handler.html
|
||||
sp<AHandlerReflector<MediaResourceManagerService> > mReflector;
|
||||
|
||||
// The lock protects manager operations called from multiple threads.
|
||||
Mutex mLock;
|
||||
|
||||
// Keeps all the records.
|
||||
ResourceTable mResources;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
|
|
@ -4,6 +4,14 @@
|
|||
# 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/.
|
||||
|
||||
EXPORTS += [
|
||||
'IMediaResourceManagerClient.h',
|
||||
'IMediaResourceManagerDeathNotifier.h',
|
||||
'IMediaResourceManagerService.h',
|
||||
'MediaResourceManagerClient.h',
|
||||
'MediaResourceManagerService.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'IMediaResourceManagerClient.cpp',
|
||||
'IMediaResourceManagerDeathNotifier.cpp',
|
||||
|
|
|
@ -227,7 +227,6 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(AudioDestinationNode, AudioNode,
|
|||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioDestinationNode)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_END_INHERITING(AudioNode)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(AudioDestinationNode, AudioNode)
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIAudioChannelAgent.h"
|
||||
#include "AudioChannelCommon.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -22,7 +21,6 @@ class AudioContext;
|
|||
class AudioDestinationNode : public AudioNode
|
||||
, public nsIDOMEventListener
|
||||
, public nsIAudioChannelAgentCallback
|
||||
, public nsSupportsWeakReference
|
||||
, public MainThreadMediaStreamListener
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -9,11 +9,14 @@
|
|||
#include "AudioNodeStream.h"
|
||||
#include "AudioNodeEngine.h"
|
||||
#include "mozilla/dom/AudioParam.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static const uint32_t INVALID_PORT = 0xffffffff;
|
||||
static uint32_t gId = 0;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(AudioNode)
|
||||
|
||||
|
@ -49,6 +52,7 @@ AudioNode::Release()
|
|||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioNode)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
|
||||
AudioNode::AudioNode(AudioContext* aContext,
|
||||
|
@ -60,6 +64,10 @@ AudioNode::AudioNode(AudioContext* aContext,
|
|||
, mChannelCount(aChannelCount)
|
||||
, mChannelCountMode(aChannelCountMode)
|
||||
, mChannelInterpretation(aChannelInterpretation)
|
||||
, mId(gId++)
|
||||
#ifdef DEBUG
|
||||
, mDemiseNotified(false)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(aContext);
|
||||
DOMEventTargetHelper::BindToOwner(aContext->GetParentObject());
|
||||
|
@ -72,6 +80,10 @@ AudioNode::~AudioNode()
|
|||
MOZ_ASSERT(mInputNodes.IsEmpty());
|
||||
MOZ_ASSERT(mOutputNodes.IsEmpty());
|
||||
MOZ_ASSERT(mOutputParams.IsEmpty());
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(mDemiseNotified,
|
||||
"The webaudio-node-demise notification must have been sent");
|
||||
#endif
|
||||
if (mContext) {
|
||||
mContext->UpdateNodeCount(-1);
|
||||
}
|
||||
|
@ -385,6 +397,16 @@ AudioNode::DestroyMediaStream()
|
|||
|
||||
mStream->Destroy();
|
||||
mStream = nullptr;
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
nsAutoString id;
|
||||
id.AppendPrintf("%u", mId);
|
||||
obs->NotifyObservers(nullptr, "webaudio-node-demise", id.get());
|
||||
}
|
||||
#ifdef DEBUG
|
||||
mDemiseNotified = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "MediaStreamGraph.h"
|
||||
#include "WebAudioUtils.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -82,7 +83,8 @@ private:
|
|||
* still alive, and will still be alive when it receives a message from the
|
||||
* engine.
|
||||
*/
|
||||
class AudioNode : public DOMEventTargetHelper
|
||||
class AudioNode : public DOMEventTargetHelper,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
protected:
|
||||
// You can only use refcounting to delete this object
|
||||
|
@ -133,6 +135,8 @@ public:
|
|||
virtual uint16_t NumberOfInputs() const { return 1; }
|
||||
virtual uint16_t NumberOfOutputs() const { return 1; }
|
||||
|
||||
uint32_t Id() const { return mId; }
|
||||
|
||||
uint32_t ChannelCount() const { return mChannelCount; }
|
||||
virtual void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv)
|
||||
{
|
||||
|
@ -266,6 +270,12 @@ private:
|
|||
uint32_t mChannelCount;
|
||||
ChannelCountMode mChannelCountMode;
|
||||
ChannelInterpretation mChannelInterpretation;
|
||||
const uint32_t mId;
|
||||
#ifdef DEBUG
|
||||
// In debug builds, check to make sure that the node demise notification has
|
||||
// been properly sent before the node is destroyed.
|
||||
bool mDemiseNotified;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ MediaStreamAudioSourceNode::MediaStreamAudioSourceNode(AudioContext* aContext,
|
|||
ProcessedMediaStream* outputStream = static_cast<ProcessedMediaStream*>(mStream.get());
|
||||
mInputPort = outputStream->AllocateInputPort(aMediaStream->GetStream(),
|
||||
MediaInputPort::FLAG_BLOCK_INPUT);
|
||||
mInputStream->AddConsumerToKeepAlive(this);
|
||||
mInputStream->AddConsumerToKeepAlive(static_cast<nsIDOMEventTarget*>(this));
|
||||
|
||||
PrincipalChanged(mInputStream); // trigger enabling/disabling of the connector
|
||||
mInputStream->AddPrincipalChangeObserver(this);
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[DEFAULT]
|
||||
|
||||
[test_AudioNodeDevtoolsAPI.html]
|
|
@ -8,3 +8,7 @@ MOCHITEST_MANIFESTS += [
|
|||
'blink/mochitest.ini',
|
||||
'mochitest.ini',
|
||||
]
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += [
|
||||
'chrome.ini'
|
||||
]
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test the devtool AudioNode API</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var ac = new AudioContext();
|
||||
var ids;
|
||||
var weak;
|
||||
(function() {
|
||||
var src1 = ac.createBufferSource();
|
||||
var src2 = ac.createBufferSource();
|
||||
ok(src2.id > src1.id, "The ID should be monotonic");
|
||||
ok(src1.id > ac.destination.id, "The ID of the destination node should be the lowest");
|
||||
ids = [src1.id, src2.id];
|
||||
weak = Components.utils.getWeakReference(src1);
|
||||
is(weak.get(), src1, "The node should support a weak reference");
|
||||
})();
|
||||
function observer(subject, topic, data) {
|
||||
var id = parseInt(data);
|
||||
var index = ids.indexOf(id);
|
||||
if (index != -1) {
|
||||
info("Dropping id " + id + " at index " + index);
|
||||
ids.splice(index, 1);
|
||||
if (ids.length == 0) {
|
||||
SimpleTest.executeSoon(function() {
|
||||
is(weak.get(), null, "The weak reference must be dropped now");
|
||||
Services.obs.removeObserver(observer, "webaudio-node-demise");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Services.obs.addObserver(observer, "webaudio-node-demise", false);
|
||||
|
||||
forceCC();
|
||||
forceCC();
|
||||
|
||||
function forceCC() {
|
||||
SpecialPowers.DOMWindowUtils.cycleCollect();
|
||||
SpecialPowers.DOMWindowUtils.garbageCollect();
|
||||
SpecialPowers.DOMWindowUtils.garbageCollect();
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -60,6 +60,7 @@
|
|||
#include "mozilla/dom/CDATASection.h"
|
||||
#include "mozilla/dom/Comment.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/HTMLTemplateElement.h"
|
||||
#include "mozilla/dom/ProcessingInstruction.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
@ -848,7 +849,17 @@ nsXMLContentSink::PushContent(nsIContent *aContent)
|
|||
StackNode *sn = mContentStack.AppendElement();
|
||||
NS_ENSURE_TRUE(sn, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
sn->mContent = aContent;
|
||||
nsIContent* contentToPush = aContent;
|
||||
|
||||
// When an XML parser would append a node to a template element, it
|
||||
// must instead append it to the template element's template contents.
|
||||
if (contentToPush->IsHTML(nsGkAtoms::_template)) {
|
||||
HTMLTemplateElement* templateElement =
|
||||
static_cast<HTMLTemplateElement*>(contentToPush);
|
||||
contentToPush = templateElement->Content();
|
||||
}
|
||||
|
||||
sn->mContent = contentToPush;
|
||||
sn->mNumFlushed = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1076,8 +1087,13 @@ nsXMLContentSink::HandleEndElement(const char16_t *aName,
|
|||
nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix),
|
||||
getter_AddRefs(debugTagAtom),
|
||||
&debugNameSpaceID);
|
||||
NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID),
|
||||
"Wrong element being closed");
|
||||
// Check if we are closing a template element because template
|
||||
// elements do not get pushed on the stack, the template
|
||||
// element content is pushed instead.
|
||||
bool isTemplateElement = debugTagAtom == nsGkAtoms::_template &&
|
||||
debugNameSpaceID == kNameSpaceID_XHTML;
|
||||
NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID) ||
|
||||
isTemplateElement, "Wrong element being closed");
|
||||
#endif
|
||||
|
||||
result = CloseElement(content);
|
||||
|
|
|
@ -154,9 +154,13 @@ ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
|
|||
rv = GetFileResult(cx, &result, aFileList);
|
||||
break;
|
||||
|
||||
case GetFiles:
|
||||
rv = GetFilesResult(cx, &result, aFileList);
|
||||
break;
|
||||
case GetFiles:
|
||||
rv = GetFilesResult(cx, &result, aFileList);
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
|
@ -1497,7 +1497,7 @@ Navigator::GetFeature(const nsAString& aName)
|
|||
if (XRE_GetProcessType() == GeckoProcessType_Default) {
|
||||
uint32_t memLevel = mozilla::hal::GetTotalSystemMemoryLevel();
|
||||
if (memLevel == 0) {
|
||||
p->MaybeReject(NS_LITERAL_STRING("Abnormal"));
|
||||
p->MaybeReject(NS_ERROR_NOT_AVAILABLE);
|
||||
return p.forget();
|
||||
}
|
||||
p->MaybeResolve((int)memLevel);
|
||||
|
|
|
@ -244,6 +244,7 @@ AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
|||
, ScriptSettingsStackEntry(aGlobalObject, /* aCandidate = */ true)
|
||||
, mAc(cx(), aGlobalObject->GetGlobalJSObject())
|
||||
, mStack(ScriptSettingsStack::Ref())
|
||||
, mWebIDLCallerPrincipal(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(aGlobalObject);
|
||||
MOZ_ASSERT_IF(!aCx, aIsMainThread); // cx is mandatory off-main-thread.
|
||||
|
|
|
@ -179,7 +179,14 @@ public:
|
|||
private:
|
||||
JSAutoCompartment mAc;
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
nsCOMPtr<nsIPrincipal> mWebIDLCallerPrincipal;
|
||||
// It's safe to make this a weak pointer, since it's the subject principal
|
||||
// when we go on the stack, so can't go away until after we're gone. In
|
||||
// particular, this is only used from the CallSetup constructor, and only in
|
||||
// the aIsJSImplementedWebIDL case. And in that case, the subject principal
|
||||
// is the principal of the callee function that is part of the CallArgs just a
|
||||
// bit up the stack, and which will outlive us. So we know the principal
|
||||
// can't go away until then either.
|
||||
nsIPrincipal* mWebIDLCallerPrincipal;
|
||||
friend nsIPrincipal* GetWebIDLCallerPrincipal();
|
||||
};
|
||||
|
||||
|
|
|
@ -2615,13 +2615,6 @@ OldBindingConstructorEnabled(const nsGlobalNameStruct *aStruct,
|
|||
}
|
||||
}
|
||||
|
||||
// Don't expose CSSSupportsRule unless @supports processing is enabled.
|
||||
if (aStruct->mDOMClassInfoID == eDOMClassInfo_CSSSupportsRule_id) {
|
||||
if (!CSSSupportsRule::PrefEnabled()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't expose CSSFontFeatureValuesRule unless the pref is enabled
|
||||
if (aStruct->mDOMClassInfoID == eDOMClassInfo_CSSFontFeatureValuesRule_id) {
|
||||
return nsCSSFontFeatureValuesRule::PrefEnabled();
|
||||
|
|
|
@ -3025,7 +3025,7 @@ nsDOMWindowUtils::GetFileId(JS::Handle<JS::Value> aFile, JSContext* aCx,
|
|||
if (!aFile.isPrimitive()) {
|
||||
JSObject* obj = aFile.toObjectOrNull();
|
||||
|
||||
FileHandle* fileHandle;
|
||||
FileHandle* fileHandle = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileHandle, obj, fileHandle))) {
|
||||
*aResult = fileHandle->GetFileId();
|
||||
return NS_OK;
|
||||
|
|
|
@ -1562,7 +1562,7 @@ class CGClassConstructor(CGAbstractStaticMethod):
|
|||
ctorName=ctorName)
|
||||
|
||||
name = self._ctor.identifier.name
|
||||
nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
|
||||
nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
|
||||
callGenerator = CGMethodCall(nativeName, True, self.descriptor,
|
||||
self._ctor, isConstructor=True,
|
||||
constructorName=ctorName)
|
||||
|
@ -6947,7 +6947,7 @@ class CGSpecializedMethod(CGAbstractStaticMethod):
|
|||
@staticmethod
|
||||
def makeNativeName(descriptor, method):
|
||||
name = method.identifier.name
|
||||
return MakeNativeName(descriptor.binaryNames.get(name, name))
|
||||
return MakeNativeName(descriptor.binaryNameFor(name))
|
||||
|
||||
|
||||
class CGMethodPromiseWrapper(CGAbstractStaticMethod):
|
||||
|
@ -7036,7 +7036,7 @@ class CGLegacyCallHook(CGAbstractBindingMethod):
|
|||
|
||||
def generate_code(self):
|
||||
name = self._legacycaller.identifier.name
|
||||
nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
|
||||
nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
|
||||
return CGMethodCall(nativeName, False, self.descriptor,
|
||||
self._legacycaller)
|
||||
|
||||
|
@ -7287,7 +7287,7 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
|||
@staticmethod
|
||||
def makeNativeName(descriptor, attr):
|
||||
name = attr.identifier.name
|
||||
nativeName = MakeNativeName(descriptor.binaryNames.get(name, name))
|
||||
nativeName = MakeNativeName(descriptor.binaryNameFor(name))
|
||||
# resultOutParam does not depend on whether resultAlreadyAddRefed is set
|
||||
_, resultOutParam, _, _ = getRetvalDeclarationForType(attr.type,
|
||||
descriptor,
|
||||
|
@ -7390,7 +7390,7 @@ class CGSpecializedSetter(CGAbstractStaticMethod):
|
|||
@staticmethod
|
||||
def makeNativeName(descriptor, attr):
|
||||
name = attr.identifier.name
|
||||
return "Set" + MakeNativeName(descriptor.binaryNames.get(name, name))
|
||||
return "Set" + MakeNativeName(descriptor.binaryNameFor(name))
|
||||
|
||||
|
||||
class CGStaticSetter(CGAbstractStaticBindingMethod):
|
||||
|
@ -9095,7 +9095,7 @@ class CGProxySpecialOperation(CGPerSignatureCall):
|
|||
def __init__(self, descriptor, operation, checkFound=True, argumentMutableValue=None):
|
||||
self.checkFound = checkFound
|
||||
|
||||
nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation))
|
||||
nativeName = MakeNativeName(descriptor.binaryNameFor(operation))
|
||||
operation = descriptor.operations[operation]
|
||||
assert len(operation.signatures()) == 1
|
||||
signature = operation.signatures()[0]
|
||||
|
@ -12308,12 +12308,12 @@ def genConstructorBody(descriptor, initCall=""):
|
|||
# We're always fallible
|
||||
def callbackGetterName(attr, descriptor):
|
||||
return "Get" + MakeNativeName(
|
||||
descriptor.binaryNames.get(attr.identifier.name, attr.identifier.name))
|
||||
descriptor.binaryNameFor(attr.identifier.name))
|
||||
|
||||
|
||||
def callbackSetterName(attr, descriptor):
|
||||
return "Set" + MakeNativeName(
|
||||
descriptor.binaryNames.get(attr.identifier.name, attr.identifier.name))
|
||||
descriptor.binaryNameFor(attr.identifier.name))
|
||||
|
||||
|
||||
class CGJSImplGetter(CGJSImplMember):
|
||||
|
@ -13052,7 +13052,7 @@ class CallbackOperationBase(CallbackMethod):
|
|||
"""
|
||||
def __init__(self, signature, jsName, nativeName, descriptor, singleOperation, rethrowContentException=False):
|
||||
self.singleOperation = singleOperation
|
||||
self.methodName = descriptor.binaryNames.get(jsName, jsName)
|
||||
self.methodName = descriptor.binaryNameFor(jsName)
|
||||
CallbackMethod.__init__(self, signature, nativeName, descriptor, singleOperation, rethrowContentException)
|
||||
|
||||
def getThisDecl(self):
|
||||
|
@ -13107,7 +13107,7 @@ class CallbackOperation(CallbackOperationBase):
|
|||
jsName = method.identifier.name
|
||||
CallbackOperationBase.__init__(self, signature,
|
||||
jsName,
|
||||
MakeNativeName(descriptor.binaryNames.get(jsName, jsName)),
|
||||
MakeNativeName(descriptor.binaryNameFor(jsName)),
|
||||
descriptor, descriptor.interface.isSingleOperationInterface(),
|
||||
rethrowContentException=descriptor.interface.isJSImplemented())
|
||||
|
||||
|
@ -13151,8 +13151,7 @@ class CallbackGetter(CallbackAccessor):
|
|||
return${errorReturn};
|
||||
}
|
||||
""",
|
||||
attrName=self.descriptorProvider.binaryNames.get(self.attrName,
|
||||
self.attrName),
|
||||
attrName=self.descriptorProvider.binaryNameFor(self.attrName),
|
||||
errorReturn=self.getDefaultRetval())
|
||||
|
||||
|
||||
|
@ -13177,8 +13176,7 @@ class CallbackSetter(CallbackAccessor):
|
|||
return${errorReturn};
|
||||
}
|
||||
""",
|
||||
attrName=self.descriptorProvider.binaryNames.get(self.attrName,
|
||||
self.attrName),
|
||||
attrName=self.descriptorProvider.binaryNameFor(self.attrName),
|
||||
errorReturn=self.getDefaultRetval())
|
||||
|
||||
def getArgcDecl(self):
|
||||
|
|
|
@ -414,12 +414,9 @@ class Descriptor(DescriptorProvider):
|
|||
for attribute in ['implicitJSContext', 'resultNotAddRefed']:
|
||||
addExtendedAttribute(attribute, desc.get(attribute, {}))
|
||||
|
||||
self.binaryNames = desc.get('binaryNames', {})
|
||||
if '__legacycaller' not in self.binaryNames:
|
||||
self.binaryNames["__legacycaller"] = "LegacyCall"
|
||||
if '__stringifier' not in self.binaryNames:
|
||||
self.binaryNames["__stringifier"] = "Stringify"
|
||||
|
||||
self._binaryNames = desc.get('binaryNames', {})
|
||||
self._binaryNames.setdefault('__legacycaller', 'LegacyCall')
|
||||
self._binaryNames.setdefault('__stringifier', 'Stringify')
|
||||
|
||||
if not self.interface.isExternal():
|
||||
self.permissions = dict()
|
||||
|
@ -457,6 +454,9 @@ class Descriptor(DescriptorProvider):
|
|||
config.maxProtoChainLength = max(config.maxProtoChainLength,
|
||||
len(self.prototypeChain))
|
||||
|
||||
def binaryNameFor(self, name):
|
||||
return self._binaryNames.get(name, name)
|
||||
|
||||
def hasInterfaceOrInterfacePrototypeObject(self):
|
||||
|
||||
# Forward-declared interfaces don't need either interface object or
|
||||
|
|
|
@ -26,7 +26,7 @@ struct TypedArrayObjectStorage : AllTypedArraysBase {
|
|||
protected:
|
||||
JSObject* mObj;
|
||||
|
||||
TypedArrayObjectStorage(JSObject *obj) : mObj(obj)
|
||||
TypedArrayObjectStorage() : mObj(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -60,18 +60,8 @@ template<typename T,
|
|||
struct TypedArray_base : public TypedArrayObjectStorage {
|
||||
typedef T element_type;
|
||||
|
||||
TypedArray_base(JSObject* obj)
|
||||
: TypedArrayObjectStorage(obj),
|
||||
mData(nullptr),
|
||||
mLength(0),
|
||||
mComputed(false)
|
||||
{
|
||||
MOZ_ASSERT(obj != nullptr);
|
||||
}
|
||||
|
||||
TypedArray_base()
|
||||
: TypedArrayObjectStorage(nullptr),
|
||||
mData(nullptr),
|
||||
: mData(nullptr),
|
||||
mLength(0),
|
||||
mComputed(false)
|
||||
{
|
||||
|
@ -97,7 +87,7 @@ public:
|
|||
inline bool Init(JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(!inited());
|
||||
DoInit(obj);
|
||||
mObj = UnwrapArray(obj);
|
||||
return inited();
|
||||
}
|
||||
|
||||
|
@ -135,11 +125,6 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
inline void DoInit(JSObject* obj)
|
||||
{
|
||||
mObj = UnwrapArray(obj);
|
||||
}
|
||||
|
||||
inline void ComputeData() const {
|
||||
MOZ_ASSERT(inited());
|
||||
if (!mComputed) {
|
||||
|
@ -163,10 +148,6 @@ private:
|
|||
typedef TypedArray_base<T, UnwrapArray, GetLengthAndData> Base;
|
||||
|
||||
public:
|
||||
TypedArray(JSObject* obj)
|
||||
: Base(obj)
|
||||
{}
|
||||
|
||||
TypedArray()
|
||||
: Base()
|
||||
{}
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
#include "BluetoothService.h"
|
||||
#include "BluetoothUtils.h"
|
||||
|
||||
#define ERR_INVALID_ADAPTER_STATE "InvalidAdapterStateError"
|
||||
#define ERR_CHANGE_ADAPTER_STATE "ChangeAdapterStateError"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
|
@ -121,6 +124,7 @@ public:
|
|||
BluetoothReplyRunnable::ReleaseMembers();
|
||||
mAdapterPtr = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothAdapter> mAdapterPtr;
|
||||
};
|
||||
|
@ -156,6 +160,38 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class EnableDisableAdapterTask : public BluetoothReplyRunnable
|
||||
{
|
||||
public:
|
||||
EnableDisableAdapterTask(Promise* aPromise)
|
||||
: BluetoothReplyRunnable(nullptr)
|
||||
, mPromise(aPromise)
|
||||
{ }
|
||||
|
||||
bool
|
||||
ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
/*
|
||||
* It is supposed to be Promise<void> according to BluetoothAdapter.webidl,
|
||||
* but we have to pass "true" since it is mandatory to pass an
|
||||
* argument while calling MaybeResolve.
|
||||
*/
|
||||
mPromise->MaybeResolve(true);
|
||||
aValue.setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ReleaseMembers()
|
||||
{
|
||||
BluetoothReplyRunnable::ReleaseMembers();
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<Promise> mPromise;
|
||||
};
|
||||
|
||||
static int kCreatePairedDeviceTimeout = 50000; // unit: msec
|
||||
|
||||
BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow,
|
||||
|
@ -164,12 +200,13 @@ BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow,
|
|||
, BluetoothPropertyContainer(BluetoothObjectType::TYPE_ADAPTER)
|
||||
, mJsUuids(nullptr)
|
||||
, mJsDeviceAddresses(nullptr)
|
||||
// TODO: Change to Disabled after Bug 1006309 landed
|
||||
, mState(BluetoothAdapterState::Enabled)
|
||||
, mDiscoverable(false)
|
||||
, mDiscovering(false)
|
||||
, mPairable(false)
|
||||
, mPowered(false)
|
||||
, mIsRooted(false)
|
||||
, mState(BluetoothAdapterState::Disabled)
|
||||
{
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(IsDOMBinding());
|
||||
|
@ -231,7 +268,11 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
|
|||
{
|
||||
const nsString& name = aValue.name();
|
||||
const BluetoothValue& value = aValue.value();
|
||||
if (name.EqualsLiteral("Name")) {
|
||||
if (name.EqualsLiteral("State")) {
|
||||
bool isEnabled = value.get_bool();
|
||||
mState = isEnabled ? BluetoothAdapterState::Enabled
|
||||
: BluetoothAdapterState::Disabled;
|
||||
} else if (name.EqualsLiteral("Name")) {
|
||||
mName = value.get_nsString();
|
||||
} else if (name.EqualsLiteral("Address")) {
|
||||
mAddress = value.get_nsString();
|
||||
|
@ -669,19 +710,55 @@ BluetoothAdapter::SetPairingConfirmation(const nsAString& aDeviceAddress,
|
|||
return request.forget();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Implement Enable/Disable functions
|
||||
*/
|
||||
already_AddRefed<Promise>
|
||||
BluetoothAdapter::EnableDisable(bool aEnable)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
|
||||
NS_ENSURE_TRUE(global, nullptr);
|
||||
|
||||
nsRefPtr<Promise> promise = new Promise(global);
|
||||
|
||||
// Make sure BluetoothService is available before modifying adapter state
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
if (!bs) {
|
||||
promise->MaybeReject(ERR_CHANGE_ADAPTER_STATE);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
if (aEnable) {
|
||||
if (mState != BluetoothAdapterState::Disabled) {
|
||||
promise->MaybeReject(ERR_INVALID_ADAPTER_STATE);
|
||||
return promise.forget();
|
||||
}
|
||||
mState = BluetoothAdapterState::Enabling;
|
||||
} else {
|
||||
if (mState != BluetoothAdapterState::Enabled) {
|
||||
promise->MaybeReject(ERR_INVALID_ADAPTER_STATE);
|
||||
return promise.forget();
|
||||
}
|
||||
mState = BluetoothAdapterState::Disabling;
|
||||
}
|
||||
|
||||
// TODO: Fire attr changed event for this state change
|
||||
nsRefPtr<BluetoothReplyRunnable> result = new EnableDisableAdapterTask(promise);
|
||||
|
||||
if(NS_FAILED(bs->EnableDisable(aEnable, result))) {
|
||||
promise->MaybeReject(ERR_CHANGE_ADAPTER_STATE);
|
||||
}
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
BluetoothAdapter::Enable()
|
||||
{
|
||||
return nullptr;
|
||||
return EnableDisable(true);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
BluetoothAdapter::Disable()
|
||||
{
|
||||
return nullptr;
|
||||
return EnableDisable(false);
|
||||
}
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
|
|
|
@ -122,10 +122,9 @@ public:
|
|||
SetAuthorization(const nsAString& aDeviceAddress, bool aAllow,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Enable();
|
||||
already_AddRefed<Promise>
|
||||
Disable();
|
||||
already_AddRefed<Promise> EnableDisable(bool aEnable);
|
||||
already_AddRefed<Promise> Enable();
|
||||
already_AddRefed<Promise> Disable();
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
Connect(BluetoothDevice& aDevice,
|
||||
|
|
|
@ -163,14 +163,8 @@ BluetoothService::ToggleBtAck::Run()
|
|||
sBluetoothService->SetEnabled(mEnabled);
|
||||
sToggleInProgress = false;
|
||||
|
||||
nsAutoString signalName;
|
||||
signalName = mEnabled ? NS_LITERAL_STRING("Enabled")
|
||||
: NS_LITERAL_STRING("Disabled");
|
||||
BluetoothSignal signal(signalName, NS_LITERAL_STRING(KEY_MANAGER), true);
|
||||
sBluetoothService->DistributeSignal(signal);
|
||||
|
||||
// Event 'AdapterAdded' has to be fired after firing 'Enabled'
|
||||
sBluetoothService->TryFiringAdapterAdded();
|
||||
sBluetoothService->FireAdapterStateChanged(mEnabled);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -220,19 +214,6 @@ BluetoothService::~BluetoothService()
|
|||
Cleanup();
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
RemoveObserversExceptBluetoothManager
|
||||
(const nsAString& key,
|
||||
nsAutoPtr<BluetoothSignalObserverList>& value,
|
||||
void* arg)
|
||||
{
|
||||
if (!key.EqualsLiteral(KEY_MANAGER)) {
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
// static
|
||||
BluetoothService*
|
||||
BluetoothService::Create()
|
||||
|
@ -384,7 +365,8 @@ BluetoothService::DistributeSignal(const BluetoothSignal& aSignal)
|
|||
}
|
||||
|
||||
nsresult
|
||||
BluetoothService::StartBluetooth(bool aIsStartup)
|
||||
BluetoothService::StartBluetooth(bool aIsStartup,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -405,7 +387,7 @@ BluetoothService::StartBluetooth(bool aIsStartup)
|
|||
*/
|
||||
if (aIsStartup || !sBluetoothService->IsEnabled()) {
|
||||
// Switch Bluetooth on
|
||||
if (NS_FAILED(sBluetoothService->StartInternal())) {
|
||||
if (NS_FAILED(sBluetoothService->StartInternal(aRunnable))) {
|
||||
BT_WARNING("Bluetooth service failed to start!");
|
||||
}
|
||||
} else {
|
||||
|
@ -420,7 +402,8 @@ BluetoothService::StartBluetooth(bool aIsStartup)
|
|||
}
|
||||
|
||||
nsresult
|
||||
BluetoothService::StopBluetooth(bool aIsStartup)
|
||||
BluetoothService::StopBluetooth(bool aIsStartup,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -466,7 +449,7 @@ BluetoothService::StopBluetooth(bool aIsStartup)
|
|||
*/
|
||||
if (aIsStartup || sBluetoothService->IsEnabled()) {
|
||||
// Switch Bluetooth off
|
||||
if (NS_FAILED(sBluetoothService->StopInternal())) {
|
||||
if (NS_FAILED(sBluetoothService->StopInternal(aRunnable))) {
|
||||
BT_WARNING("Bluetooth service failed to stop!");
|
||||
}
|
||||
} else {
|
||||
|
@ -481,13 +464,15 @@ BluetoothService::StopBluetooth(bool aIsStartup)
|
|||
}
|
||||
|
||||
nsresult
|
||||
BluetoothService::StartStopBluetooth(bool aStart, bool aIsStartup)
|
||||
BluetoothService::StartStopBluetooth(bool aStart,
|
||||
bool aIsStartup,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
nsresult rv;
|
||||
if (aStart) {
|
||||
rv = StartBluetooth(aIsStartup);
|
||||
rv = StartBluetooth(aIsStartup, aRunnable);
|
||||
} else {
|
||||
rv = StopBluetooth(aIsStartup);
|
||||
rv = StopBluetooth(aIsStartup, aRunnable);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
@ -504,17 +489,6 @@ BluetoothService::SetEnabled(bool aEnabled)
|
|||
unused << childActors[index]->SendEnabled(aEnabled);
|
||||
}
|
||||
|
||||
if (!aEnabled) {
|
||||
/**
|
||||
* Remove all handlers except BluetoothManager when turning off bluetooth
|
||||
* since it is possible that the event 'onAdapterAdded' would be fired after
|
||||
* BluetoothManagers of child process are registered. Please see Bug 827759
|
||||
* for more details.
|
||||
*/
|
||||
mBluetoothSignalObserverTable.Enumerate(
|
||||
RemoveObserversExceptBluetoothManager, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* mEnabled: real status of bluetooth
|
||||
* aEnabled: expected status of bluetooth
|
||||
|
@ -553,7 +527,7 @@ nsresult
|
|||
BluetoothService::HandleStartupSettingsCheck(bool aEnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return StartStopBluetooth(aEnable, true);
|
||||
return StartStopBluetooth(aEnable, true, nullptr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -610,37 +584,6 @@ BluetoothService::HandleSettingsChanged(const nsAString& aData)
|
|||
}
|
||||
|
||||
SWITCH_BT_DEBUG(value.toBoolean());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Second, check if the string is BLUETOOTH_ENABLED_SETTING
|
||||
if (!JS_StringEqualsAscii(cx, key.toString(), BLUETOOTH_ENABLED_SETTING, &match)) {
|
||||
MOZ_ASSERT(!JS_IsExceptionPending(cx));
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (match) {
|
||||
JS::Rooted<JS::Value> value(cx);
|
||||
if (!JS_GetProperty(cx, obj, "value", &value)) {
|
||||
MOZ_ASSERT(!JS_IsExceptionPending(cx));
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (!value.isBoolean()) {
|
||||
MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.enabled'!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (sToggleInProgress || value.toBoolean() == IsEnabled()) {
|
||||
// Nothing to do here.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
sToggleInProgress = true;
|
||||
|
||||
nsresult rv = StartStopBluetooth(value.toBoolean(), false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -704,7 +647,7 @@ BluetoothService::HandleShutdown()
|
|||
}
|
||||
}
|
||||
|
||||
if (IsEnabled() && NS_FAILED(StopBluetooth(false))) {
|
||||
if (IsEnabled() && NS_FAILED(StopBluetooth(false, nullptr))) {
|
||||
MOZ_ASSERT(false, "Failed to deliver stop message!");
|
||||
}
|
||||
|
||||
|
@ -785,6 +728,38 @@ BluetoothService::AdapterAddedReceived()
|
|||
mAdapterAddedReceived = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable the local adapter.
|
||||
*
|
||||
* There is only one adapter on the mobile in current use cases.
|
||||
* In addition, bluedroid couldn't enable/disable a single adapter.
|
||||
* So currently we will turn on/off BT to enable/disable the adapter.
|
||||
*
|
||||
* TODO: To support enable/disable single adapter in the future,
|
||||
* we will need to implement EnableDisableInternal for different stacks.
|
||||
*/
|
||||
nsresult
|
||||
BluetoothService::EnableDisable(bool aEnable,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
sToggleInProgress = true;
|
||||
return StartStopBluetooth(aEnable, false, aRunnable);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothService::FireAdapterStateChanged(bool aEnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
InfallibleTArray<BluetoothNamedValue> props;
|
||||
BT_APPEND_NAMED_VALUE(props, "State", aEnable);
|
||||
BluetoothValue value(props);
|
||||
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER), value);
|
||||
DistributeSignal(signal);
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothService::Notify(const BluetoothSignal& aData)
|
||||
{
|
||||
|
|
|
@ -315,6 +315,28 @@ public:
|
|||
void TryFiringAdapterAdded();
|
||||
void AdapterAddedReceived();
|
||||
|
||||
void FireAdapterStateChanged(bool aEnable);
|
||||
nsresult EnableDisable(bool aEnable,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
/**
|
||||
* Platform specific startup functions go here. Usually deals with member
|
||||
* variables, so not static. Guaranteed to be called outside of main thread.
|
||||
*
|
||||
* @return NS_OK on correct startup, NS_ERROR_FAILURE otherwise
|
||||
*/
|
||||
virtual nsresult
|
||||
StartInternal(BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
/**
|
||||
* Platform specific startup functions go here. Usually deals with member
|
||||
* variables, so not static. Guaranteed to be called outside of main thread.
|
||||
*
|
||||
* @return NS_OK on correct startup, NS_ERROR_FAILURE otherwise
|
||||
*/
|
||||
virtual nsresult
|
||||
StopInternal(BluetoothReplyRunnable* aRunnable) = 0;
|
||||
|
||||
protected:
|
||||
BluetoothService() : mEnabled(false)
|
||||
, mAdapterAddedReceived(false)
|
||||
|
@ -330,31 +352,15 @@ protected:
|
|||
Cleanup();
|
||||
|
||||
nsresult
|
||||
StartBluetooth(bool aIsStartup);
|
||||
StartBluetooth(bool aIsStartup, BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
nsresult
|
||||
StopBluetooth(bool aIsStartup);
|
||||
StopBluetooth(bool aIsStartup, BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
nsresult
|
||||
StartStopBluetooth(bool aStart, bool aIsStartup);
|
||||
|
||||
/**
|
||||
* Platform specific startup functions go here. Usually deals with member
|
||||
* variables, so not static. Guaranteed to be called outside of main thread.
|
||||
*
|
||||
* @return NS_OK on correct startup, NS_ERROR_FAILURE otherwise
|
||||
*/
|
||||
virtual nsresult
|
||||
StartInternal() = 0;
|
||||
|
||||
/**
|
||||
* Platform specific startup functions go here. Usually deals with member
|
||||
* variables, so not static. Guaranteed to be called outside of main thread.
|
||||
*
|
||||
* @return NS_OK on correct startup, NS_ERROR_FAILURE otherwise
|
||||
*/
|
||||
virtual nsresult
|
||||
StopInternal() = 0;
|
||||
StartStopBluetooth(bool aStart,
|
||||
bool aIsStartup,
|
||||
BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
/**
|
||||
* Called when XPCOM first creates this service.
|
||||
|
|
|
@ -33,34 +33,47 @@
|
|||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
#define ENSURE_BLUETOOTH_IS_READY(runnable, result) \
|
||||
do { \
|
||||
if (!sBtInterface || !IsEnabled()) { \
|
||||
NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth is not ready"); \
|
||||
DispatchBluetoothReply(runnable, BluetoothValue(), errorStr); \
|
||||
return result; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::ipc;
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
|
||||
/**
|
||||
* Static variables
|
||||
*/
|
||||
static bluetooth_device_t* sBtDevice;
|
||||
static const bt_interface_t* sBtInterface;
|
||||
static bool sAdapterDiscoverable = false;
|
||||
static bool sIsBtEnabled = false;
|
||||
// TODO: Non thread-safe static variables
|
||||
static nsString sAdapterBdAddress;
|
||||
static nsString sAdapterBdName;
|
||||
static uint32_t sAdapterDiscoverableTimeout;
|
||||
static InfallibleTArray<nsString> sAdapterBondedAddressArray;
|
||||
static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeAdapterStateRunnableArray;
|
||||
|
||||
// Static variables below should only be used on *main thread*
|
||||
static const bt_interface_t* sBtInterface;
|
||||
static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
|
||||
static nsTArray<int> sRequestedDeviceCountArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
|
||||
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
|
||||
|
||||
// Static variables below should only be used on *callback thread*
|
||||
|
||||
|
||||
// Atomic static variables
|
||||
static Atomic<bool> sAdapterDiscoverable(false);
|
||||
static Atomic<uint32_t> sAdapterDiscoverableTimeout(0);
|
||||
|
||||
/**
|
||||
* Classes only used in this file
|
||||
*/
|
||||
class DistributeBluetoothSignalTask : public nsRunnable {
|
||||
class DistributeBluetoothSignalTask MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
DistributeBluetoothSignalTask(const BluetoothSignal& aSignal) :
|
||||
mSignal(aSignal)
|
||||
|
@ -84,12 +97,9 @@ private:
|
|||
BluetoothSignal mSignal;
|
||||
};
|
||||
|
||||
class SetupAfterEnabledTask : public nsRunnable
|
||||
class SetupAfterEnabledTask MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SetupAfterEnabledTask()
|
||||
{ }
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
|
@ -135,17 +145,37 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class CleanupTask : public nsRunnable
|
||||
class CleanupTask MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
CleanupTask()
|
||||
{ }
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
/*
|
||||
* Cleanup static adapter properties and notify adapter to clean them
|
||||
*
|
||||
* TODO: clean up and notify Discovering also
|
||||
*/
|
||||
sAdapterBdAddress.Truncate();
|
||||
sAdapterBdName.Truncate();
|
||||
sAdapterDiscoverable = false;
|
||||
|
||||
InfallibleTArray<BluetoothNamedValue> props;
|
||||
BT_APPEND_NAMED_VALUE(props, "Name", sAdapterBdName);
|
||||
BT_APPEND_NAMED_VALUE(props, "Address", sAdapterBdAddress);
|
||||
BT_APPEND_NAMED_VALUE(props, "Discoverable",
|
||||
BluetoothValue(sAdapterDiscoverable));
|
||||
BluetoothValue value(props);
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER), value);
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
||||
|
||||
bs->DistributeSignal(signal);
|
||||
|
||||
// Cleanup bluetooth interfaces after BT state becomes BT_STATE_OFF.
|
||||
BluetoothHfpManager::DeinitHfpInterface();
|
||||
BluetoothA2dpManager::DeinitA2dpInterface();
|
||||
|
@ -270,45 +300,69 @@ PlayStatusStringToControlPlayStatus(const nsAString& aPlayStatus)
|
|||
return playStatus;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsReady()
|
||||
{
|
||||
if (!sBtInterface || !sIsBtEnabled) {
|
||||
BT_LOGR("Warning! Bluetooth Service is not ready");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bluedroid HAL callback functions
|
||||
*
|
||||
* Several callbacks are dispatched to main thread to avoid racing issues.
|
||||
*/
|
||||
static void
|
||||
AdapterStateChangeCallback(bt_state_t aStatus)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
BT_LOGR("BT_STATE %d", aStatus);
|
||||
BT_LOGR("BT_STATE: %d", aStatus);
|
||||
|
||||
sIsBtEnabled = (aStatus == BT_STATE_ON);
|
||||
bool isBtEnabled = (aStatus == BT_STATE_ON);
|
||||
|
||||
if (!sIsBtEnabled && NS_FAILED(NS_DispatchToMainThread(new CleanupTask()))) {
|
||||
if (!isBtEnabled &&
|
||||
NS_FAILED(NS_DispatchToMainThread(new CleanupTask()))) {
|
||||
BT_WARNING("Failed to dispatch to main thread!");
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<nsRunnable> runnable =
|
||||
new BluetoothService::ToggleBtAck(sIsBtEnabled);
|
||||
new BluetoothService::ToggleBtAck(isBtEnabled);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
|
||||
BT_WARNING("Failed to dispatch to main thread!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sIsBtEnabled &&
|
||||
if (isBtEnabled &&
|
||||
NS_FAILED(NS_DispatchToMainThread(new SetupAfterEnabledTask()))) {
|
||||
BT_WARNING("Failed to dispatch to main thread!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Resolve promise if existed
|
||||
if(!sChangeAdapterStateRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sChangeAdapterStateRunnableArray[0],
|
||||
BluetoothValue(true),
|
||||
EmptyString());
|
||||
sChangeAdapterStateRunnableArray.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
class AdapterPropertiesCallbackTask MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sSetPropertyRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sSetPropertyRunnableArray[0],
|
||||
BluetoothValue(true), EmptyString());
|
||||
sSetPropertyRunnableArray.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* AdapterPropertiesCallback will be called after enable() but before
|
||||
* AdapterStateChangeCallback sIsBtEnabled get updated. At that moment, both
|
||||
* AdapterStateChangeCallback is called. At that moment, both
|
||||
* BluetoothManager/BluetoothAdapter does not register observer yet.
|
||||
*/
|
||||
static void
|
||||
|
@ -385,14 +439,64 @@ AdapterPropertiesCallback(bt_status_t aStatus, int aNumProperties,
|
|||
BT_WARNING("Failed to dispatch to main thread!");
|
||||
}
|
||||
|
||||
// bluedroid BTU task was stored in the task queue, see GKI_send_msg
|
||||
if (!sSetPropertyRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sSetPropertyRunnableArray[0], BluetoothValue(true),
|
||||
EmptyString());
|
||||
sSetPropertyRunnableArray.RemoveElementAt(0);
|
||||
}
|
||||
// Redirect to main thread to avoid racing problem
|
||||
NS_DispatchToMainThread(new AdapterPropertiesCallbackTask());
|
||||
}
|
||||
|
||||
class RemoteDevicePropertiesCallbackTask : public nsRunnable
|
||||
{
|
||||
const InfallibleTArray<BluetoothNamedValue> mProps;
|
||||
nsString mRemoteDeviceBdAddress;
|
||||
public:
|
||||
RemoteDevicePropertiesCallbackTask(
|
||||
const InfallibleTArray<BluetoothNamedValue>& aProps,
|
||||
const nsAString& aRemoteDeviceBdAddress)
|
||||
: mProps(aProps)
|
||||
, mRemoteDeviceBdAddress(aRemoteDeviceBdAddress)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (sRequestedDeviceCountArray.IsEmpty()) {
|
||||
// This is possible because the callback would be called after turning
|
||||
// Bluetooth on.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Update to registered BluetoothDevice objects
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
|
||||
mRemoteDeviceBdAddress, mProps);
|
||||
nsRefPtr<DistributeBluetoothSignalTask>
|
||||
t = new DistributeBluetoothSignalTask(signal);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(t))) {
|
||||
BT_WARNING("Failed to dispatch to main thread!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack;
|
||||
|
||||
// Use address as the index
|
||||
sRemoteDevicesPack.AppendElement(
|
||||
BluetoothNamedValue(mRemoteDeviceBdAddress, mProps));
|
||||
|
||||
if (--sRequestedDeviceCountArray[0] == 0) {
|
||||
if (!sGetDeviceRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sGetDeviceRunnableArray[0],
|
||||
sRemoteDevicesPack, EmptyString());
|
||||
sGetDeviceRunnableArray.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
sRequestedDeviceCountArray.RemoveElementAt(0);
|
||||
sRemoteDevicesPack.Clear();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* RemoteDevicePropertiesCallback will be called, as the following conditions:
|
||||
* 1. When BT is turning on, bluedroid automatically execute this callback
|
||||
|
@ -404,13 +508,6 @@ RemoteDevicePropertiesCallback(bt_status_t aStatus, bt_bdaddr_t *aBdAddress,
|
|||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
if (sRequestedDeviceCountArray.IsEmpty()) {
|
||||
MOZ_ASSERT(sGetDeviceRunnableArray.IsEmpty());
|
||||
return;
|
||||
}
|
||||
|
||||
sRequestedDeviceCountArray[0]--;
|
||||
|
||||
InfallibleTArray<BluetoothNamedValue> props;
|
||||
|
||||
nsString remoteDeviceBdAddress;
|
||||
|
@ -435,36 +532,9 @@ RemoteDevicePropertiesCallback(bt_status_t aStatus, bt_bdaddr_t *aBdAddress,
|
|||
}
|
||||
}
|
||||
|
||||
// Update to registered BluetoothDevice objects
|
||||
BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
|
||||
remoteDeviceBdAddress, props);
|
||||
nsRefPtr<DistributeBluetoothSignalTask>
|
||||
t = new DistributeBluetoothSignalTask(signal);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(t))) {
|
||||
BT_WARNING("Failed to dispatch to main thread!");
|
||||
}
|
||||
|
||||
// Use address as the index
|
||||
sRemoteDevicesPack.AppendElement(
|
||||
BluetoothNamedValue(remoteDeviceBdAddress, props));
|
||||
|
||||
if (sRequestedDeviceCountArray[0] == 0) {
|
||||
MOZ_ASSERT(!sGetDeviceRunnableArray.IsEmpty());
|
||||
|
||||
if (sGetDeviceRunnableArray.IsEmpty()) {
|
||||
BT_LOGR("No runnable to return");
|
||||
return;
|
||||
}
|
||||
|
||||
DispatchBluetoothReply(sGetDeviceRunnableArray[0],
|
||||
sRemoteDevicesPack, EmptyString());
|
||||
|
||||
// After firing it, clean up cache
|
||||
sRemoteDevicesPack.Clear();
|
||||
|
||||
sRequestedDeviceCountArray.RemoveElementAt(0);
|
||||
sGetDeviceRunnableArray.RemoveElementAt(0);
|
||||
}
|
||||
// Redirect to main thread to avoid racing problem
|
||||
NS_DispatchToMainThread(
|
||||
new RemoteDevicePropertiesCallbackTask(props, remoteDeviceBdAddress));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -511,18 +581,33 @@ DeviceFoundCallback(int aNumProperties, bt_property_t *aProperties)
|
|||
}
|
||||
}
|
||||
|
||||
class DiscoveryStateChangedCallbackTask MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sChangeDiscoveryRunnableArray.IsEmpty()) {
|
||||
BluetoothValue values(true);
|
||||
DispatchBluetoothReply(sChangeDiscoveryRunnableArray[0],
|
||||
values, EmptyString());
|
||||
|
||||
sChangeDiscoveryRunnableArray.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
DiscoveryStateChangedCallback(bt_discovery_state_t aState)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
if (!sChangeDiscoveryRunnableArray.IsEmpty()) {
|
||||
BluetoothValue values(true);
|
||||
DispatchBluetoothReply(sChangeDiscoveryRunnableArray[0],
|
||||
values, EmptyString());
|
||||
|
||||
sChangeDiscoveryRunnableArray.RemoveElementAt(0);
|
||||
}
|
||||
// Redirect to main thread to avoid racing problem
|
||||
NS_DispatchToMainThread(new DiscoveryStateChangedCallbackTask());
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -581,26 +666,75 @@ SspRequestCallback(bt_bdaddr_t* aRemoteBdAddress, bt_bdname_t* aRemoteBdName,
|
|||
}
|
||||
}
|
||||
|
||||
class BondStateChangedCallbackTask : public nsRunnable
|
||||
{
|
||||
nsString mRemoteDeviceBdAddress;
|
||||
bool mBonded;
|
||||
public:
|
||||
BondStateChangedCallbackTask(const nsAString& aRemoteDeviceBdAddress,
|
||||
bool aBonded)
|
||||
: mRemoteDeviceBdAddress(aRemoteDeviceBdAddress)
|
||||
, mBonded(aBonded)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mBonded && !sBondingRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sBondingRunnableArray[0],
|
||||
BluetoothValue(true), EmptyString());
|
||||
|
||||
sBondingRunnableArray.RemoveElementAt(0);
|
||||
} else if (!mBonded && !sUnbondingRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sUnbondingRunnableArray[0],
|
||||
BluetoothValue(true), EmptyString());
|
||||
|
||||
sUnbondingRunnableArray.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
// Update bonding status to gaia
|
||||
InfallibleTArray<BluetoothNamedValue> propertiesArray;
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "address", mRemoteDeviceBdAddress);
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "status", mBonded);
|
||||
|
||||
BluetoothSignal signal(NS_LITERAL_STRING(PAIRED_STATUS_CHANGED_ID),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER),
|
||||
BluetoothValue(propertiesArray));
|
||||
NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
BondStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress,
|
||||
bt_bond_state_t aState)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
nsAutoString remoteAddress;
|
||||
BdAddressTypeToString(aRemoteBdAddress, remoteAddress);
|
||||
if (aState == BT_BOND_STATE_BONDING) {
|
||||
// No need to handle bonding state
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString remoteBdAddress;
|
||||
BdAddressTypeToString(aRemoteBdAddress, remoteBdAddress);
|
||||
|
||||
if (aState == BT_BOND_STATE_BONDED &&
|
||||
sAdapterBondedAddressArray.Contains(remoteBdAddress)) {
|
||||
// See bug 940271 for more details about this case.
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't need to handle bonding state
|
||||
NS_ENSURE_TRUE_VOID(aState != BT_BOND_STATE_BONDING);
|
||||
NS_ENSURE_FALSE_VOID(aState == BT_BOND_STATE_BONDED &&
|
||||
sAdapterBondedAddressArray.Contains(remoteAddress));
|
||||
bool bonded;
|
||||
if (aState == BT_BOND_STATE_NONE) {
|
||||
bonded = false;
|
||||
sAdapterBondedAddressArray.RemoveElement(remoteAddress);
|
||||
sAdapterBondedAddressArray.RemoveElement(remoteBdAddress);
|
||||
} else if (aState == BT_BOND_STATE_BONDED) {
|
||||
bonded = true;
|
||||
sAdapterBondedAddressArray.AppendElement(remoteAddress);
|
||||
sAdapterBondedAddressArray.AppendElement(remoteBdAddress);
|
||||
}
|
||||
|
||||
// Update bonded address list to BluetoothAdapter
|
||||
|
@ -614,27 +748,9 @@ BondStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress,
|
|||
BluetoothValue(propertiesChangeArray));
|
||||
NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal));
|
||||
|
||||
// Update bonding status to gaia
|
||||
InfallibleTArray<BluetoothNamedValue> propertiesArray;
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
|
||||
BT_APPEND_NAMED_VALUE(propertiesArray, "status", bonded);
|
||||
|
||||
BluetoothSignal newSignal(NS_LITERAL_STRING(PAIRED_STATUS_CHANGED_ID),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER),
|
||||
BluetoothValue(propertiesArray));
|
||||
NS_DispatchToMainThread(new DistributeBluetoothSignalTask(newSignal));
|
||||
|
||||
if (bonded && !sBondingRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sBondingRunnableArray[0],
|
||||
BluetoothValue(true), EmptyString());
|
||||
|
||||
sBondingRunnableArray.RemoveElementAt(0);
|
||||
} else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sUnbondingRunnableArray[0],
|
||||
BluetoothValue(true), EmptyString());
|
||||
|
||||
sUnbondingRunnableArray.RemoveElementAt(0);
|
||||
}
|
||||
// Redirect to main thread to avoid racing problem
|
||||
NS_DispatchToMainThread(
|
||||
new BondStateChangedCallbackTask(remoteBdAddress, bonded));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -673,15 +789,17 @@ EnsureBluetoothHalLoad()
|
|||
{
|
||||
hw_module_t* module;
|
||||
hw_device_t* device;
|
||||
|
||||
int err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
|
||||
if (err != 0) {
|
||||
BT_LOGR("Error: %s", strerror(err));
|
||||
return false;
|
||||
}
|
||||
module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
|
||||
sBtDevice = (bluetooth_device_t *)device;
|
||||
NS_ENSURE_TRUE(sBtDevice, false);
|
||||
sBtInterface = sBtDevice->get_bluetooth_interface();
|
||||
bluetooth_device_t* btDevice = (bluetooth_device_t *)device;
|
||||
NS_ENSURE_TRUE(btDevice, false);
|
||||
|
||||
sBtInterface = btDevice->get_bluetooth_interface();
|
||||
NS_ENSURE_TRUE(sBtInterface, false);
|
||||
|
||||
return true;
|
||||
|
@ -709,12 +827,16 @@ static nsresult
|
|||
StartStopGonkBluetooth(bool aShouldEnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE);
|
||||
|
||||
if (sIsBtEnabled == aShouldEnable) {
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
||||
|
||||
if (bs->IsEnabled() == aShouldEnable) {
|
||||
// Keep current enable status
|
||||
nsRefPtr<nsRunnable> runnable =
|
||||
new BluetoothService::ToggleBtAck(sIsBtEnabled);
|
||||
new BluetoothService::ToggleBtAck(aShouldEnable);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
|
||||
BT_WARNING("Failed to dispatch to main thread!");
|
||||
}
|
||||
|
@ -772,10 +894,15 @@ BluetoothServiceBluedroid::~BluetoothServiceBluedroid()
|
|||
}
|
||||
|
||||
nsresult
|
||||
BluetoothServiceBluedroid::StartInternal()
|
||||
BluetoothServiceBluedroid::StartInternal(BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// aRunnable will be a nullptr while startup
|
||||
if(aRunnable) {
|
||||
sChangeAdapterStateRunnableArray.AppendElement(aRunnable);
|
||||
}
|
||||
|
||||
nsresult ret = StartStopGonkBluetooth(true);
|
||||
if (NS_FAILED(ret)) {
|
||||
nsRefPtr<nsRunnable> runnable =
|
||||
|
@ -790,10 +917,15 @@ BluetoothServiceBluedroid::StartInternal()
|
|||
}
|
||||
|
||||
nsresult
|
||||
BluetoothServiceBluedroid::StopInternal()
|
||||
BluetoothServiceBluedroid::StopInternal(BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// aRunnable will be a nullptr during starup and shutdown
|
||||
if(aRunnable) {
|
||||
sChangeAdapterStateRunnableArray.AppendElement(aRunnable);
|
||||
}
|
||||
|
||||
nsresult ret = StartStopGonkBluetooth(false);
|
||||
if (NS_FAILED(ret)) {
|
||||
nsRefPtr<nsRunnable> runnable =
|
||||
|
@ -828,6 +960,11 @@ BluetoothServiceBluedroid::GetAdaptersInternal(
|
|||
uint32_t numAdapters = 1; // Bluedroid supports single adapter only
|
||||
|
||||
for (uint32_t i = 0; i < numAdapters; i++) {
|
||||
// Since Atomic<*> is not acceptable for BT_APPEND_NAMED_VALUE(),
|
||||
// create another variable to store data.
|
||||
bool discoverable = sAdapterDiscoverable;
|
||||
uint32_t discoverableTimeout = sAdapterDiscoverableTimeout;
|
||||
|
||||
BluetoothValue properties = InfallibleTArray<BluetoothNamedValue>();
|
||||
|
||||
// TODO: Revise here based on new BluetoothAdapter interface
|
||||
|
@ -836,9 +973,9 @@ BluetoothServiceBluedroid::GetAdaptersInternal(
|
|||
BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
|
||||
"Name", sAdapterBdName);
|
||||
BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
|
||||
"Discoverable", sAdapterDiscoverable);
|
||||
"Discoverable", discoverable);
|
||||
BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
|
||||
"DiscoverableTimeout", sAdapterDiscoverableTimeout);
|
||||
"DiscoverableTimeout", discoverableTimeout);
|
||||
BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
|
||||
"Devices", sAdapterBondedAddressArray);
|
||||
|
||||
|
@ -856,11 +993,7 @@ BluetoothServiceBluedroid::GetConnectedDevicePropertiesInternal(
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!IsReady()) {
|
||||
NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
|
||||
return NS_OK;
|
||||
}
|
||||
ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
|
||||
|
||||
BluetoothProfileManagerBase* profile =
|
||||
BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid);
|
||||
|
@ -910,11 +1043,7 @@ BluetoothServiceBluedroid::GetPairedDevicePropertiesInternal(
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!IsReady()) {
|
||||
NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
|
||||
return NS_OK;
|
||||
}
|
||||
ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
|
||||
|
||||
int requestedDeviceCount = aDeviceAddress.Length();
|
||||
if (requestedDeviceCount == 0) {
|
||||
|
@ -947,12 +1076,8 @@ BluetoothServiceBluedroid::StartDiscoveryInternal(
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!IsReady()) {
|
||||
NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
|
||||
ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
int ret = sBtInterface->start_discovery();
|
||||
if (ret != BT_STATUS_SUCCESS) {
|
||||
ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StartDiscovery"));
|
||||
|
@ -970,11 +1095,7 @@ BluetoothServiceBluedroid::StopDiscoveryInternal(
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!IsReady()) {
|
||||
NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
|
||||
return NS_OK;
|
||||
}
|
||||
ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
|
||||
|
||||
int ret = sBtInterface->cancel_discovery();
|
||||
if (ret != BT_STATUS_SUCCESS) {
|
||||
|
@ -994,12 +1115,7 @@ BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType,
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!IsReady()) {
|
||||
NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
|
||||
|
||||
const nsString propName = aValue.name();
|
||||
bt_property_t prop;
|
||||
|
@ -1072,11 +1188,7 @@ BluetoothServiceBluedroid::CreatePairedDeviceInternal(
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!IsReady()) {
|
||||
NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
|
||||
return NS_OK;
|
||||
}
|
||||
ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
|
||||
|
||||
bt_bdaddr_t remoteAddress;
|
||||
StringToBdAddressType(aDeviceAddress, &remoteAddress);
|
||||
|
@ -1097,11 +1209,7 @@ BluetoothServiceBluedroid::RemoveDeviceInternal(
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!IsReady()) {
|
||||
NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
|
||||
return NS_OK;
|
||||
}
|
||||
ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
|
||||
|
||||
bt_bdaddr_t remoteAddress;
|
||||
StringToBdAddressType(aDeviceAddress, &remoteAddress);
|
||||
|
@ -1124,11 +1232,7 @@ BluetoothServiceBluedroid::SetPinCodeInternal(
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!IsReady()) {
|
||||
NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
|
||||
return false;
|
||||
}
|
||||
ENSURE_BLUETOOTH_IS_READY(aRunnable, false);
|
||||
|
||||
bt_bdaddr_t remoteAddress;
|
||||
StringToBdAddressType(aDeviceAddress, &remoteAddress);
|
||||
|
@ -1161,11 +1265,7 @@ BluetoothServiceBluedroid::SetPairingConfirmationInternal(
|
|||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!IsReady()) {
|
||||
NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
|
||||
DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
|
||||
return false;
|
||||
}
|
||||
ENSURE_BLUETOOTH_IS_READY(aRunnable, false);
|
||||
|
||||
bt_bdaddr_t remoteAddress;
|
||||
StringToBdAddressType(aDeviceAddress, &remoteAddress);
|
||||
|
|
|
@ -22,8 +22,8 @@ public:
|
|||
BluetoothServiceBluedroid();
|
||||
~BluetoothServiceBluedroid();
|
||||
|
||||
virtual nsresult StartInternal();
|
||||
virtual nsresult StopInternal();
|
||||
virtual nsresult StartInternal(BluetoothReplyRunnable* aRunnable);
|
||||
virtual nsresult StopInternal(BluetoothReplyRunnable* aRunnable);
|
||||
|
||||
virtual nsresult
|
||||
GetAdaptersInternal(BluetoothReplyRunnable* aRunnable);
|
||||
|
|
|
@ -2097,8 +2097,10 @@ public:
|
|||
};
|
||||
|
||||
nsresult
|
||||
BluetoothDBusService::StartInternal()
|
||||
BluetoothDBusService::StartInternal(BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(!aRunnable);
|
||||
|
||||
nsRefPtr<nsRunnable> runnable = new StartBluetoothRunnable();
|
||||
nsresult rv = DispatchToBtThread(runnable);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -2225,8 +2227,10 @@ public:
|
|||
};
|
||||
|
||||
nsresult
|
||||
BluetoothDBusService::StopInternal()
|
||||
BluetoothDBusService::StopInternal(BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(!aRunnable);
|
||||
|
||||
nsRefPtr<nsRunnable> runnable = new StopBluetoothRunnable();
|
||||
nsresult rv = DispatchToBtThread(runnable);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
|
@ -47,9 +47,9 @@ public:
|
|||
|
||||
bool IsReady();
|
||||
|
||||
virtual nsresult StartInternal() MOZ_OVERRIDE;
|
||||
virtual nsresult StartInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult StopInternal() MOZ_OVERRIDE;
|
||||
virtual nsresult StopInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult
|
||||
GetAdaptersInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
|
|
@ -192,6 +192,10 @@ BluetoothParent::RecvPBluetoothRequestConstructor(
|
|||
switch (aRequest.type()) {
|
||||
case Request::TGetAdaptersRequest:
|
||||
return actor->DoRequest(aRequest.get_GetAdaptersRequest());
|
||||
case Request::TStartBluetoothRequest:
|
||||
return actor->DoRequest(aRequest.get_StartBluetoothRequest());
|
||||
case Request::TStopBluetoothRequest:
|
||||
return actor->DoRequest(aRequest.get_StopBluetoothRequest());
|
||||
case Request::TSetPropertyRequest:
|
||||
return actor->DoRequest(aRequest.get_SetPropertyRequest());
|
||||
case Request::TStartDiscoveryRequest:
|
||||
|
@ -321,6 +325,30 @@ BluetoothRequestParent::DoRequest(const GetAdaptersRequest& aRequest)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(const StartBluetoothRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
MOZ_ASSERT(mRequestType == Request::TStartBluetoothRequest);
|
||||
|
||||
nsresult rv = mService->StartInternal(mReplyRunnable.get());
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(const StopBluetoothRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
MOZ_ASSERT(mRequestType == Request::TStopBluetoothRequest);
|
||||
|
||||
nsresult rv = mService->StopInternal(mReplyRunnable.get());
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothRequestParent::DoRequest(const SetPropertyRequest& aRequest)
|
||||
{
|
||||
|
|
|
@ -128,6 +128,12 @@ protected:
|
|||
bool
|
||||
DoRequest(const GetAdaptersRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const StartBluetoothRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const StopBluetoothRequest& aRequest);
|
||||
|
||||
bool
|
||||
DoRequest(const SetPropertyRequest& aRequest);
|
||||
|
||||
|
|
|
@ -103,6 +103,20 @@ BluetoothServiceChildProcess::GetAdaptersInternal(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
BluetoothServiceChildProcess::StartInternal(BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
SendRequest(aRunnable, StartBluetoothRequest());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
BluetoothServiceChildProcess::StopInternal(BluetoothReplyRunnable* aRunnable)
|
||||
{
|
||||
SendRequest(aRunnable, StopBluetoothRequest());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
BluetoothServiceChildProcess::GetConnectedDevicePropertiesInternal(
|
||||
uint16_t aServiceUuid,
|
||||
|
@ -377,18 +391,6 @@ BluetoothServiceChildProcess::HandleShutdown()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
BluetoothServiceChildProcess::StartInternal()
|
||||
{
|
||||
MOZ_CRASH("This should never be called!");
|
||||
}
|
||||
|
||||
nsresult
|
||||
BluetoothServiceChildProcess::StopInternal()
|
||||
{
|
||||
MOZ_CRASH("This should never be called!");
|
||||
}
|
||||
|
||||
bool
|
||||
BluetoothServiceChildProcess::IsConnected(uint16_t aServiceUuid)
|
||||
{
|
||||
|
|
|
@ -46,6 +46,12 @@ public:
|
|||
virtual nsresult
|
||||
GetAdaptersInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult
|
||||
StartInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult
|
||||
StopInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult
|
||||
GetPairedDevicePropertiesInternal(const nsTArray<nsString>& aDeviceAddresses,
|
||||
BluetoothReplyRunnable* aRunnable)
|
||||
|
@ -199,14 +205,6 @@ protected:
|
|||
HandleShutdown() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
// This method should never be called.
|
||||
virtual nsresult
|
||||
StartInternal() MOZ_OVERRIDE;
|
||||
|
||||
// This method should never be called.
|
||||
virtual nsresult
|
||||
StopInternal() MOZ_OVERRIDE;
|
||||
|
||||
bool
|
||||
IsSignalRegistered(const nsAString& aNodeName) {
|
||||
return !!mBluetoothSignalObserverTable.Get(aNodeName);
|
||||
|
|
|
@ -25,6 +25,14 @@ namespace bluetooth {
|
|||
struct GetAdaptersRequest
|
||||
{ };
|
||||
|
||||
struct StartBluetoothRequest
|
||||
{
|
||||
};
|
||||
|
||||
struct StopBluetoothRequest
|
||||
{
|
||||
};
|
||||
|
||||
struct SetPropertyRequest
|
||||
{
|
||||
BluetoothObjectType type;
|
||||
|
@ -166,6 +174,8 @@ struct SendPlayStatusRequest
|
|||
union Request
|
||||
{
|
||||
GetAdaptersRequest;
|
||||
StartBluetoothRequest;
|
||||
StopBluetoothRequest;
|
||||
SetPropertyRequest;
|
||||
GetPropertyRequest;
|
||||
StartDiscoveryRequest;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "domstubs.idl"
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMMozCellBroadcastEtwsInfo;
|
||||
|
@ -10,7 +11,7 @@ interface nsIDOMMozCellBroadcastEtwsInfo;
|
|||
* MozCellBroadcastMessage encapsulates Cell Broadcast short message service
|
||||
* (CBS) messages.
|
||||
*/
|
||||
[scriptable, uuid(6abe65de-6729-41f7-906a-3f3a2dbe30ae)]
|
||||
[scriptable, uuid(701e74a9-5fc4-4e2d-a324-9b7693395159)]
|
||||
interface nsIDOMMozCellBroadcastMessage : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -53,7 +54,7 @@ interface nsIDOMMozCellBroadcastMessage : nsISupports
|
|||
/**
|
||||
* System time stamp at receival.
|
||||
*/
|
||||
readonly attribute jsval timestamp; // jsval is for Date.
|
||||
readonly attribute DOMTimeStamp timestamp;
|
||||
|
||||
/**
|
||||
* Additional ETWS-specific info.
|
||||
|
|
|
@ -196,7 +196,7 @@ function testReceiving_ETWS_Timestamp() {
|
|||
doTestHelper(pdu, testReceiving_ETWS_WarningType, function(message) {
|
||||
// Cell Broadcast messages do not contain a timestamp field (however, ETWS
|
||||
// does). We only check the timestamp doesn't go too far (60 seconds) here.
|
||||
let msMessage = message.timestamp.getTime();
|
||||
let msMessage = message.timestamp;
|
||||
let msNow = Date.now();
|
||||
ok(Math.abs(msMessage - msNow) < (1000 * 60), "message.timestamp");
|
||||
});
|
||||
|
|
|
@ -361,7 +361,7 @@ function testReceiving_GSM_Timestamp() {
|
|||
doTestHelper(pdu, testReceiving_GSM_WarningType, function(message) {
|
||||
// Cell Broadcast messages do not contain a timestamp field (however, ETWS
|
||||
// does). We only check the timestamp doesn't go too far (60 seconds) here.
|
||||
let msMessage = message.timestamp.getTime();
|
||||
let msMessage = message.timestamp;
|
||||
let msNow = Date.now();
|
||||
ok(Math.abs(msMessage - msNow) < (1000 * 60), "message.timestamp");
|
||||
});
|
||||
|
|
|
@ -150,7 +150,7 @@ RejectPromise(nsPIDOMWindow* aWindow, Promise* aPromise, nsresult aRv)
|
|||
NS_LITERAL_STRING("An error occurred"));
|
||||
}
|
||||
|
||||
aPromise->MaybeReject(error);
|
||||
aPromise->MaybeRejectBrokenly(error);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -20,13 +20,149 @@
|
|||
#define DEFINE_KEYNAME_WITH_SAME_NAME(aName) \
|
||||
DEFINE_KEYNAME_INTERNAL(aName, #aName)
|
||||
|
||||
/******************************************************************************
|
||||
* Special Key Values
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Unidentified)
|
||||
|
||||
/******************************************************************************
|
||||
* Our Internal Key Values (must have "Moz" prefix)
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_INTERNAL(PrintableKey, "MozPrintableKey")
|
||||
|
||||
/******************************************************************************
|
||||
* Modifier Keys
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Alt)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AltGraph)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(CapsLock)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Control)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Fn)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(FnLock)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Hyper)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Meta)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(NumLock)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(OS)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ScrollLock)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Shift)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Super)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Symbol)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(SymbolLock)
|
||||
|
||||
/******************************************************************************
|
||||
* Whitespace Keys
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Enter)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Separator)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Tab)
|
||||
|
||||
/******************************************************************************
|
||||
* Navigation Keys
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Down) // Rename to ArrowDown
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Left) // Rename to ArrowLeft
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Right) // Rename to ArrowRight
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Up) // Rename to ArrowUp
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(End)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Home)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PageDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PageUp)
|
||||
|
||||
/******************************************************************************
|
||||
* Editing Keys
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Backspace)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Clear)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Copy)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Crsel) // Rename to CrSel
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Cut)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Del) // Rename to Delete
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(EraseEof)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Exsel) // Rename to ExSel
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Insert)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Paste)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Redo)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Undo)
|
||||
|
||||
/******************************************************************************
|
||||
* UI Keys
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Accept)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Again)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Attn)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Apps)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Crsel)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Exsel)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Cancel)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Menu) // Rename to ContextMenu
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Esc) // Rename to Escape
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Execute)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Find)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Help)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Pause)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Play)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Props)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Select)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ZoomIn)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ZoomOut)
|
||||
|
||||
/******************************************************************************
|
||||
* Device Keys
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrightnessDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrightnessUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Camera)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Eject)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LogOff)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Power)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(PowerOff)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PrintScreen)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Hibernate)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Standby)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(WakeUp)
|
||||
|
||||
/******************************************************************************
|
||||
* IME and Composition Keys
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AllCandidates)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Alphanumeric)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(CodeInput)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Compose)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Convert)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Dead)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(FinalMode)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(GroupFirst)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(GroupLast)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(GroupNext)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(GroupPrevious)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ModeChange)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(NextCandidate)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Nonconvert) // Rename to NonConvert
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PreviousCandidate)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Process)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(SingleCandidate)
|
||||
|
||||
/******************************************************************************
|
||||
* Keys specific to Korean keyboards
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(HangulMode)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(HanjaMode)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(JunjaMode)
|
||||
|
||||
/******************************************************************************
|
||||
* Keys specific to Japanese keyboards
|
||||
*****************************************************************************/
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Eisu)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(HalfWidth) // Rename to Hankaku
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Hiragana)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(HiraganaKatakana)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(KanaMode)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(KanjiMode)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Katakana)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(RomanCharacters) // Rename to Romaji
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(FullWidth) // Rename to Zenkaku
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ZenkakuHankaku)
|
||||
|
||||
/******************************************************************************
|
||||
* General-Purpose Function Keys
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(F1)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(F2)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(F3)
|
||||
|
@ -62,6 +198,47 @@ DEFINE_KEYNAME_WITH_SAME_NAME(F32)
|
|||
DEFINE_KEYNAME_WITH_SAME_NAME(F33)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(F34)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(F35)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Soft1)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Soft2)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Soft3)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Soft4)
|
||||
|
||||
/******************************************************************************
|
||||
* Multimedia Keys
|
||||
*****************************************************************************/
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Close)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(MailForward)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(MailReply)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(MailSend)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlayPause)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(SelectMedia) // Rename to MediaSelect
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaStop)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaNextTrack) // Rename to MediaTrackNext
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaPreviousTrack) // Rename to MediaTrackPrevious
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(New)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Open)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Print)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Save)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(SpellCheck)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VolumeDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VolumeUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VolumeMute)
|
||||
|
||||
/******************************************************************************
|
||||
* Application Keys
|
||||
*****************************************************************************/
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchCalculator)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchCalendar)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMail)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMediaPlayer)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMusicPlayer)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMyComputer)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchScreenSaver)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchSpreadsheet)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWebBrowser)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWebCam)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWordProcessor)
|
||||
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication1)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication2)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication3)
|
||||
|
@ -80,64 +257,103 @@ DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication15)
|
|||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication16)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication17)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication18)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMail)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(List)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Props)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Soft1)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Soft2)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Soft3)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Soft4)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Accept)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Again)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Enter)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Find)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Help)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Info)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Menu)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Pause)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Play)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ScrollLock) // IE9 users "Scroll"
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Execute)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Cancel)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Esc)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Exit)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Zoom)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrightnessDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrightnessUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Camera)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Eject)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Power)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PrintScreen)
|
||||
|
||||
/******************************************************************************
|
||||
* Browser Keys
|
||||
*****************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrowserBack)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrowserFavorites)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrowserForward)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrowserHome)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrowserRefresh)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrowserSearch)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrowserStop)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrowserBack)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(BrowserForward)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Left)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PageDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PageUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Right)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Up)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(UpLeft)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(UpRight)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Down)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DownLeft)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DownRight)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Home)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(End)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Select)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Tab)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Backspace)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Clear)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Copy)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Cut)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Del)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(EraseEof)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Insert)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Paste)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Undo)
|
||||
|
||||
/******************************************************************************
|
||||
* Media Controller Keys
|
||||
*****************************************************************************/
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(AudioBalanceLeft)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(AudioBalanceRight)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostUp)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderFront)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderRear)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(AudioSurroundModeNext)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(AVRInput)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(AVRPower)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ChannelDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ChannelUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Red) // Rename to ColorF0Red
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Green) // Rename to ColorF1Green
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Yellow) // Rename to ColorF2Yellow
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Blue) // Rename to ColorF3Blue
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Grey) // Rename to ColorF4Grey
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Brown) // Rename to ColorF5Brown
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ClosedCaptionToggle)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Dimmer)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(DisplaySwap)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Exit)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite0) // Rename to FavoriteClear0
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite1) // Rename to FavoriteClear1
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite2) // Rename to FavoriteClear2
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite3) // Rename to FavoriteClear3
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite0) // Rename to FavoriteRecall0
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite1) // Rename to FavoriteRecall1
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite2) // Rename to FavoriteRecall2
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite3) // Rename to FavoriteRecall3
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite0) // Rename to FavoriteStore0
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite1) // Rename to FavoriteStore1
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite2) // Rename to FavoriteStore2
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite3) // Rename to FavoriteStore3
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Guide)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(NextDay) // Rename to GuideNextDay
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(PrevDay) // Rename to GuidePreviousDay
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Info)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(InstantReplay)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Link)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(List) // Rename to ListProgram
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Live) // Rename to LiveContent
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Lock)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Apps) // Rename to MediaApps
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(FastFwd) // Rename to MediaFastForward
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaLast)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaPause)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlay)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaRecord)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaRewind)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(MediaSkip)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(NextFavoriteChannel)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(NextUserProfile)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(OnDemand)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(PinPDown)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(PinPMove)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PinPToggle)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(PinPUp)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedDown)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedReset)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(RandomToggle)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(RcLowBattery)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(RecordSpeedNext)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(RfBypass)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ScanChannelsToggle)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(ScreenModeNext)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Settings)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(SplitScreenToggle)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(STBInput)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(STBPower)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Subtitle)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Teletext)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(TV)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(TVInput)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(TVPower)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(VideoModeNext)
|
||||
// DEFINE_KEYNAME_WITH_SAME_NAME(Wink)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Zoom) // Rename to ZoomToggle
|
||||
|
||||
/******************************************************************************
|
||||
* Deprecated
|
||||
******************************************************************************/
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadGrave)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadAcute)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadCircumflex)
|
||||
|
@ -154,112 +370,6 @@ DEFINE_KEYNAME_WITH_SAME_NAME(DeadOgonek)
|
|||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadIota)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadVoicedSound)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DeadSemivoicedSound)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Alphanumeric)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Alt)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AltGraph)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(CapsLock)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Control)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Fn)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(FnLock)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Meta)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Process)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(NumLock)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Shift)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(SymbolLock)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(OS) // IE9 uses "Win"
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Compose)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AllCandidates)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(NextCandidate)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PreviousCandidate)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(CodeInput)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Convert)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Nonconvert)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(FinalMode)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(FullWidth)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(HalfWidth)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ModeChange)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(RomanCharacters)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(HangulMode)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(HanjaMode)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(JunjaMode)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Hiragana)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(KanaMode)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(KanjiMode)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Katakana)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderFront)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderRear)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioBalanceLeft)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioBalanceRight)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VolumeMute)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VolumeDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VolumeUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaPause)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlay)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaStop)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaNextTrack)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaPreviousTrack)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlayPause)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaTrackSkip)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaTrackStart)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaTrackEnd)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(SelectMedia)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Blue)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Brown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ChannelDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ChannelUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite0)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite1)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite2)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite3)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Dimmer)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DisplaySwap)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(FastFwd)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Green)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Grey)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Guide)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(InstantReplay)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaLast)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Link)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Live)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Lock)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(NextDay)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(NextFavoriteChannel)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(OnDemand)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PinPDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PinPMove)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PinPToggle)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PinPUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedDown)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedReset)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedUp)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(PrevDay)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(RandomToggle)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite0)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite1)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite2)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite3)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaRecord)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(RecordSpeedNext)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Red)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(MediaRewind)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(RfBypass)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ScanChannelsToggle)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(ScreenModeNext)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Settings)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(SplitScreenToggle)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite0)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite1)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite2)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite3)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Subtitle)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(AudioSurroundModeNext)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Teletext)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(VideoModeNext)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(DisplayWide)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Wink)
|
||||
DEFINE_KEYNAME_WITH_SAME_NAME(Yellow)
|
||||
|
||||
#undef DEFINE_KEYNAME_WITH_SAME_NAME
|
||||
#undef DEFINE_KEYNAME_INTERNAL
|
||||
|
|
|
@ -42,7 +42,7 @@ DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Digit8)
|
|||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Digit9)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Equal)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(IntlBackslash)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(IntlHash)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(IntlHash)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(IntlRo)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(IntlYen)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(KeyA)
|
||||
|
@ -97,9 +97,9 @@ DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Convert)
|
|||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(KanaMode)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang1)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang2)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang3)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang4)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang5)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang3)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang4)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang5)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NonConvert)
|
||||
|
||||
// Control pad section
|
||||
|
@ -131,21 +131,21 @@ DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Numpad8)
|
|||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Numpad9)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadAdd)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadBackspace)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadClear)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadClearEntry)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadClear)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadClearEntry)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadComma)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadDecimal)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadDivide)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadEnter)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadEqual)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryAdd)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryClear)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryRecall)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryStore)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryAdd)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryClear)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryRecall)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryStore)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemorySubtract)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMultiply)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadParenLeft)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadParenRight)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadParenLeft)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadParenRight)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadSubtract)
|
||||
|
||||
// Function section
|
||||
|
@ -175,7 +175,7 @@ DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F22)
|
|||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F23)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F24)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Fn)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(FLock)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(FLock)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(PrintScreen)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(ScrollLock)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Pause)
|
||||
|
@ -205,13 +205,12 @@ DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(VolumeUp)
|
|||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(WakeUp)
|
||||
|
||||
// Legacy keys
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Abort)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Hyper)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Meta)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Resume)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Super)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Suspend)
|
||||
DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Turbo)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Abort)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Hyper)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Resume)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Super)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Suspend)
|
||||
// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Turbo)
|
||||
|
||||
#undef DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME
|
||||
#undef NS_DEFINE_PHYSICAL_KEY_CODE_NAME_INTERNAL
|
||||
|
|
|
@ -122,7 +122,7 @@ CreateDirectoryTask::HandlerCallback()
|
|||
if (HasError()) {
|
||||
nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
|
||||
mErrorValue);
|
||||
mPromise->MaybeReject(domError);
|
||||
mPromise->MaybeRejectBrokenly(domError);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -287,7 +287,7 @@ CreateFileTask::HandlerCallback()
|
|||
if (HasError()) {
|
||||
nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
|
||||
mErrorValue);
|
||||
mPromise->MaybeReject(domError);
|
||||
mPromise->MaybeRejectBrokenly(domError);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -197,7 +197,7 @@ GetFileOrDirectoryTask::HandlerCallback()
|
|||
if (HasError()) {
|
||||
nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
|
||||
mErrorValue);
|
||||
mPromise->MaybeReject(domError);
|
||||
mPromise->MaybeRejectBrokenly(domError);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -185,7 +185,7 @@ RemoveTask::HandlerCallback()
|
|||
if (HasError()) {
|
||||
nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
|
||||
mErrorValue);
|
||||
mPromise->MaybeReject(domError);
|
||||
mPromise->MaybeRejectBrokenly(domError);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1473,7 +1473,7 @@ ContentChild::RecvSystemMemoryAvailable(const uint64_t& aGetterId,
|
|||
nsRefPtr<Promise> p = dont_AddRef(reinterpret_cast<Promise*>(aGetterId));
|
||||
|
||||
if (!aMemoryAvailable) {
|
||||
p->MaybeReject(NS_LITERAL_STRING("Abnormal"));
|
||||
p->MaybeReject(NS_ERROR_NOT_AVAILABLE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include "TabChild.h"
|
||||
#include "LoadContext.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
@ -1888,9 +1889,7 @@ bool
|
|||
TabParent::UseAsyncPanZoom()
|
||||
{
|
||||
bool usingOffMainThreadCompositing = !!CompositorParent::CompositorLoop();
|
||||
bool asyncPanZoomEnabled =
|
||||
Preferences::GetBool("layers.async-pan-zoom.enabled", false);
|
||||
return (usingOffMainThreadCompositing && asyncPanZoomEnabled &&
|
||||
return (usingOffMainThreadCompositing && gfxPrefs::AsyncPanZoomEnabled() &&
|
||||
GetScrollingBehavior() == ASYNC_PAN_ZOOM);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,5 +7,3 @@
|
|||
DIRS += ['interfaces', 'src']
|
||||
TEST_DIRS += ['tests']
|
||||
|
||||
if CONFIG['ENABLE_TESTS']:
|
||||
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell.ini']
|
||||
|
|
|
@ -4,5 +4,8 @@
|
|||
# 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/.
|
||||
|
||||
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
||||
MOCHITEST_MANIFESTS += ['mochitest/mochitest.ini']
|
||||
|
||||
if CONFIG['ENABLE_TESTS']:
|
||||
XPCSHELL_TESTS_MANIFESTS += ['xpcshell/xpcshell.ini']
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
[DEFAULT]
|
||||
head = header_helpers.js
|
||||
tail =
|
||||
support-files =
|
||||
test_sms_basics.html
|
||||
test_smsfilter.html
|
||||
|
||||
[test_smsservice_createsmsmessage.js]
|
||||
[test_wsp_pdu_helper.js]
|
|
@ -7,6 +7,7 @@
|
|||
#include "mozilla/dom/Promise.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "mozilla/dom/OwningNonNull.h"
|
||||
#include "mozilla/dom/PromiseBinding.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
|
@ -1431,5 +1432,15 @@ PromiseWorkerProxy::CleanUp(JSContext* aCx)
|
|||
mCleanedUp = true;
|
||||
}
|
||||
|
||||
// Specializations of MaybeRejectBrokenly we actually support.
|
||||
template<>
|
||||
void Promise::MaybeRejectBrokenly(const nsRefPtr<DOMError>& aArg) {
|
||||
MaybeSomething(aArg, &Promise::MaybeReject);
|
||||
}
|
||||
template<>
|
||||
void Promise::MaybeRejectBrokenly(const nsAString& aArg) {
|
||||
MaybeSomething(aArg, &Promise::MaybeReject);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
|
||||
class AnyCallback;
|
||||
class DOMError;
|
||||
class PromiseCallback;
|
||||
class PromiseInit;
|
||||
class PromiseNativeHandler;
|
||||
|
@ -89,11 +90,21 @@ public:
|
|||
MaybeSomething(aArg, &Promise::MaybeResolve);
|
||||
}
|
||||
|
||||
// aArg is a const reference so we can pass rvalues like NS_ERROR_*
|
||||
template <typename T>
|
||||
void MaybeReject(const T& aArg) {
|
||||
inline void MaybeReject(nsresult aArg) {
|
||||
MOZ_ASSERT(NS_FAILED(aArg));
|
||||
MaybeSomething(aArg, &Promise::MaybeReject);
|
||||
}
|
||||
// DO NOT USE MaybeRejectBrokenly with in new code. Promises should be
|
||||
// rejected with Error instances.
|
||||
// Note: MaybeRejectBrokenly is a template so we can use it with DOMError
|
||||
// without instantiating the DOMError specialization of MaybeSomething in
|
||||
// every translation unit that includes this header, because that would
|
||||
// require use to include DOMError.h either here or in all those translation
|
||||
// units.
|
||||
template<typename T>
|
||||
void MaybeRejectBrokenly(const T& aArg); // Not implemented by default; see
|
||||
// specializations in the .cpp for
|
||||
// the T values we support.
|
||||
|
||||
// WebIDL
|
||||
|
||||
|
|
|
@ -1494,10 +1494,13 @@ this.PushService = {
|
|||
let iccInfo = icc.getIccInfo(clientId);
|
||||
if (iccInfo) {
|
||||
debug("Running on mobile data");
|
||||
let ips = {};
|
||||
let prefixLengths = {};
|
||||
nm.active.getAddresses(ips, prefixLengths);
|
||||
return {
|
||||
mcc: iccInfo.mcc,
|
||||
mnc: iccInfo.mnc,
|
||||
ip: nm.active.ip
|
||||
ip: ips.value[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -312,7 +312,7 @@ function CellBroadcastMessage(pdu) {
|
|||
this.language = pdu.language;
|
||||
this.body = pdu.fullBody;
|
||||
this.messageClass = pdu.messageClass;
|
||||
this.timestamp = new Date(pdu.timestamp);
|
||||
this.timestamp = pdu.timestamp;
|
||||
|
||||
if (pdu.etws != null) {
|
||||
this.etws = new CellBroadcastEtwsInfo(pdu.etws);
|
||||
|
|
|
@ -12791,9 +12791,17 @@ SimRecordHelperObject.prototype = {
|
|||
|
||||
let ICCUtilsHelper = this.context.ICCUtilsHelper;
|
||||
let RIL = this.context.RIL;
|
||||
// TS 31.102, clause 4.2.18 EFAD
|
||||
let mncLength = 0;
|
||||
if (ad && ad[3]) {
|
||||
mncLength = ad[3] & 0x0f;
|
||||
if (mncLength != 0x02 && mncLength != 0x03) {
|
||||
mncLength = 0;
|
||||
}
|
||||
}
|
||||
// The 4th byte of the response is the length of MNC.
|
||||
let mccMnc = ICCUtilsHelper.parseMccMncFromImsi(RIL.iccInfoPrivate.imsi,
|
||||
ad && ad[3]);
|
||||
mncLength);
|
||||
if (mccMnc) {
|
||||
RIL.iccInfo.mcc = mccMnc.mcc;
|
||||
RIL.iccInfo.mnc = mccMnc.mnc;
|
||||
|
@ -14130,6 +14138,7 @@ ICCUtilsHelperObject.prototype = {
|
|||
* The imsi of icc.
|
||||
* @param mncLength [optional]
|
||||
* The length of mnc.
|
||||
* Zero indicates we haven't got a valid mnc length.
|
||||
*
|
||||
* @return An object contains the parsing result of mcc and mnc.
|
||||
* Or null if any error occurred.
|
||||
|
|
|
@ -2504,7 +2504,7 @@ add_test(function test_reading_ad_and_parsing_mcc_mnc() {
|
|||
|
||||
io.loadTransparentEF = function fakeLoadTransparentEF(options) {
|
||||
let ad = [0x00, 0x00, 0x00];
|
||||
if (mncLengthInEf) {
|
||||
if (typeof mncLengthInEf === 'number') {
|
||||
ad.push(mncLengthInEf);
|
||||
}
|
||||
|
||||
|
@ -2531,9 +2531,20 @@ add_test(function test_reading_ad_and_parsing_mcc_mnc() {
|
|||
}
|
||||
|
||||
do_test(undefined, "466923202422409", "466", "92" );
|
||||
do_test(0x00, "466923202422409", "466", "92" );
|
||||
do_test(0x01, "466923202422409", "466", "92" );
|
||||
do_test(0x02, "466923202422409", "466", "92" );
|
||||
do_test(0x03, "466923202422409", "466", "923");
|
||||
do_test(0x04, "466923202422409", "466", "92" );
|
||||
do_test(0xff, "466923202422409", "466", "92" );
|
||||
|
||||
do_test(undefined, "310260542718417", "310", "260");
|
||||
do_test(0x00, "310260542718417", "310", "260");
|
||||
do_test(0x01, "310260542718417", "310", "260");
|
||||
do_test(0x02, "310260542718417", "310", "26" );
|
||||
do_test(0x03, "310260542718417", "310", "260");
|
||||
do_test(0x04, "310260542718417", "310", "260");
|
||||
do_test(0xff, "310260542718417", "310", "260");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
NS_IMETHODIMP
|
||||
NotifyDialError(const nsAString& aError)
|
||||
{
|
||||
mPromise->MaybeReject(aError);
|
||||
mPromise->MaybeRejectBrokenly(aError);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -255,13 +255,13 @@ Telephony::DialInternal(uint32_t aServiceId, const nsAString& aNumber,
|
|||
nsRefPtr<Promise> promise = new Promise(global);
|
||||
|
||||
if (!IsValidNumber(aNumber) || !IsValidServiceId(aServiceId)) {
|
||||
promise->MaybeReject(NS_LITERAL_STRING("InvalidAccessError"));
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
// We only support one outgoing call at a time.
|
||||
if (HasDialingCall()) {
|
||||
promise->MaybeReject(NS_LITERAL_STRING("InvalidStateError"));
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
@ -269,7 +269,7 @@ Telephony::DialInternal(uint32_t aServiceId, const nsAString& aNumber,
|
|||
new Callback(this, promise, aServiceId, aNumber);
|
||||
nsresult rv = mService->Dial(aServiceId, aNumber, aIsEmergency, callback);
|
||||
if (NS_FAILED(rv)) {
|
||||
promise->MaybeReject(NS_LITERAL_STRING("InvalidStateError"));
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ support-files =
|
|||
inert_style.css
|
||||
|
||||
[test_bug900724.html]
|
||||
[test_bug1017896.html]
|
||||
[test_content_element.html]
|
||||
[test_nested_content_element.html]
|
||||
[test_dest_insertion_points.html]
|
||||
|
@ -16,6 +17,7 @@ support-files =
|
|||
[test_document_register_stack.html]
|
||||
[test_document_shared_registry.html]
|
||||
[test_template.html]
|
||||
[test_template_xhtml.html]
|
||||
[test_shadowroot.html]
|
||||
[test_shadowroot_inert_element.html]
|
||||
[test_shadowroot_style.html]
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1017896
|
||||
-->
|
||||
<head>
|
||||
<title>Test template element in stale document.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1017896">Bug 1017896</a>
|
||||
<div id="container"></div>
|
||||
<script>
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var frame = document.createElement("iframe");
|
||||
document.getElementById("container").appendChild(frame);
|
||||
|
||||
var staleFrameDoc = frame.contentDocument;
|
||||
|
||||
setTimeout(function() {
|
||||
var v = staleFrameDoc.createElement("div");
|
||||
v.innerHTML = "<template>Content</template>";
|
||||
is(v.firstChild.content.childNodes.length, 1, "Template should have one child in template content.");
|
||||
SimpleTest.finish();
|
||||
}, 0);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче