зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland
This commit is contained in:
Коммит
c3e7ae1ce7
|
@ -982,7 +982,7 @@ static const nsRoleMapEntry sWAIRoleMaps[] =
|
|||
&nsGkAtoms::separator_,
|
||||
roles::SEPARATOR,
|
||||
kUseMapRole,
|
||||
eNoValue,
|
||||
eHasValueMinMaxIfFocusable,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kGenericAccType,
|
||||
|
|
|
@ -34,7 +34,15 @@ enum EValueRule
|
|||
* Value interface is implemented, supports value, min and max from
|
||||
* aria-valuenow, aria-valuemin and aria-valuemax.
|
||||
*/
|
||||
eHasValueMinMax
|
||||
eHasValueMinMax,
|
||||
|
||||
/**
|
||||
* Value interface is implemented, but only if the element is focusable.
|
||||
* For instance, in ARIA 1.1 the ability for authors to create adjustable
|
||||
* splitters was provided by supporting the value interface on separators
|
||||
* that are focusable. Non-focusable separators expose no value information.
|
||||
*/
|
||||
eHasValueMinMaxIfFocusable
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -95,7 +95,13 @@ Accessible::HasNumericValue() const
|
|||
return true;
|
||||
|
||||
const nsRoleMapEntry* roleMapEntry = ARIARoleMap();
|
||||
return roleMapEntry && roleMapEntry->valueRule != eNoValue;
|
||||
if (!roleMapEntry || roleMapEntry->valueRule == eNoValue)
|
||||
return false;
|
||||
|
||||
if (roleMapEntry->valueRule == eHasValueMinMaxIfFocusable)
|
||||
return InteractiveState() & states::FOCUSABLE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
|
|
|
@ -2056,8 +2056,6 @@ DocAccessible::RelocateARIAOwnedIfNeeded(nsIContent* aElement)
|
|||
void
|
||||
DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
|
||||
{
|
||||
nsTArray<RefPtr<Accessible> >* children = mARIAOwnsHash.LookupOrAdd(aOwner);
|
||||
|
||||
MOZ_ASSERT(aOwner, "aOwner must be a valid pointer");
|
||||
MOZ_ASSERT(aOwner->Elm(), "aOwner->Elm() must be a valid pointer");
|
||||
|
||||
|
@ -2065,10 +2063,13 @@ DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
|
|||
logging::TreeInfo("aria owns relocation", logging::eVerbose, aOwner);
|
||||
#endif
|
||||
|
||||
nsTArray<RefPtr<Accessible> >* owned = mARIAOwnsHash.LookupOrAdd(aOwner);
|
||||
|
||||
IDRefsIterator iter(this, aOwner->Elm(), nsGkAtoms::aria_owns);
|
||||
uint32_t arrayIdx = 0, insertIdx = aOwner->ChildCount() - children->Length();
|
||||
uint32_t idx = 0;
|
||||
while (nsIContent* childEl = iter.NextElem()) {
|
||||
Accessible* child = GetAccessible(childEl);
|
||||
auto insertIdx = aOwner->ChildCount() - owned->Length() + idx;
|
||||
|
||||
// Make an attempt to create an accessible if it wasn't created yet.
|
||||
if (!child) {
|
||||
|
@ -2081,15 +2082,13 @@ DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
|
|||
imut.Done();
|
||||
|
||||
child->SetRelocated(true);
|
||||
children->InsertElementAt(arrayIdx, child);
|
||||
owned->InsertElementAt(idx, child);
|
||||
idx++;
|
||||
|
||||
// Create subtree before adjusting the insertion index, since subtree
|
||||
// creation may alter children in the container.
|
||||
CreateSubtree(child);
|
||||
FireEventsOnInsertion(aOwner);
|
||||
|
||||
insertIdx = child->IndexInParent() + 1;
|
||||
arrayIdx++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
@ -2103,15 +2102,14 @@ DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
|
|||
// Same child on same position, no change.
|
||||
if (child->Parent() == aOwner &&
|
||||
child->IndexInParent() == static_cast<int32_t>(insertIdx)) {
|
||||
MOZ_ASSERT(child == children->ElementAt(arrayIdx), "Not in sync!");
|
||||
insertIdx++; arrayIdx++;
|
||||
MOZ_ASSERT(owned->ElementAt(idx) == child, "Not in sync!");
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(children->SafeElementAt(arrayIdx) != child, "Already in place!");
|
||||
MOZ_ASSERT(owned->SafeElementAt(idx) != child, "Already in place!");
|
||||
|
||||
nsTArray<RefPtr<Accessible> >::index_type idx = children->IndexOf(child);
|
||||
if (idx < arrayIdx) {
|
||||
if (owned->IndexOf(child) < idx) {
|
||||
continue; // ignore second entry of same ID
|
||||
}
|
||||
|
||||
|
@ -2129,15 +2127,14 @@ DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
|
|||
|
||||
if (MoveChild(child, aOwner, insertIdx)) {
|
||||
child->SetRelocated(true);
|
||||
children->InsertElementAt(arrayIdx, child);
|
||||
arrayIdx++;
|
||||
insertIdx = child->IndexInParent() + 1;
|
||||
owned->InsertElementAt(idx, child);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
// Put back children that are not seized anymore.
|
||||
PutChildrenBack(children, arrayIdx);
|
||||
if (children->Length() == 0) {
|
||||
PutChildrenBack(owned, idx);
|
||||
if (owned->Length() == 0) {
|
||||
mARIAOwnsHash.Remove(aOwner);
|
||||
}
|
||||
}
|
||||
|
@ -2146,6 +2143,8 @@ void
|
|||
DocAccessible::PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
|
||||
uint32_t aStartIdx)
|
||||
{
|
||||
MOZ_ASSERT(aStartIdx <= aChildren->Length(), "Wrong removal index");
|
||||
|
||||
nsTArray<RefPtr<Accessible> > containers;
|
||||
for (auto idx = aStartIdx; idx < aChildren->Length(); idx++) {
|
||||
Accessible* child = aChildren->ElementAt(idx);
|
||||
|
@ -2196,6 +2195,8 @@ DocAccessible::MoveChild(Accessible* aChild, Accessible* aNewParent,
|
|||
{
|
||||
MOZ_ASSERT(aChild, "No child");
|
||||
MOZ_ASSERT(aChild->Parent(), "No parent");
|
||||
MOZ_ASSERT(aIdxInParent <= static_cast<int32_t>(aNewParent->ChildCount()),
|
||||
"Wrong insertion point for a moving child");
|
||||
|
||||
Accessible* curParent = aChild->Parent();
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="Mozilla.Firefox.xul" version="1.0.0.0" />
|
||||
<file name="xul.dll" />
|
||||
<comInterfaceExternalProxyStub
|
||||
iid="{618736E0-3C3D-11CF-810C-00AA00389B71}"
|
||||
proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
|
||||
name="IAccessible"
|
||||
tlbid="{1EA4DBF0-3C3B-11CF-810C-00AA00389B71}"
|
||||
/>
|
||||
</assembly>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="Mozilla.Firefox.xul" version="1.0.0.0" />
|
||||
<file name="xul.dll" />
|
||||
<comInterfaceExternalProxyStub
|
||||
iid="{618736E0-3C3D-11CF-810C-00AA00389B71}"
|
||||
proxyStubClsid32="{03022430-ABC4-11D0-BDE2-00AA001A1953}"
|
||||
name="IAccessible"
|
||||
/>
|
||||
</assembly>
|
|
@ -7,6 +7,7 @@
|
|||
#include "mozilla/a11y/PlatformChild.h"
|
||||
#include "mozilla/mscom/EnsureMTA.h"
|
||||
#include "mozilla/mscom/InterceptorLog.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
||||
#include "Accessible2.h"
|
||||
#include "Accessible2_2.h"
|
||||
|
@ -48,6 +49,27 @@ PlatformChild::PlatformChild()
|
|||
, mMiscTypelib(mozilla::mscom::RegisterTypelib(L"Accessible.tlb"))
|
||||
, mSdnTypelib(mozilla::mscom::RegisterTypelib(L"AccessibleMarshal.dll"))
|
||||
{
|
||||
// The manifest for 32-bit Windows is embedded with resource ID 32.
|
||||
// The manifest for 64-bit Windows is embedded with resource ID 64.
|
||||
// Beginning with Windows 10 Creators Update, 32-bit builds use the 64-bit
|
||||
// manifest.
|
||||
WORD actCtxResourceId;
|
||||
#if defined(HAVE_64BIT_BUILD)
|
||||
actCtxResourceId = 64;
|
||||
#else
|
||||
if (IsWin10CreatorsUpdateOrLater()) {
|
||||
actCtxResourceId = 64;
|
||||
} else {
|
||||
actCtxResourceId = 32;
|
||||
}
|
||||
#endif
|
||||
|
||||
mozilla::mscom::MTADeletePtr<mozilla::mscom::ActivationContextRegion> tmpActCtxMTA;
|
||||
mozilla::mscom::EnsureMTA([actCtxResourceId, &tmpActCtxMTA]() -> void {
|
||||
tmpActCtxMTA.reset(new mozilla::mscom::ActivationContextRegion(actCtxResourceId));
|
||||
});
|
||||
mActCtxMTA = Move(tmpActCtxMTA);
|
||||
|
||||
mozilla::mscom::InterceptorLog::Init();
|
||||
mozilla::mscom::RegisterArrayData(sPlatformChildArrayData);
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#ifndef mozilla_a11y_PlatformChild_h
|
||||
#define mozilla_a11y_PlatformChild_h
|
||||
|
||||
#include "mozilla/mscom/ActivationContext.h"
|
||||
#include "mozilla/mscom/Ptr.h"
|
||||
#include "mozilla/mscom/Registration.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -23,6 +25,7 @@ public:
|
|||
PlatformChild& operator=(PlatformChild&&) = delete;
|
||||
|
||||
private:
|
||||
mscom::MTADeletePtr<mozilla::mscom::ActivationContextRegion> mActCtxMTA;
|
||||
UniquePtr<mozilla::mscom::RegisteredProxy> mCustomProxy;
|
||||
UniquePtr<mozilla::mscom::RegisteredProxy> mIA2Proxy;
|
||||
UniquePtr<mozilla::mscom::RegisteredProxy> mAccTypelib;
|
||||
|
|
|
@ -13,9 +13,21 @@ if CONFIG['COMPILE_ENVIRONMENT'] and CONFIG['ACCESSIBILITY']:
|
|||
# With --disable-accessibility, we need to compile PDocAccessible.ipdl (which
|
||||
# also depends on COMPtrTypes.h), but not the C++.
|
||||
IPDL_SOURCES += ['PDocAccessible.ipdl']
|
||||
EXPORTS.mozilla.a11y += ['COMPtrTypes.h']
|
||||
|
||||
EXPORTS.mozilla.a11y += [
|
||||
'COMPtrTypes.h',
|
||||
]
|
||||
|
||||
if CONFIG['ACCESSIBILITY']:
|
||||
if not CONFIG['HAVE_64BIT_BUILD']:
|
||||
EXPORTS += [
|
||||
'IAccessible32.manifest',
|
||||
]
|
||||
|
||||
EXPORTS += [
|
||||
'IAccessible64.manifest',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.a11y += [
|
||||
'DocAccessibleChild.h',
|
||||
'HandlerProvider.h',
|
||||
|
|
|
@ -161,9 +161,14 @@
|
|||
testValue("slider_vnvt", "plain", 0, 0, 5, 0);
|
||||
testValue("slider_vt", "hi", 0, 0, 3, 0);
|
||||
testValue("scrollbar", "5", 5, 0, 1000, 0);
|
||||
testValue("splitter", "5", 5, 0, 1000, 0);
|
||||
testValue("progress", "22%", 22, 0, 100, 0);
|
||||
testValue("range", "6", 6, 0, 10, 1);
|
||||
|
||||
// Test that elements which should not expose values do not
|
||||
var accSeparator = getAccessible("separator", [nsIAccessibleValue], null, DONOTFAIL_IF_NO_INTERFACE);
|
||||
ok(!accSeparator, "value interface is not exposed for separator");
|
||||
|
||||
// Test value change events
|
||||
gQueue = new eventQueue();
|
||||
|
||||
|
@ -171,6 +176,7 @@
|
|||
gQueue.push(new changeARIAValue("slider_vt", undefined, "hey!"));
|
||||
gQueue.push(new changeARIAValue("slider_vnvt", "3", "sweet"));
|
||||
gQueue.push(new changeARIAValue("scrollbar", "6", undefined));
|
||||
gQueue.push(new changeARIAValue("splitter", "6", undefined));
|
||||
|
||||
gQueue.push(new changeValue("combobox", "hello"));
|
||||
|
||||
|
@ -237,6 +243,14 @@
|
|||
<div id="scrollbar" role="scrollbar" aria-valuenow="5"
|
||||
aria-valuemin="0" aria-valuemax="1000">slider</div>
|
||||
|
||||
<!-- ARIA separator which is focusable (i.e. a splitter) -->
|
||||
<div id="splitter" role="separator" tabindex="0" aria-valuenow="5"
|
||||
aria-valuemin="0" aria-valuemax="1000">splitter</div>
|
||||
|
||||
<!-- ARIA separator which is not focusable and should not expose values -->
|
||||
<div id="separator" role="separator" aria-valuenow="5"
|
||||
aria-valuemin="0" aria-valuemax="1000">splitter</div>
|
||||
|
||||
<!-- ARIA combobox -->
|
||||
<input id="combobox" role="combobox" aria-autocomplete="inline">
|
||||
|
||||
|
|
|
@ -14,10 +14,12 @@
|
|||
#include "nsIXULRuntime.h"
|
||||
#include "nsWinUtils.h"
|
||||
#include "mozilla/a11y/ProxyAccessible.h"
|
||||
#include "mozilla/mscom/ActivationContext.h"
|
||||
#include "mozilla/mscom/InterceptorLog.h"
|
||||
#include "mozilla/mscom/Registration.h"
|
||||
#include "mozilla/mscom/Utils.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "ProxyWrappers.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -28,7 +30,6 @@ static StaticAutoPtr<RegisteredProxy> gRegCustomProxy;
|
|||
static StaticAutoPtr<RegisteredProxy> gRegProxy;
|
||||
static StaticAutoPtr<RegisteredProxy> gRegAccTlb;
|
||||
static StaticAutoPtr<RegisteredProxy> gRegMiscTlb;
|
||||
|
||||
void
|
||||
a11y::PlatformInit()
|
||||
{
|
||||
|
|
|
@ -314,18 +314,6 @@ pref("browser.urlbar.maxRichResults", 10);
|
|||
// autocomplete.xml.
|
||||
pref("browser.urlbar.delay", 50);
|
||||
|
||||
// The special characters below can be typed into the urlbar to either restrict
|
||||
// the search to visited history, bookmarked, tagged pages; or force a match on
|
||||
// just the title text or url.
|
||||
pref("browser.urlbar.restrict.history", "^");
|
||||
pref("browser.urlbar.restrict.bookmark", "*");
|
||||
pref("browser.urlbar.restrict.tag", "+");
|
||||
pref("browser.urlbar.restrict.openpage", "%");
|
||||
pref("browser.urlbar.restrict.typed", "~");
|
||||
pref("browser.urlbar.restrict.searches", "$");
|
||||
pref("browser.urlbar.match.title", "#");
|
||||
pref("browser.urlbar.match.url", "@");
|
||||
|
||||
// The default behavior for the urlbar can be configured to use any combination
|
||||
// of the match filters with each additional filter adding more results (union).
|
||||
pref("browser.urlbar.suggest.history", true);
|
||||
|
@ -691,7 +679,7 @@ pref("plugins.click_to_play", true);
|
|||
pref("plugins.testmode", false);
|
||||
|
||||
// Should plugins that are hidden show the infobar UI?
|
||||
pref("plugins.show_infobar", true);
|
||||
pref("plugins.show_infobar", false);
|
||||
|
||||
// Should dismissing the hidden plugin infobar suppress it permanently?
|
||||
pref("plugins.remember_infobar_dismissal", true);
|
||||
|
|
|
@ -3,26 +3,27 @@ const gTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.
|
|||
var gTestBrowser = null;
|
||||
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({ set: [
|
||||
["plugins.show_infobar", true],
|
||||
["plugins.click_to_play", true],
|
||||
["extensions.blocklist.supressUI", true],
|
||||
]});
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
clearAllPluginPermissions();
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
|
||||
Services.prefs.clearUserPref("plugins.click_to_play");
|
||||
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
|
||||
gBrowser.removeCurrentTab();
|
||||
window.focus();
|
||||
gTestBrowser = null;
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
||||
|
||||
let newTab = BrowserTestUtils.addTab(gBrowser);
|
||||
gBrowser.selectedTab = newTab;
|
||||
gTestBrowser = gBrowser.selectedBrowser;
|
||||
});
|
||||
|
||||
add_task(async function() {
|
||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
|
||||
|
||||
await promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_small.html");
|
||||
|
|
|
@ -3,18 +3,19 @@ const gHttpTestRoot = gTestRoot.replace("chrome://mochitests/content/",
|
|||
"http://127.0.0.1:8888/");
|
||||
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({ set: [
|
||||
["plugins.click_to_play", true],
|
||||
["extensions.blocklist.suppressUI", true],
|
||||
["plugins.show_infobar", true],
|
||||
]});
|
||||
registerCleanupFunction(function() {
|
||||
clearAllPluginPermissions();
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Second Test Plug-in");
|
||||
Services.prefs.clearUserPref("plugins.click_to_play");
|
||||
Services.prefs.clearUserPref("extensions.blocklist.suppressUI");
|
||||
gBrowser.removeCurrentTab();
|
||||
window.focus();
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref("plugins.click_to_play", true);
|
||||
Services.prefs.setBoolPref("extensions.blocklist.suppressUI", true);
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Test Plug-in");
|
||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY, "Second Test Plug-in");
|
||||
});
|
||||
|
|
|
@ -21,8 +21,11 @@ add_task(async function setup() {
|
|||
|
||||
// And then make the plugin hidden.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [[HIDDEN_CTP_PLUGIN_PREF, TEST_PLUGIN_NAME]],
|
||||
})
|
||||
set: [
|
||||
[HIDDEN_CTP_PLUGIN_PREF, TEST_PLUGIN_NAME],
|
||||
["plugins.show_infobar", true],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,8 @@ const TEST_URL_BASES = [
|
|||
"http://example.org/browser/browser/base/content/test/urlbar/moz.png#tabmatch"
|
||||
];
|
||||
|
||||
const RESTRICT_TOKEN_OPENPAGE = "%";
|
||||
|
||||
var gController = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
|
@ -209,5 +211,5 @@ function checkAutocompleteResults(aExpected, aCallback) {
|
|||
};
|
||||
|
||||
info("Searching open pages.");
|
||||
gController.startSearch(Services.prefs.getCharPref("browser.urlbar.restrict.openpage"));
|
||||
gController.startSearch(RESTRICT_TOKEN_OPENPAGE);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,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/. */
|
||||
|
||||
const RESTRICT_TOKEN_OPENPAGE = "%";
|
||||
|
||||
var stateBackup = ss.getBrowserState();
|
||||
|
||||
function cleanup() {
|
||||
|
@ -116,5 +118,5 @@ function checkAutocompleteResults(aExpected, aCallback) {
|
|||
};
|
||||
|
||||
info("Searching open pages.");
|
||||
gController.startSearch(Services.prefs.getCharPref("browser.urlbar.restrict.openpage"));
|
||||
gController.startSearch(RESTRICT_TOKEN_OPENPAGE);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,9 @@
|
|||
--tab-selection-color: #f5f7fa;
|
||||
--tab-selection-background-color: #5675B9;
|
||||
--tab-selection-box-shadow: none;
|
||||
%ifndef MOZ_PHOTON_THEME
|
||||
--pinned-tab-glow: radial-gradient(22px at center calc(100% - 2px), rgba(76,158,217,0.9) 13%, rgba(0,0,0,0.4) 16%, transparent 70%);
|
||||
%endif
|
||||
|
||||
/* Url and search bars */
|
||||
--url-and-searchbar-background-color: #171B1F;
|
||||
|
@ -84,7 +86,9 @@ toolbar:-moz-lwtheme-brighttext {
|
|||
--tab-selection-color: #f5f7fa;
|
||||
--tab-selection-background-color: #4c9ed9;
|
||||
--tab-selection-box-shadow: none;
|
||||
%ifndef MOZ_PHOTON_THEME
|
||||
--pinned-tab-glow: radial-gradient(22px at center calc(100% - 2px), rgba(76,158,217,0.9) 13%, transparent 16%);
|
||||
%endif
|
||||
}
|
||||
|
||||
%ifndef MOZ_PHOTON_THEME
|
||||
|
@ -324,9 +328,13 @@ window:not([chromehidden~="toolbar"]) #urlbar-wrapper > #urlbar:-moz-locale-dir(
|
|||
|
||||
.tabbrowser-tab:-moz-any([image], [pinned]) > .tab-stack > .tab-content[attention]:not([selected="true"]),
|
||||
.tabbrowser-tab > .tab-stack > .tab-content[pinned][titlechanged]:not([selected="true"]) {
|
||||
%ifdef MOZ_PHOTON_THEME
|
||||
background-position: center bottom -4px;
|
||||
%else
|
||||
background-image: var(--pinned-tab-glow);
|
||||
background-position: center;
|
||||
background-size: 100%;
|
||||
%endif
|
||||
}
|
||||
|
||||
.tabbrowser-tab[image] > .tab-stack > .tab-content[attention]:not([pinned]):not([selected="true"]) {
|
||||
|
|
|
@ -187,6 +187,7 @@
|
|||
skin/classic/browser/tabbrowser/connecting.png (../shared/tabbrowser/connecting.png)
|
||||
skin/classic/browser/tabbrowser/connecting@2x.png (../shared/tabbrowser/connecting@2x.png)
|
||||
skin/classic/browser/tabbrowser/crashed.svg (../shared/tabbrowser/crashed.svg)
|
||||
skin/classic/browser/tabbrowser/indicator-tab-attention.svg (../shared/tabbrowser/indicator-tab-attention.svg)
|
||||
skin/classic/browser/tabbrowser/pendingpaint.png (../shared/tabbrowser/pendingpaint.png)
|
||||
skin/classic/browser/tabbrowser/tab-audio-playing.svg (../shared/tabbrowser/tab-audio-playing.svg)
|
||||
skin/classic/browser/tabbrowser/tab-audio-muted.svg (../shared/tabbrowser/tab-audio-muted.svg)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
|
||||
<circle r="6" cy="6" cx="6" fill-opacity=".2" fill="#00C8D7" />
|
||||
<circle r="4" cy="6" cx="6" fill-opacity=".6" fill="#00C8D7" />
|
||||
<circle r="2" cy="6" cx="6" fill="#00FEFF" />
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 271 B |
|
@ -471,10 +471,15 @@
|
|||
|
||||
.tabbrowser-tab:-moz-any([image], [pinned]) > .tab-stack > .tab-content[attention]:not([selected="true"]),
|
||||
.tabbrowser-tab > .tab-stack > .tab-content[pinned][titlechanged]:not([selected="true"]) {
|
||||
%ifdef MOZ_PHOTON_THEME
|
||||
background-image: url(chrome://browser/skin/tabbrowser/indicator-tab-attention.svg);
|
||||
background-position: center bottom -3px;
|
||||
%else
|
||||
background-image: radial-gradient(farthest-corner at center bottom, rgb(255,255,255) 3%, rgba(186,221,251,0.75) 20%, rgba(127,179,255,0.25) 40%, transparent 70%);
|
||||
background-position: center bottom var(--tab-toolbar-navbar-overlap);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 85% 100%;
|
||||
%endif
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.tabbrowser-tab[image] > .tab-stack > .tab-content[attention]:not([pinned]):not([selected="true"]) {
|
||||
|
|
|
@ -31,8 +31,9 @@ from mozversioncontrol import get_repository_from_env
|
|||
|
||||
|
||||
architecture_independent = set([ 'generic' ])
|
||||
all_architecture_names = set([ 'x86', 'x64', 'arm', 'arm64', 'mips32', 'mips64' ])
|
||||
all_shared_architecture_names = set([ 'x86_shared', 'mips_shared', 'arm', 'arm64' ])
|
||||
all_unsupported_architectures_names = set([ 'mips32', 'mips64', 'mips_shared' ])
|
||||
all_architecture_names = set([ 'x86', 'x64', 'arm', 'arm64' ])
|
||||
all_shared_architecture_names = set([ 'x86_shared', 'arm', 'arm64' ])
|
||||
|
||||
reBeforeArg = "(?<=[(,\s])"
|
||||
reArgType = "(?P<type>[\w\s:*&]+)"
|
||||
|
@ -97,6 +98,7 @@ def get_normalized_signatures(signature, fileAnnot = None):
|
|||
file_suffixes = set([
|
||||
a.replace('_', '-') for a in
|
||||
all_architecture_names.union(all_shared_architecture_names)
|
||||
.union(all_unsupported_architectures_names)
|
||||
])
|
||||
def get_file_annotation(filename):
|
||||
origFilename = filename
|
||||
|
@ -210,6 +212,7 @@ def generate_file_content(signatures):
|
|||
output = []
|
||||
for s in sorted(signatures.keys()):
|
||||
archs = set(sorted(signatures[s]))
|
||||
archs -= all_unsupported_architectures_names
|
||||
if len(archs.symmetric_difference(architecture_independent)) == 0:
|
||||
output.append(s + ';\n')
|
||||
if s.startswith('inline'):
|
||||
|
@ -222,8 +225,8 @@ def generate_file_content(signatures):
|
|||
elif len(archs.symmetric_difference(all_shared_architecture_names)) == 0:
|
||||
output.append(s + ' PER_SHARED_ARCH;\n')
|
||||
else:
|
||||
output.append(s + ' DEFINED_ON(' + ', '.join(archs) + ');\n')
|
||||
for a in archs:
|
||||
output.append(s + ' DEFINED_ON(' + ', '.join(sorted(archs)) + ');\n')
|
||||
for a in sorted(archs):
|
||||
a = a.replace('_', '-')
|
||||
masm = '%s/MacroAssembler-%s' % (a, a)
|
||||
if s.startswith('inline'):
|
||||
|
|
|
@ -891,7 +891,7 @@ ifdef MOZ_MSVCBITS
|
|||
# to use the 64-bit linker for build.rs scripts. This conflict results
|
||||
# in a build failure (see bug 1350001). So we clear out the environment
|
||||
# variables that are actually relevant to 32- vs 64-bit builds.
|
||||
environment_cleaner = PATH='' LIB='' LIBPATH=''
|
||||
environment_cleaner = -u VCINSTALLDIR PATH='' LIB='' LIBPATH=''
|
||||
# The servo build needs to know where python is, and we're removing the PATH
|
||||
# so we tell it explicitly via the PYTHON env var.
|
||||
environment_cleaner += PYTHON='$(shell which $(PYTHON))'
|
||||
|
|
|
@ -44,3 +44,4 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
|
|||
subsuite = clipboard
|
||||
skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
|
||||
[browser_computed_style-editor-link.js]
|
||||
skip-if = os == 'mac' # bug 1307846
|
||||
|
|
|
@ -640,6 +640,11 @@ netmonitor.toolbar.resetColumns=Reset Columns
|
|||
# displayed in the network table header context menu for the timing submenu
|
||||
netmonitor.toolbar.timings=Timings
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.toolbar.responseHeaders): This is the
|
||||
# label displayed in the network table header context menu for the
|
||||
# response headers submenu.
|
||||
netmonitor.toolbar.responseHeaders=Response Headers
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.summary.url): This is the label displayed
|
||||
# in the network details headers tab identifying the URL.
|
||||
netmonitor.summary.url=Request URL:
|
||||
|
|
|
@ -23,9 +23,9 @@ EventEmitter.decorate(window);
|
|||
|
||||
pref("devtools.netmonitor.enabled", true);
|
||||
pref("devtools.netmonitor.filters", "[\"all\"]");
|
||||
pref("devtools.netmonitor.hiddenColumns",
|
||||
"[\"cookies\",\"duration\",\"endTime\",\"latency\"," +
|
||||
"\"protocol\",\"remoteip\",\"responseTime\",\"scheme\",\"setCookies\",\"startTime\"]"
|
||||
pref("devtools.netmonitor.visibleColumns",
|
||||
"[\"status\",\"method\",\"file\",\"domain\",\"cause\"," +
|
||||
"\"type\",\"transferred\",\"contentSize\",\"waterfall\"]"
|
||||
);
|
||||
pref("devtools.netmonitor.panes-network-details-width", 550);
|
||||
pref("devtools.netmonitor.panes-network-details-height", 450);
|
||||
|
|
|
@ -489,6 +489,9 @@ body,
|
|||
width: 8%;
|
||||
}
|
||||
|
||||
.requests-list-response-header {
|
||||
width: 13%;
|
||||
}
|
||||
|
||||
.requests-list-domain.requests-list-column {
|
||||
text-align: start;
|
||||
|
|
|
@ -23,6 +23,7 @@ DevToolsModules(
|
|||
'request-list-column-method.js',
|
||||
'request-list-column-protocol.js',
|
||||
'request-list-column-remote-ip.js',
|
||||
'request-list-column-response-header.js',
|
||||
'request-list-column-response-time.js',
|
||||
'request-list-column-scheme.js',
|
||||
'request-list-column-set-cookies.js',
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
createClass,
|
||||
DOM,
|
||||
PropTypes,
|
||||
} = require("devtools/client/shared/vendor/react");
|
||||
const { getResponseHeader } = require("../utils/request-utils");
|
||||
|
||||
const { div } = DOM;
|
||||
|
||||
/**
|
||||
* Renders a response header column in the requests list. The actual
|
||||
* header to show is passed as a prop.
|
||||
*/
|
||||
const RequestListColumnResponseHeader = createClass({
|
||||
displayName: "RequestListColumnResponseHeader",
|
||||
|
||||
propTypes: {
|
||||
item: PropTypes.object.isRequired,
|
||||
header: PropTypes.string.isRequired,
|
||||
},
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
const currHeader = getResponseHeader(this.props.item, this.props.header);
|
||||
const nextHeader = getResponseHeader(nextProps.item, nextProps.header);
|
||||
return currHeader !== nextHeader;
|
||||
},
|
||||
|
||||
render() {
|
||||
let header = getResponseHeader(this.props.item, this.props.header);
|
||||
return (
|
||||
div({
|
||||
className: "requests-list-column requests-list-response-header",
|
||||
title: header
|
||||
},
|
||||
header
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = RequestListColumnResponseHeader;
|
|
@ -89,7 +89,8 @@ const RequestListHeader = createClass({
|
|||
HEADERS.filter((header) => columns.get(header.name)).map((header) => {
|
||||
let name = header.name;
|
||||
let boxName = header.boxName || name;
|
||||
let label = L10N.getStr(`netmonitor.toolbar.${header.label || name}`);
|
||||
let label = header.noLocalization
|
||||
? name : L10N.getStr(`netmonitor.toolbar.${header.label || name}`);
|
||||
let sorted, sortedTitle;
|
||||
let active = sort.type == name ? true : undefined;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ const {
|
|||
} = require("devtools/client/shared/vendor/react");
|
||||
const I = require("devtools/client/shared/vendor/immutable");
|
||||
const { propertiesEqual } = require("../utils/request-utils");
|
||||
const { RESPONSE_HEADERS } = require("../constants");
|
||||
|
||||
// Components
|
||||
const RequestListColumnCause = createFactory(require("./request-list-column-cause"));
|
||||
|
@ -25,6 +26,7 @@ const RequestListColumnLatency = createFactory(require("./request-list-column-la
|
|||
const RequestListColumnMethod = createFactory(require("./request-list-column-method"));
|
||||
const RequestListColumnProtocol = createFactory(require("./request-list-column-protocol"));
|
||||
const RequestListColumnRemoteIP = createFactory(require("./request-list-column-remote-ip"));
|
||||
const RequestListColumnResponseHeader = createFactory(require("./request-list-column-response-header"));
|
||||
const RequestListColumnResponseTime = createFactory(require("./request-list-column-response-time"));
|
||||
const RequestListColumnScheme = createFactory(require("./request-list-column-scheme"));
|
||||
const RequestListColumnSetCookies = createFactory(require("./request-list-column-set-cookies"));
|
||||
|
@ -163,6 +165,9 @@ const RequestListItem = createClass({
|
|||
RequestListColumnResponseTime({ item, firstRequestStartedMillis }),
|
||||
columns.get("duration") && RequestListColumnDuration({ item }),
|
||||
columns.get("latency") && RequestListColumnLatency({ item }),
|
||||
...RESPONSE_HEADERS.filter(header => columns.get(header)).map(
|
||||
header => RequestListColumnResponseHeader({ item, header }),
|
||||
),
|
||||
columns.get("waterfall") &&
|
||||
RequestListColumnWaterfall({ item, firstRequestStartedMillis,
|
||||
onWaterfallMouseDown }),
|
||||
|
|
|
@ -93,6 +93,18 @@ const EVENTS = {
|
|||
CONNECTED: "connected",
|
||||
};
|
||||
|
||||
const RESPONSE_HEADERS = [
|
||||
"Cache-Control",
|
||||
"Connection",
|
||||
"Content-Encoding",
|
||||
"Content-Length",
|
||||
"ETag",
|
||||
"Keep-Alive",
|
||||
"Last-Modified",
|
||||
"Server",
|
||||
"Vary"
|
||||
];
|
||||
|
||||
const HEADERS = [
|
||||
{
|
||||
name: "status",
|
||||
|
@ -180,6 +192,13 @@ const HEADERS = [
|
|||
canFilter: false,
|
||||
subMenu: "timings",
|
||||
},
|
||||
...RESPONSE_HEADERS
|
||||
.map(header => ({
|
||||
name: header,
|
||||
canFilter: false,
|
||||
subMenu: "responseHeaders",
|
||||
noLocalization: true
|
||||
})),
|
||||
{
|
||||
name: "waterfall",
|
||||
canFilter: false,
|
||||
|
@ -225,6 +244,7 @@ const general = {
|
|||
EVENTS,
|
||||
FILTER_SEARCH_DELAY: 200,
|
||||
HEADERS,
|
||||
RESPONSE_HEADERS,
|
||||
FILTER_FLAGS,
|
||||
SOURCE_EDITOR_SYNTAX_HIGHLIGHT_MAX_SIZE: 51200, // 50 KB in bytes
|
||||
REQUESTS_WATERFALL,
|
||||
|
|
|
@ -32,11 +32,11 @@ function prefsMiddleware(store) {
|
|||
break;
|
||||
case TOGGLE_COLUMN:
|
||||
case RESET_COLUMNS:
|
||||
let hiddenColumns = [...store.getState().ui.columns]
|
||||
.filter(([column, shown]) => !shown)
|
||||
let visibleColumns = [...store.getState().ui.columns]
|
||||
.filter(([column, shown]) => shown)
|
||||
.map(([column, shown]) => column);
|
||||
Services.prefs.setCharPref(
|
||||
"devtools.netmonitor.hiddenColumns", JSON.stringify(hiddenColumns));
|
||||
"devtools.netmonitor.visibleColumns", JSON.stringify(visibleColumns));
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
|
|
|
@ -11,6 +11,7 @@ const {
|
|||
OPEN_STATISTICS,
|
||||
REMOVE_SELECTED_CUSTOM_REQUEST,
|
||||
RESET_COLUMNS,
|
||||
RESPONSE_HEADERS,
|
||||
SELECT_DETAILS_PANEL_TAB,
|
||||
SEND_CUSTOM_REQUEST,
|
||||
SELECT_REQUEST,
|
||||
|
@ -18,7 +19,7 @@ const {
|
|||
WATERFALL_RESIZE,
|
||||
} = require("../constants");
|
||||
|
||||
const Columns = I.Record({
|
||||
const cols = {
|
||||
status: true,
|
||||
method: true,
|
||||
file: true,
|
||||
|
@ -38,7 +39,13 @@ const Columns = I.Record({
|
|||
duration: false,
|
||||
latency: false,
|
||||
waterfall: true,
|
||||
});
|
||||
};
|
||||
const Columns = I.Record(
|
||||
Object.assign(
|
||||
cols,
|
||||
RESPONSE_HEADERS.reduce((acc, header) => Object.assign(acc, { [header]: false }), {})
|
||||
)
|
||||
);
|
||||
|
||||
const UI = I.Record({
|
||||
columns: new Columns(),
|
||||
|
|
|
@ -16,6 +16,10 @@ const subMenuMap = HEADERS
|
|||
.filter((header) => header.hasOwnProperty("subMenu"))
|
||||
.reduce((acc, { name, subMenu }) => Object.assign(acc, { [name]: subMenu }), {});
|
||||
|
||||
const nonLocalizedHeaders = HEADERS
|
||||
.filter((header) => header.hasOwnProperty("noLocalization"))
|
||||
.map((header) => header.name);
|
||||
|
||||
class RequestListHeaderContextMenu {
|
||||
constructor({ toggleColumn, resetColumns }) {
|
||||
this.toggleColumn = toggleColumn;
|
||||
|
@ -37,13 +41,16 @@ class RequestListHeaderContextMenu {
|
|||
*/
|
||||
open(event = {}) {
|
||||
let menu = [];
|
||||
let subMenu = { timings: [] };
|
||||
let subMenu = { timings: [], responseHeaders: [] };
|
||||
let onlyOneColumn = this.visibleColumns.length === 1;
|
||||
|
||||
for (let [column, shown] of this.columns) {
|
||||
let label = nonLocalizedHeaders.includes(column)
|
||||
? stringMap[column] || column
|
||||
: L10N.getStr(`netmonitor.toolbar.${stringMap[column] || column}`);
|
||||
let entry = {
|
||||
id: `request-list-header-${column}-toggle`,
|
||||
label: L10N.getStr(`netmonitor.toolbar.${stringMap[column] || column}`),
|
||||
label,
|
||||
type: "checkbox",
|
||||
checked: shown,
|
||||
click: () => this.toggleColumn(column),
|
||||
|
@ -60,6 +67,10 @@ class RequestListHeaderContextMenu {
|
|||
label: L10N.getStr("netmonitor.toolbar.timings"),
|
||||
submenu: subMenu.timings,
|
||||
});
|
||||
menu.push({
|
||||
label: L10N.getStr("netmonitor.toolbar.responseHeaders"),
|
||||
submenu: subMenu.responseHeaders,
|
||||
});
|
||||
|
||||
menu.push({ type: "separator" });
|
||||
menu.push({
|
||||
|
|
|
@ -32,11 +32,11 @@ function configureStore() {
|
|||
});
|
||||
|
||||
let columns = new Columns();
|
||||
let hiddenColumns = getPref("devtools.netmonitor.hiddenColumns");
|
||||
let visibleColumns = getPref("devtools.netmonitor.visibleColumns");
|
||||
|
||||
for (let [col] of columns) {
|
||||
columns = columns.withMutations((state) => {
|
||||
state.set(col, !hiddenColumns.includes(col));
|
||||
state.set(col, visibleColumns.includes(col));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,6 @@ const { PrefsHelper } = require("devtools/client/shared/prefs");
|
|||
exports.Prefs = new PrefsHelper("devtools.netmonitor", {
|
||||
networkDetailsWidth: ["Int", "panes-network-details-width"],
|
||||
networkDetailsHeight: ["Int", "panes-network-details-height"],
|
||||
hiddenColumns: ["Json", "hiddenColumns"],
|
||||
visibleColumns: ["Json", "visibleColumns"],
|
||||
filters: ["Json", "filters"]
|
||||
});
|
||||
|
|
|
@ -356,6 +356,24 @@ function getFormattedProtocol(item) {
|
|||
return protocol.join("+");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a particular response header, or null if not
|
||||
* present.
|
||||
*/
|
||||
function getResponseHeader(item, header) {
|
||||
let { responseHeaders } = item;
|
||||
if (!responseHeaders || !responseHeaders.headers.length) {
|
||||
return null;
|
||||
}
|
||||
header = header.toLowerCase();
|
||||
for (let responseHeader of responseHeaders.headers) {
|
||||
if (responseHeader.name.toLowerCase() == header) {
|
||||
return responseHeader.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getFormDataSections,
|
||||
fetchHeaders,
|
||||
|
@ -365,6 +383,7 @@ module.exports = {
|
|||
getAbbreviatedMimeType,
|
||||
getEndTime,
|
||||
getFormattedProtocol,
|
||||
getResponseHeader,
|
||||
getResponseTime,
|
||||
getStartTime,
|
||||
getUrlBaseName,
|
||||
|
|
|
@ -8,9 +8,11 @@ const {
|
|||
getAbbreviatedMimeType,
|
||||
getEndTime,
|
||||
getResponseTime,
|
||||
getResponseHeader,
|
||||
getStartTime,
|
||||
ipToLong,
|
||||
} = require("./request-utils");
|
||||
const { RESPONSE_HEADERS } = require("../constants");
|
||||
|
||||
/**
|
||||
* Predicates used when sorting items.
|
||||
|
@ -92,6 +94,16 @@ function latency(first, second) {
|
|||
return result || waterfall(first, second);
|
||||
}
|
||||
|
||||
function compareHeader(header, first, second) {
|
||||
const result = compareValues(getResponseHeader(first, header) || "",
|
||||
getResponseHeader(second, header) || "");
|
||||
return result || waterfall(first, second);
|
||||
}
|
||||
|
||||
const responseHeaders = RESPONSE_HEADERS
|
||||
.reduce((acc, header) => Object.assign(
|
||||
acc, {[header]: (first, second) => compareHeader(header, first, second)}), {});
|
||||
|
||||
function domain(first, second) {
|
||||
const firstDomain = first.urlDetails.host.toLowerCase();
|
||||
const secondDomain = second.urlDetails.host.toLowerCase();
|
||||
|
@ -150,7 +162,7 @@ function contentSize(first, second) {
|
|||
return result || waterfall(first, second);
|
||||
}
|
||||
|
||||
exports.Sorters = {
|
||||
const sorters = {
|
||||
status,
|
||||
method,
|
||||
file,
|
||||
|
@ -171,3 +183,4 @@ exports.Sorters = {
|
|||
latency,
|
||||
waterfall,
|
||||
};
|
||||
exports.Sorters = Object.assign(sorters, responseHeaders);
|
||||
|
|
|
@ -18,6 +18,9 @@ add_task(function* () {
|
|||
.filter(([_, visible]) => visible);
|
||||
|
||||
if (visibleColumns.length === 1) {
|
||||
if (!shown) {
|
||||
continue;
|
||||
}
|
||||
yield testLastMenuItem(column);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -4,38 +4,36 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests if hidden columns are properly saved
|
||||
* Tests if visible columns are properly saved
|
||||
*/
|
||||
|
||||
add_task(function* () {
|
||||
Services.prefs.setCharPref("devtools.netmonitor.hiddenColumns",
|
||||
'["status", "contentSize"]');
|
||||
Services.prefs.setCharPref("devtools.netmonitor.visibleColumns",
|
||||
'["status", "contentSize", "waterfall"]');
|
||||
|
||||
let { monitor } = yield initNetMonitor(SIMPLE_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
let { document, parent } = monitor.panelWin;
|
||||
|
||||
ok(!document.querySelector("#requests-list-status-button"),
|
||||
"Status column should be hidden");
|
||||
ok(!document.querySelector("#requests-list-contentSize-button"),
|
||||
"Content size column should be hidden");
|
||||
|
||||
yield showColumn("status");
|
||||
yield showColumn("contentSize");
|
||||
|
||||
ok(!Services.prefs.getCharPref("devtools.netmonitor.hiddenColumns").includes("status"),
|
||||
"Pref should be synced for status");
|
||||
ok(!Services.prefs.getCharPref("devtools.netmonitor.hiddenColumns")
|
||||
.includes("contentSize"), "Pref should be synced for contentSize");
|
||||
ok(document.querySelector("#requests-list-status-button"),
|
||||
"Status column should be shown");
|
||||
ok(document.querySelector("#requests-list-contentSize-button"),
|
||||
"Content size column should be shown");
|
||||
|
||||
yield hideColumn("status");
|
||||
yield hideColumn("contentSize");
|
||||
|
||||
ok(Services.prefs.getCharPref("devtools.netmonitor.hiddenColumns").includes("status"),
|
||||
ok(!Services.prefs.getCharPref("devtools.netmonitor.visibleColumns").includes("status"),
|
||||
"Pref should be synced for status");
|
||||
ok(!Services.prefs.getCharPref("devtools.netmonitor.visibleColumns")
|
||||
.includes("contentSize"), "Pref should be synced for contentSize");
|
||||
|
||||
yield showColumn("status");
|
||||
|
||||
ok(Services.prefs.getCharPref("devtools.netmonitor.visibleColumns").includes("status"),
|
||||
"Pref should be synced for status");
|
||||
|
||||
function* hideColumn(column) {
|
||||
info(`Clicking context-menu item for ${column}`);
|
||||
EventUtils.sendMouseEvent({ type: "contextmenu" },
|
||||
|
|
|
@ -14,7 +14,7 @@ add_task(function* () {
|
|||
let { document, parent, windowRequire } = monitor.panelWin;
|
||||
let { Prefs } = windowRequire("devtools/client/netmonitor/src/utils/prefs");
|
||||
|
||||
let prefBefore = Prefs.hiddenColumns;
|
||||
let prefBefore = Prefs.visibleColumns;
|
||||
|
||||
hideColumn("status");
|
||||
hideColumn("waterfall");
|
||||
|
@ -24,7 +24,7 @@ add_task(function* () {
|
|||
|
||||
parent.document.querySelector("#request-list-header-reset-columns").click();
|
||||
|
||||
is(JSON.stringify(prefBefore), JSON.stringify(Prefs.hiddenColumns),
|
||||
is(JSON.stringify(prefBefore), JSON.stringify(Prefs.visibleColumns),
|
||||
"Reset columns item should reset columns pref");
|
||||
|
||||
function* hideColumn(column) {
|
||||
|
|
|
@ -8,11 +8,10 @@
|
|||
*/
|
||||
|
||||
add_task(function* () {
|
||||
// Hide file, protocol, remoteip columns to make sure timing division
|
||||
// can render properly
|
||||
// Make sure timing division can render properly
|
||||
Services.prefs.setCharPref(
|
||||
"devtools.netmonitor.hiddenColumns",
|
||||
"[\"file\",\"protocol\",\"remoteip\"]"
|
||||
"devtools.netmonitor.visibleColumns",
|
||||
"[\"waterfall\"]"
|
||||
);
|
||||
|
||||
let { tab, monitor } = yield initNetMonitor(CUSTOM_GET_URL);
|
||||
|
|
|
@ -92,8 +92,14 @@ Services.prefs.setBoolPref("devtools.debugger.log", false);
|
|||
// Always reset some prefs to their original values after the test finishes.
|
||||
const gDefaultFilters = Services.prefs.getCharPref("devtools.netmonitor.filters");
|
||||
|
||||
// Reveal all hidden columns for test
|
||||
Services.prefs.setCharPref("devtools.netmonitor.hiddenColumns", "[]");
|
||||
// Reveal many columns for test
|
||||
Services.prefs.setCharPref(
|
||||
"devtools.netmonitor.visibleColumns",
|
||||
"[\"cause\",\"contentSize\",\"cookies\",\"domain\",\"duration\"," +
|
||||
"\"endTime\",\"file\",\"latency\",\"method\",\"protocol\"," +
|
||||
"\"remoteip\",\"responseTime\",\"scheme\",\"setCookies\"," +
|
||||
"\"startTime\",\"status\",\"transferred\",\"type\",\"waterfall\"]"
|
||||
);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
info("finish() was called, cleaning up...");
|
||||
|
|
|
@ -160,8 +160,8 @@ pref("devtools.netmonitor.enabled", true);
|
|||
pref("devtools.netmonitor.panes-network-details-width", 550);
|
||||
pref("devtools.netmonitor.panes-network-details-height", 450);
|
||||
pref("devtools.netmonitor.filters", "[\"all\"]");
|
||||
pref("devtools.netmonitor.hiddenColumns",
|
||||
"[\"cookies\",\"duration\",\"endTime\",\"latency\",\"protocol\",\"remoteip\",\"responseTime\",\"scheme\",\"setCookies\",\"startTime\"]"
|
||||
pref("devtools.netmonitor.visibleColumns",
|
||||
"[\"status\",\"method\",\"file\",\"domain\",\"cause\",\"type\",\"transferred\",\"contentSize\",\"waterfall\"]"
|
||||
);
|
||||
|
||||
// The default Network monitor HAR export setting
|
||||
|
|
|
@ -467,18 +467,12 @@ body {
|
|||
z-index: 1;
|
||||
}
|
||||
|
||||
.animation-timeline .all-properties .name::after {
|
||||
background-color: var(--theme-content-color3);
|
||||
clip-path: url(images/animation-fast-track.svg#thunderbolt);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.animation-timeline .all-properties .name::after,
|
||||
.animation-timeline .some-properties .name::after {
|
||||
background-color: var(--theme-content-color3);
|
||||
clip-path: url(images/animation-fast-track.svg#thunderbolt);
|
||||
-moz-context-properties: fill;
|
||||
fill: var(--theme-content-color3);
|
||||
background-image: url("images/animation-fast-track.svg");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.animation-timeline .animation .delay,
|
||||
|
@ -601,8 +595,9 @@ body {
|
|||
display: inline-block;
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
background-color: var(--background-color);
|
||||
clip-path: url(images/animation-fast-track.svg#thunderbolt);
|
||||
-moz-context-properties: fill;
|
||||
fill: var(--background-color);
|
||||
background-image: url("images/animation-fast-track.svg");
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
|
||||
<clipPath id="thunderbolt" transform="scale(1.4)">
|
||||
<path d="M5.75 0l-1 5.5 2 .5-3.5 6 1-5-2-.5z"/>
|
||||
</clipPath>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 9 12" width="16" height="16">
|
||||
<path d="M5.75 0l-1 5.5 2 .5-3.5 6 1-5-2-.5z" fill="context-fill"/>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 400 B После Ширина: | Высота: | Размер: 372 B |
|
@ -3499,7 +3499,7 @@ Selection::PostScrollSelectionIntoViewEvent(
|
|||
new ScrollSelectionIntoViewEvent(this, aRegion, aVertical, aHorizontal,
|
||||
aFlags);
|
||||
mScrollEvent = ev;
|
||||
refreshDriver->AddPendingSelectionScroll(ev);
|
||||
refreshDriver->AddEarlyRunner(ev);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,8 @@ NS_INTERFACE_MAP_END
|
|||
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsBaseContentList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsBaseContentList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsBaseContentList,
|
||||
LastRelease())
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -592,6 +593,17 @@ nsContentList::NodeWillBeDestroyed(const nsINode* aNode)
|
|||
SetDirty();
|
||||
}
|
||||
|
||||
void
|
||||
nsContentList::LastRelease()
|
||||
{
|
||||
RemoveFromCaches();
|
||||
if (mRootNode) {
|
||||
mRootNode->RemoveMutationObserver(this);
|
||||
mRootNode = nullptr;
|
||||
}
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsContentList::GetLength(uint32_t* aLength)
|
||||
{
|
||||
|
|
|
@ -95,6 +95,9 @@ public:
|
|||
{
|
||||
mElements.SetCapacity(aCapacity);
|
||||
}
|
||||
|
||||
virtual void LastRelease() {}
|
||||
|
||||
protected:
|
||||
virtual ~nsBaseContentList();
|
||||
|
||||
|
@ -352,6 +355,8 @@ public:
|
|||
Reset();
|
||||
}
|
||||
|
||||
virtual void LastRelease() override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Returns whether the element matches our criterion
|
||||
|
|
|
@ -200,7 +200,7 @@ public:
|
|||
*/
|
||||
char16_t CharAt(int32_t aIndex) const
|
||||
{
|
||||
NS_ASSERTION(uint32_t(aIndex) < mState.mLength, "bad index");
|
||||
MOZ_ASSERT(uint32_t(aIndex) < mState.mLength, "bad index");
|
||||
return mState.mIs2b ? m2b[aIndex] : static_cast<unsigned char>(m1b[aIndex]);
|
||||
}
|
||||
|
||||
|
|
|
@ -153,6 +153,8 @@ public:
|
|||
/**
|
||||
* TryToFlushPendingNotificationsToIME() suggests flushing pending
|
||||
* notifications to IME to IMEContentObserver.
|
||||
* Doesn't do anything in child processes where flushing happens
|
||||
* asynchronously.
|
||||
*/
|
||||
void TryToFlushPendingNotificationsToIME();
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "nsISupports.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "WritingModes.h"
|
||||
|
||||
|
@ -1731,15 +1732,7 @@ IMEContentObserver::FlushMergeableNotifications()
|
|||
// it may kick runnable event immediately after DOM tree is changed but
|
||||
// the selection range isn't modified yet.
|
||||
mQueuedSender = new IMENotificationSender(this);
|
||||
nsIScriptGlobalObject* globalObject = mDocShell ?
|
||||
mDocShell->GetScriptGlobalObject() :
|
||||
nullptr;
|
||||
if (globalObject) {
|
||||
RefPtr<IMENotificationSender> queuedSender = mQueuedSender;
|
||||
globalObject->Dispatch(nullptr, TaskCategory::Other, queuedSender.forget());
|
||||
} else {
|
||||
NS_DispatchToCurrentThread(mQueuedSender);
|
||||
}
|
||||
mQueuedSender->Dispatch(mDocShell);
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::FlushMergeableNotifications(), "
|
||||
"finished", this));
|
||||
|
@ -1748,7 +1741,8 @@ IMEContentObserver::FlushMergeableNotifications()
|
|||
void
|
||||
IMEContentObserver::TryToFlushPendingNotifications()
|
||||
{
|
||||
if (!mQueuedSender || mSendingNotification != NOTIFY_IME_OF_NOTHING) {
|
||||
if (!mQueuedSender || mSendingNotification != NOTIFY_IME_OF_NOTHING ||
|
||||
XRE_IsContentProcess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1767,28 +1761,30 @@ bool
|
|||
IMEContentObserver::AChangeEvent::CanNotifyIME(
|
||||
ChangeEventType aChangeEventType) const
|
||||
{
|
||||
if (NS_WARN_IF(!mIMEContentObserver)) {
|
||||
RefPtr<IMEContentObserver> observer = GetObserver();
|
||||
if (NS_WARN_IF(!observer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aChangeEventType == eChangeEventType_CompositionEventHandled) {
|
||||
return mIMEContentObserver->mWidget != nullptr;
|
||||
return observer->mWidget != nullptr;
|
||||
}
|
||||
State state = mIMEContentObserver->GetState();
|
||||
State state = observer->GetState();
|
||||
// If it's not initialized, we should do nothing.
|
||||
if (state == eState_NotObserving) {
|
||||
return false;
|
||||
}
|
||||
// If setting focus, just check the state.
|
||||
if (aChangeEventType == eChangeEventType_Focus) {
|
||||
return !NS_WARN_IF(mIMEContentObserver->mIMEHasFocus);
|
||||
return !NS_WARN_IF(observer->mIMEHasFocus);
|
||||
}
|
||||
// If we've not notified IME of focus yet, we shouldn't notify anything.
|
||||
if (!mIMEContentObserver->mIMEHasFocus) {
|
||||
if (!observer->mIMEHasFocus) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If IME has focus, IMEContentObserver must hold the widget.
|
||||
MOZ_ASSERT(mIMEContentObserver->mWidget);
|
||||
MOZ_ASSERT(observer->mWidget);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1800,17 +1796,23 @@ IMEContentObserver::AChangeEvent::IsSafeToNotifyIME(
|
|||
if (NS_WARN_IF(!nsContentUtils::IsSafeToRunScript())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<IMEContentObserver> observer = GetObserver();
|
||||
if (!observer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// While we're sending a notification, we shouldn't send another notification
|
||||
// recursively.
|
||||
if (mIMEContentObserver->mSendingNotification != NOTIFY_IME_OF_NOTHING) {
|
||||
if (observer->mSendingNotification != NOTIFY_IME_OF_NOTHING) {
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::AChangeEvent::IsSafeToNotifyIME(), "
|
||||
"putting off sending notification due to detecting recursive call, "
|
||||
"mIMEContentObserver={ mSendingNotification=%s }",
|
||||
this, ToChar(mIMEContentObserver->mSendingNotification)));
|
||||
this, ToChar(observer->mSendingNotification)));
|
||||
return false;
|
||||
}
|
||||
State state = mIMEContentObserver->GetState();
|
||||
State state = observer->GetState();
|
||||
if (aChangeEventType == eChangeEventType_Focus) {
|
||||
if (NS_WARN_IF(state != eState_Initializing && state != eState_Observing)) {
|
||||
return false;
|
||||
|
@ -1820,13 +1822,39 @@ IMEContentObserver::AChangeEvent::IsSafeToNotifyIME(
|
|||
} else if (state != eState_Observing) {
|
||||
return false;
|
||||
}
|
||||
return mIMEContentObserver->IsSafeToNotifyIME();
|
||||
return observer->IsSafeToNotifyIME();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* mozilla::IMEContentObserver::IMENotificationSender
|
||||
******************************************************************************/
|
||||
|
||||
void
|
||||
IMEContentObserver::IMENotificationSender::Dispatch(nsIDocShell* aDocShell)
|
||||
{
|
||||
if (XRE_IsContentProcess() && aDocShell) {
|
||||
RefPtr<nsPresContext> presContext;
|
||||
aDocShell->GetPresContext(getter_AddRefs(presContext));
|
||||
if (presContext) {
|
||||
nsRefreshDriver* refreshDriver = presContext->RefreshDriver();
|
||||
if (refreshDriver) {
|
||||
refreshDriver->AddEarlyRunner(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsIScriptGlobalObject* globalObject =
|
||||
aDocShell ? aDocShell->GetScriptGlobalObject() : nullptr;
|
||||
if (globalObject) {
|
||||
RefPtr<IMENotificationSender> queuedSender = this;
|
||||
globalObject->Dispatch(nullptr, TaskCategory::Other,
|
||||
queuedSender.forget());
|
||||
} else {
|
||||
NS_DispatchToCurrentThread(this);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IMEContentObserver::IMENotificationSender::Run()
|
||||
{
|
||||
|
@ -1837,65 +1865,59 @@ IMEContentObserver::IMENotificationSender::Run()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<IMEContentObserver> observer = GetObserver();
|
||||
if (!observer) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AutoRestore<bool> running(mIsRunning);
|
||||
mIsRunning = true;
|
||||
|
||||
// This instance was already performed forcibly.
|
||||
if (mIMEContentObserver->mQueuedSender != this) {
|
||||
if (observer->mQueuedSender != this) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// NOTE: Reset each pending flag because sending notification may cause
|
||||
// another change.
|
||||
|
||||
if (mIMEContentObserver->mNeedsToNotifyIMEOfFocusSet) {
|
||||
mIMEContentObserver->mNeedsToNotifyIMEOfFocusSet = false;
|
||||
if (observer->mNeedsToNotifyIMEOfFocusSet) {
|
||||
observer->mNeedsToNotifyIMEOfFocusSet = false;
|
||||
SendFocusSet();
|
||||
mIMEContentObserver->mQueuedSender = nullptr;
|
||||
observer->mQueuedSender = nullptr;
|
||||
// If it's not safe to notify IME of focus, SendFocusSet() sets
|
||||
// mNeedsToNotifyIMEOfFocusSet true again. For guaranteeing to send the
|
||||
// focus notification later, we should put a new sender into the queue but
|
||||
// this case must be rare. Note that if mIMEContentObserver is already
|
||||
// destroyed, mNeedsToNotifyIMEOfFocusSet is never set true again.
|
||||
if (mIMEContentObserver->mNeedsToNotifyIMEOfFocusSet) {
|
||||
MOZ_ASSERT(!mIMEContentObserver->mIMEHasFocus);
|
||||
if (observer->mNeedsToNotifyIMEOfFocusSet) {
|
||||
MOZ_ASSERT(!observer->mIMEHasFocus);
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::Run(), "
|
||||
"posting IMENotificationSender to current thread", this));
|
||||
mIMEContentObserver->mQueuedSender =
|
||||
new IMENotificationSender(mIMEContentObserver);
|
||||
nsIScriptGlobalObject* globalObject =
|
||||
mIMEContentObserver->mDocShell ?
|
||||
mIMEContentObserver->mDocShell->GetScriptGlobalObject() : nullptr;
|
||||
if (globalObject) {
|
||||
RefPtr<IMENotificationSender> queuedSender =
|
||||
mIMEContentObserver->mQueuedSender;
|
||||
globalObject->Dispatch(nullptr, TaskCategory::Other,
|
||||
queuedSender.forget());
|
||||
} else {
|
||||
NS_DispatchToCurrentThread(mIMEContentObserver->mQueuedSender);
|
||||
}
|
||||
observer->mQueuedSender = new IMENotificationSender(observer);
|
||||
observer->mQueuedSender->Dispatch(observer->mDocShell);
|
||||
return NS_OK;
|
||||
}
|
||||
// This is the first notification to IME. So, we don't need to notify
|
||||
// anymore since IME starts to query content after it gets focus.
|
||||
mIMEContentObserver->ClearPendingNotifications();
|
||||
observer->ClearPendingNotifications();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mIMEContentObserver->mNeedsToNotifyIMEOfTextChange) {
|
||||
mIMEContentObserver->mNeedsToNotifyIMEOfTextChange = false;
|
||||
if (observer->mNeedsToNotifyIMEOfTextChange) {
|
||||
observer->mNeedsToNotifyIMEOfTextChange = false;
|
||||
SendTextChange();
|
||||
}
|
||||
|
||||
// If a text change notification causes another text change again, we should
|
||||
// notify IME of that before sending a selection change notification.
|
||||
if (!mIMEContentObserver->mNeedsToNotifyIMEOfTextChange) {
|
||||
if (!observer->mNeedsToNotifyIMEOfTextChange) {
|
||||
// Be aware, PuppetWidget depends on the order of this. A selection change
|
||||
// notification should not be sent before a text change notification because
|
||||
// PuppetWidget shouldn't query new text content every selection change.
|
||||
if (mIMEContentObserver->mNeedsToNotifyIMEOfSelectionChange) {
|
||||
mIMEContentObserver->mNeedsToNotifyIMEOfSelectionChange = false;
|
||||
if (observer->mNeedsToNotifyIMEOfSelectionChange) {
|
||||
observer->mNeedsToNotifyIMEOfSelectionChange = false;
|
||||
SendSelectionChange();
|
||||
}
|
||||
}
|
||||
|
@ -1904,10 +1926,10 @@ IMEContentObserver::IMENotificationSender::Run()
|
|||
// selection change notification causes either a text change or another
|
||||
// selection change, we should notify IME of those before sending a position
|
||||
// change notification.
|
||||
if (!mIMEContentObserver->mNeedsToNotifyIMEOfTextChange &&
|
||||
!mIMEContentObserver->mNeedsToNotifyIMEOfSelectionChange) {
|
||||
if (mIMEContentObserver->mNeedsToNotifyIMEOfPositionChange) {
|
||||
mIMEContentObserver->mNeedsToNotifyIMEOfPositionChange = false;
|
||||
if (!observer->mNeedsToNotifyIMEOfTextChange &&
|
||||
!observer->mNeedsToNotifyIMEOfSelectionChange) {
|
||||
if (observer->mNeedsToNotifyIMEOfPositionChange) {
|
||||
observer->mNeedsToNotifyIMEOfPositionChange = false;
|
||||
SendPositionChange();
|
||||
}
|
||||
}
|
||||
|
@ -1915,20 +1937,20 @@ IMEContentObserver::IMENotificationSender::Run()
|
|||
// Composition event handled notification should be sent after all the
|
||||
// other notifications because this notifies widget of finishing all pending
|
||||
// events are handled completely.
|
||||
if (!mIMEContentObserver->mNeedsToNotifyIMEOfTextChange &&
|
||||
!mIMEContentObserver->mNeedsToNotifyIMEOfSelectionChange &&
|
||||
!mIMEContentObserver->mNeedsToNotifyIMEOfPositionChange) {
|
||||
if (mIMEContentObserver->mNeedsToNotifyIMEOfCompositionEventHandled) {
|
||||
mIMEContentObserver->mNeedsToNotifyIMEOfCompositionEventHandled = false;
|
||||
if (!observer->mNeedsToNotifyIMEOfTextChange &&
|
||||
!observer->mNeedsToNotifyIMEOfSelectionChange &&
|
||||
!observer->mNeedsToNotifyIMEOfPositionChange) {
|
||||
if (observer->mNeedsToNotifyIMEOfCompositionEventHandled) {
|
||||
observer->mNeedsToNotifyIMEOfCompositionEventHandled = false;
|
||||
SendCompositionEventHandled();
|
||||
}
|
||||
}
|
||||
|
||||
mIMEContentObserver->mQueuedSender = nullptr;
|
||||
observer->mQueuedSender = nullptr;
|
||||
|
||||
// If notifications caused some new change, we should notify them now.
|
||||
if (mIMEContentObserver->NeedsToNotifyIMEOfSomething()) {
|
||||
if (mIMEContentObserver->GetState() == eState_StoppedObserving) {
|
||||
if (observer->NeedsToNotifyIMEOfSomething()) {
|
||||
if (observer->GetState() == eState_StoppedObserving) {
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::Run(), "
|
||||
"waiting IMENotificationSender to be reinitialized", this));
|
||||
|
@ -1936,19 +1958,8 @@ IMEContentObserver::IMENotificationSender::Run()
|
|||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::Run(), "
|
||||
"posting IMENotificationSender to current thread", this));
|
||||
mIMEContentObserver->mQueuedSender =
|
||||
new IMENotificationSender(mIMEContentObserver);
|
||||
nsIScriptGlobalObject* globalObject =
|
||||
mIMEContentObserver->mDocShell ?
|
||||
mIMEContentObserver->mDocShell->GetScriptGlobalObject() : nullptr;
|
||||
if (globalObject) {
|
||||
RefPtr<IMENotificationSender> queuedSender =
|
||||
mIMEContentObserver->mQueuedSender;
|
||||
globalObject->Dispatch(nullptr, TaskCategory::Other,
|
||||
queuedSender.forget());
|
||||
} else {
|
||||
NS_DispatchToCurrentThread(mIMEContentObserver->mQueuedSender);
|
||||
}
|
||||
observer->mQueuedSender = new IMENotificationSender(observer);
|
||||
observer->mQueuedSender->Dispatch(observer->mDocShell);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -1957,6 +1968,11 @@ IMEContentObserver::IMENotificationSender::Run()
|
|||
void
|
||||
IMEContentObserver::IMENotificationSender::SendFocusSet()
|
||||
{
|
||||
RefPtr<IMEContentObserver> observer = GetObserver();
|
||||
if (!observer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanNotifyIME(eChangeEventType_Focus)) {
|
||||
// If IMEContentObserver has already gone, we don't need to notify IME of
|
||||
// focus.
|
||||
|
@ -1964,7 +1980,7 @@ IMEContentObserver::IMENotificationSender::SendFocusSet()
|
|||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
"SendFocusSet(), FAILED, due to impossible to notify IME of focus",
|
||||
this));
|
||||
mIMEContentObserver->ClearPendingNotifications();
|
||||
observer->ClearPendingNotifications();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1972,30 +1988,30 @@ IMEContentObserver::IMENotificationSender::SendFocusSet()
|
|||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
"SendFocusSet(), retrying to send NOTIFY_IME_OF_FOCUS...", this));
|
||||
mIMEContentObserver->PostFocusSetNotification();
|
||||
observer->PostFocusSetNotification();
|
||||
return;
|
||||
}
|
||||
|
||||
mIMEContentObserver->mIMEHasFocus = true;
|
||||
observer->mIMEHasFocus = true;
|
||||
// Initialize selection cache with the first selection data.
|
||||
mIMEContentObserver->UpdateSelectionCache();
|
||||
observer->UpdateSelectionCache();
|
||||
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Info,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
"SendFocusSet(), sending NOTIFY_IME_OF_FOCUS...", this));
|
||||
|
||||
MOZ_RELEASE_ASSERT(mIMEContentObserver->mSendingNotification ==
|
||||
MOZ_RELEASE_ASSERT(observer->mSendingNotification ==
|
||||
NOTIFY_IME_OF_NOTHING);
|
||||
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_FOCUS;
|
||||
observer->mSendingNotification = NOTIFY_IME_OF_FOCUS;
|
||||
IMEStateManager::NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS),
|
||||
mIMEContentObserver->mWidget);
|
||||
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
||||
observer->mWidget);
|
||||
observer->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
||||
|
||||
// IMENotificationRequests referred by ObserveEditableNode() may be different
|
||||
// before or after widget receives NOTIFY_IME_OF_FOCUS. Therefore, we need
|
||||
// to guarantee to call ObserveEditableNode() after sending
|
||||
// NOTIFY_IME_OF_FOCUS.
|
||||
mIMEContentObserver->OnIMEReceivedFocus();
|
||||
observer->OnIMEReceivedFocus();
|
||||
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
|
@ -2005,6 +2021,11 @@ IMEContentObserver::IMENotificationSender::SendFocusSet()
|
|||
void
|
||||
IMEContentObserver::IMENotificationSender::SendSelectionChange()
|
||||
{
|
||||
RefPtr<IMEContentObserver> observer = GetObserver();
|
||||
if (!observer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanNotifyIME(eChangeEventType_Selection)) {
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
|
@ -2018,12 +2039,12 @@ IMEContentObserver::IMENotificationSender::SendSelectionChange()
|
|||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
"SendSelectionChange(), retrying to send "
|
||||
"NOTIFY_IME_OF_SELECTION_CHANGE...", this));
|
||||
mIMEContentObserver->PostSelectionChangeNotification();
|
||||
observer->PostSelectionChangeNotification();
|
||||
return;
|
||||
}
|
||||
|
||||
SelectionChangeData lastSelChangeData = mIMEContentObserver->mSelectionData;
|
||||
if (NS_WARN_IF(!mIMEContentObserver->UpdateSelectionCache())) {
|
||||
SelectionChangeData lastSelChangeData = observer->mSelectionData;
|
||||
if (NS_WARN_IF(!observer->UpdateSelectionCache())) {
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Error,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
"SendSelectionChange(), FAILED, due to UpdateSelectionCache() failure",
|
||||
|
@ -2042,7 +2063,7 @@ IMEContentObserver::IMENotificationSender::SendSelectionChange()
|
|||
|
||||
// If the selection isn't changed actually, we shouldn't notify IME of
|
||||
// selection change.
|
||||
SelectionChangeData& newSelChangeData = mIMEContentObserver->mSelectionData;
|
||||
SelectionChangeData& newSelChangeData = observer->mSelectionData;
|
||||
if (lastSelChangeData.IsValid() &&
|
||||
lastSelChangeData.mOffset == newSelChangeData.mOffset &&
|
||||
lastSelChangeData.String() == newSelChangeData.String() &&
|
||||
|
@ -2062,13 +2083,13 @@ IMEContentObserver::IMENotificationSender::SendSelectionChange()
|
|||
this, SelectionChangeDataToString(newSelChangeData).get()));
|
||||
|
||||
IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE);
|
||||
notification.SetData(mIMEContentObserver->mSelectionData);
|
||||
notification.SetData(observer->mSelectionData);
|
||||
|
||||
MOZ_RELEASE_ASSERT(mIMEContentObserver->mSendingNotification ==
|
||||
MOZ_RELEASE_ASSERT(observer->mSendingNotification ==
|
||||
NOTIFY_IME_OF_NOTHING);
|
||||
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_SELECTION_CHANGE;
|
||||
IMEStateManager::NotifyIME(notification, mIMEContentObserver->mWidget);
|
||||
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
||||
observer->mSendingNotification = NOTIFY_IME_OF_SELECTION_CHANGE;
|
||||
IMEStateManager::NotifyIME(notification, observer->mWidget);
|
||||
observer->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
||||
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
|
@ -2078,6 +2099,11 @@ IMEContentObserver::IMENotificationSender::SendSelectionChange()
|
|||
void
|
||||
IMEContentObserver::IMENotificationSender::SendTextChange()
|
||||
{
|
||||
RefPtr<IMEContentObserver> observer = GetObserver();
|
||||
if (!observer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanNotifyIME(eChangeEventType_Text)) {
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
|
@ -2091,17 +2117,17 @@ IMEContentObserver::IMENotificationSender::SendTextChange()
|
|||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
"SendTextChange(), retrying to send NOTIFY_IME_OF_TEXT_CHANGE...",
|
||||
this));
|
||||
mIMEContentObserver->PostTextChangeNotification();
|
||||
observer->PostTextChangeNotification();
|
||||
return;
|
||||
}
|
||||
|
||||
// If text change notification is unnecessary anymore, just cancel it.
|
||||
if (!mIMEContentObserver->NeedsTextChangeNotification()) {
|
||||
if (!observer->NeedsTextChangeNotification()) {
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Warning,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
"SendTextChange(), canceling sending NOTIFY_IME_OF_TEXT_CHANGE",
|
||||
this));
|
||||
mIMEContentObserver->CancelNotifyingIMEOfTextChange();
|
||||
observer->CancelNotifyingIMEOfTextChange();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2109,17 +2135,17 @@ IMEContentObserver::IMENotificationSender::SendTextChange()
|
|||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
"SendTextChange(), sending NOTIFY_IME_OF_TEXT_CHANGE... "
|
||||
"mIMEContentObserver={ mTextChangeData=%s }",
|
||||
this, TextChangeDataToString(mIMEContentObserver->mTextChangeData).get()));
|
||||
this, TextChangeDataToString(observer->mTextChangeData).get()));
|
||||
|
||||
IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE);
|
||||
notification.SetData(mIMEContentObserver->mTextChangeData);
|
||||
mIMEContentObserver->mTextChangeData.Clear();
|
||||
notification.SetData(observer->mTextChangeData);
|
||||
observer->mTextChangeData.Clear();
|
||||
|
||||
MOZ_RELEASE_ASSERT(mIMEContentObserver->mSendingNotification ==
|
||||
MOZ_RELEASE_ASSERT(observer->mSendingNotification ==
|
||||
NOTIFY_IME_OF_NOTHING);
|
||||
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_TEXT_CHANGE;
|
||||
IMEStateManager::NotifyIME(notification, mIMEContentObserver->mWidget);
|
||||
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
||||
observer->mSendingNotification = NOTIFY_IME_OF_TEXT_CHANGE;
|
||||
IMEStateManager::NotifyIME(notification, observer->mWidget);
|
||||
observer->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
||||
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
|
@ -2129,6 +2155,11 @@ IMEContentObserver::IMENotificationSender::SendTextChange()
|
|||
void
|
||||
IMEContentObserver::IMENotificationSender::SendPositionChange()
|
||||
{
|
||||
RefPtr<IMEContentObserver> observer = GetObserver();
|
||||
if (!observer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanNotifyIME(eChangeEventType_Position)) {
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
|
@ -2142,17 +2173,17 @@ IMEContentObserver::IMENotificationSender::SendPositionChange()
|
|||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
"SendPositionChange(), retrying to send "
|
||||
"NOTIFY_IME_OF_POSITION_CHANGE...", this));
|
||||
mIMEContentObserver->PostPositionChangeNotification();
|
||||
observer->PostPositionChangeNotification();
|
||||
return;
|
||||
}
|
||||
|
||||
// If position change notification is unnecessary anymore, just cancel it.
|
||||
if (!mIMEContentObserver->NeedsPositionChangeNotification()) {
|
||||
if (!observer->NeedsPositionChangeNotification()) {
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Warning,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
"SendPositionChange(), canceling sending NOTIFY_IME_OF_POSITION_CHANGE",
|
||||
this));
|
||||
mIMEContentObserver->CancelNotifyingIMEOfPositionChange();
|
||||
observer->CancelNotifyingIMEOfPositionChange();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2160,12 +2191,12 @@ IMEContentObserver::IMENotificationSender::SendPositionChange()
|
|||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
"SendPositionChange(), sending NOTIFY_IME_OF_POSITION_CHANGE...", this));
|
||||
|
||||
MOZ_RELEASE_ASSERT(mIMEContentObserver->mSendingNotification ==
|
||||
MOZ_RELEASE_ASSERT(observer->mSendingNotification ==
|
||||
NOTIFY_IME_OF_NOTHING);
|
||||
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_POSITION_CHANGE;
|
||||
observer->mSendingNotification = NOTIFY_IME_OF_POSITION_CHANGE;
|
||||
IMEStateManager::NotifyIME(IMENotification(NOTIFY_IME_OF_POSITION_CHANGE),
|
||||
mIMEContentObserver->mWidget);
|
||||
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
||||
observer->mWidget);
|
||||
observer->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
||||
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
|
@ -2175,6 +2206,11 @@ IMEContentObserver::IMENotificationSender::SendPositionChange()
|
|||
void
|
||||
IMEContentObserver::IMENotificationSender::SendCompositionEventHandled()
|
||||
{
|
||||
RefPtr<IMEContentObserver> observer = GetObserver();
|
||||
if (!observer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanNotifyIME(eChangeEventType_CompositionEventHandled)) {
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
|
@ -2188,7 +2224,7 @@ IMEContentObserver::IMENotificationSender::SendCompositionEventHandled()
|
|||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
"SendCompositionEventHandled(), retrying to send "
|
||||
"NOTIFY_IME_OF_POSITION_CHANGE...", this));
|
||||
mIMEContentObserver->PostCompositionEventHandledNotification();
|
||||
observer->PostCompositionEventHandledNotification();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2197,14 +2233,14 @@ IMEContentObserver::IMENotificationSender::SendCompositionEventHandled()
|
|||
"SendCompositionEventHandled(), sending "
|
||||
"NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED...", this));
|
||||
|
||||
MOZ_RELEASE_ASSERT(mIMEContentObserver->mSendingNotification ==
|
||||
MOZ_RELEASE_ASSERT(observer->mSendingNotification ==
|
||||
NOTIFY_IME_OF_NOTHING);
|
||||
mIMEContentObserver->mSendingNotification =
|
||||
observer->mSendingNotification =
|
||||
NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED;
|
||||
IMEStateManager::NotifyIME(
|
||||
IMENotification(NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED),
|
||||
mIMEContentObserver->mWidget);
|
||||
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
||||
observer->mWidget);
|
||||
observer->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
||||
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::IMENotificationSender::"
|
||||
|
|
|
@ -154,6 +154,8 @@ public:
|
|||
/**
|
||||
* TryToFlushPendingNotifications() should be called when pending events
|
||||
* should be flushed. This tries to run the queued IMENotificationSender.
|
||||
* Doesn't do anything in child processes where flushing happens
|
||||
* asynchronously.
|
||||
*/
|
||||
void TryToFlushPendingNotifications();
|
||||
|
||||
|
@ -331,12 +333,21 @@ private:
|
|||
explicit AChangeEvent(const char* aName,
|
||||
IMEContentObserver* aIMEContentObserver)
|
||||
: Runnable(aName)
|
||||
, mIMEContentObserver(aIMEContentObserver)
|
||||
, mIMEContentObserver(
|
||||
do_GetWeakReference(
|
||||
static_cast<nsISelectionListener*>(aIMEContentObserver)))
|
||||
{
|
||||
MOZ_ASSERT(mIMEContentObserver);
|
||||
MOZ_ASSERT(aIMEContentObserver);
|
||||
}
|
||||
|
||||
RefPtr<IMEContentObserver> mIMEContentObserver;
|
||||
already_AddRefed<IMEContentObserver> GetObserver() const
|
||||
{
|
||||
nsCOMPtr<nsISelectionListener> observer =
|
||||
do_QueryReferent(mIMEContentObserver);
|
||||
return observer.forget().downcast<IMEContentObserver>();
|
||||
}
|
||||
|
||||
nsWeakPtr mIMEContentObserver;
|
||||
|
||||
/**
|
||||
* CanNotifyIME() checks if mIMEContentObserver can and should notify IME.
|
||||
|
@ -359,6 +370,7 @@ private:
|
|||
}
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
void Dispatch(nsIDocShell* aDocShell);
|
||||
private:
|
||||
void SendFocusSet();
|
||||
void SendSelectionChange();
|
||||
|
|
|
@ -244,8 +244,12 @@ UIEvent::GetRangeParent()
|
|||
nsIFrame* targetFrame = nullptr;
|
||||
|
||||
if (mPresContext) {
|
||||
nsCOMPtr<nsIPresShell> shell = mPresContext->GetPresShell();
|
||||
if (shell) {
|
||||
shell->FlushPendingNotifications(FlushType::Layout);
|
||||
targetFrame = mPresContext->EventStateManager()->GetEventTarget();
|
||||
}
|
||||
}
|
||||
|
||||
if (targetFrame) {
|
||||
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent,
|
||||
|
@ -290,6 +294,13 @@ UIEvent::RangeOffset() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresShell> shell = mPresContext->GetPresShell();
|
||||
if (!shell) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
shell->FlushPendingNotifications(FlushType::Layout);
|
||||
|
||||
nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
|
||||
if (!targetFrame) {
|
||||
return 0;
|
||||
|
|
|
@ -1434,29 +1434,26 @@ HTMLFormElement::RemoveElementFromTableInternal(
|
|||
nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable,
|
||||
nsIContent* aChild, const nsAString& aName)
|
||||
{
|
||||
nsCOMPtr<nsISupports> supports;
|
||||
|
||||
if (!aTable.Get(aName, getter_AddRefs(supports)))
|
||||
auto entry = aTable.Lookup(aName);
|
||||
if (!entry) {
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
// Single element in the hash, just remove it if it's the one
|
||||
// we're trying to remove...
|
||||
if (supports == aChild) {
|
||||
aTable.Remove(aName);
|
||||
if (entry.Data() == aChild) {
|
||||
entry.Remove();
|
||||
++mExpandoAndGeneration.generation;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(supports));
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(entry.Data()));
|
||||
if (content) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMNodeList> nodeList(do_QueryInterface(supports));
|
||||
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
|
||||
|
||||
// Upcast, uggly, but it works!
|
||||
nsBaseContentList *list = static_cast<nsBaseContentList*>(nodeList.get());
|
||||
// If it's not a content node then it must be a RadioNodeList.
|
||||
MOZ_ASSERT(nsCOMPtr<RadioNodeList>(do_QueryInterface(entry.Data())));
|
||||
auto* list = static_cast<RadioNodeList*>(entry.Data().get());
|
||||
|
||||
list->RemoveElement(aChild);
|
||||
|
||||
|
@ -1466,14 +1463,14 @@ HTMLFormElement::RemoveElementFromTableInternal(
|
|||
if (!length) {
|
||||
// If the list is empty we remove if from our hash, this shouldn't
|
||||
// happen tho
|
||||
aTable.Remove(aName);
|
||||
entry.Remove();
|
||||
++mExpandoAndGeneration.generation;
|
||||
} else if (length == 1) {
|
||||
// Only one element left, replace the list in the hash with the
|
||||
// single element.
|
||||
nsIContent* node = list->Item(0);
|
||||
if (node) {
|
||||
aTable.Put(aName, node);
|
||||
entry.Data() = node;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2291,8 +2288,12 @@ HTMLFormElement::AddToRadioGroup(const nsAString& aName,
|
|||
NS_ASSERTION(element, "radio controls have to be content elements!");
|
||||
|
||||
if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
|
||||
mRequiredRadioButtonCounts.Put(aName,
|
||||
mRequiredRadioButtonCounts.Get(aName)+1);
|
||||
auto entry = mRequiredRadioButtonCounts.LookupForAdd(aName);
|
||||
if (!entry) {
|
||||
entry.OrInsert([]() { return 1; });
|
||||
} else {
|
||||
++entry.Data();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2304,14 +2305,17 @@ HTMLFormElement::RemoveFromRadioGroup(const nsAString& aName,
|
|||
NS_ASSERTION(element, "radio controls have to be content elements!");
|
||||
|
||||
if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
|
||||
uint32_t requiredNb = mRequiredRadioButtonCounts.Get(aName);
|
||||
NS_ASSERTION(requiredNb >= 1,
|
||||
"At least one radio button has to be required!");
|
||||
|
||||
if (requiredNb == 1) {
|
||||
mRequiredRadioButtonCounts.Remove(aName);
|
||||
auto entry = mRequiredRadioButtonCounts.Lookup(aName);
|
||||
if (!entry) {
|
||||
MOZ_ASSERT_UNREACHABLE("At least one radio button has to be required!");
|
||||
} else {
|
||||
mRequiredRadioButtonCounts.Put(aName, requiredNb-1);
|
||||
MOZ_ASSERT(entry.Data() >= 1,
|
||||
"At least one radio button has to be required!");
|
||||
if (entry.Data() <= 1) {
|
||||
entry.Remove();
|
||||
} else {
|
||||
--entry.Data();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2396,10 +2400,10 @@ struct PositionComparator
|
|||
}
|
||||
};
|
||||
|
||||
struct NodeListAdaptor
|
||||
struct RadioNodeListAdaptor
|
||||
{
|
||||
nsINodeList* const mList;
|
||||
explicit NodeListAdaptor(nsINodeList* aList) : mList(aList) {}
|
||||
RadioNodeList* const mList;
|
||||
explicit RadioNodeListAdaptor(RadioNodeList* aList) : mList(aList) {}
|
||||
nsIContent* operator[](size_t aIdx) const {
|
||||
return mList->Item(aIdx);
|
||||
}
|
||||
|
@ -2412,16 +2416,14 @@ HTMLFormElement::AddElementToTableInternal(
|
|||
nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable,
|
||||
nsIContent* aChild, const nsAString& aName)
|
||||
{
|
||||
nsCOMPtr<nsISupports> supports;
|
||||
aTable.Get(aName, getter_AddRefs(supports));
|
||||
|
||||
if (!supports) {
|
||||
auto entry = aTable.LookupForAdd(aName);
|
||||
if (!entry) {
|
||||
// No entry found, add the element
|
||||
aTable.Put(aName, aChild);
|
||||
entry.OrInsert([&aChild]() { return aChild; });
|
||||
++mExpandoAndGeneration.generation;
|
||||
} else {
|
||||
// Found something in the hash, check its type
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(supports);
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(entry.Data());
|
||||
|
||||
if (content) {
|
||||
// Check if the new content is the same as the one we found in the
|
||||
|
@ -2451,15 +2453,11 @@ HTMLFormElement::AddElementToTableInternal(
|
|||
nsCOMPtr<nsISupports> listSupports = do_QueryObject(list);
|
||||
|
||||
// Replace the element with the list.
|
||||
aTable.Put(aName, listSupports);
|
||||
entry.Data() = listSupports;
|
||||
} else {
|
||||
// There's already a list in the hash, add the child to the list
|
||||
nsCOMPtr<nsIDOMNodeList> nodeList = do_QueryInterface(supports);
|
||||
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
|
||||
|
||||
// Upcast, uggly, but it works!
|
||||
RadioNodeList *list =
|
||||
static_cast<RadioNodeList*>(nodeList.get());
|
||||
// There's already a list in the hash, add the child to the list.
|
||||
MOZ_ASSERT(nsCOMPtr<RadioNodeList>(do_QueryInterface(entry.Data())));
|
||||
auto* list = static_cast<RadioNodeList*>(entry.Data().get());
|
||||
|
||||
NS_ASSERTION(list->Length() > 1,
|
||||
"List should have been converted back to a single element");
|
||||
|
@ -2480,7 +2478,7 @@ HTMLFormElement::AddElementToTableInternal(
|
|||
}
|
||||
|
||||
size_t idx;
|
||||
DebugOnly<bool> found = BinarySearchIf(NodeListAdaptor(list), 0, list->Length(),
|
||||
DebugOnly<bool> found = BinarySearchIf(RadioNodeListAdaptor(list), 0, list->Length(),
|
||||
PositionComparator(aChild), &idx);
|
||||
MOZ_ASSERT(!found, "should not have found an element");
|
||||
|
||||
|
|
|
@ -3109,7 +3109,7 @@ HTMLInputElement::SetValueInternal(const nsAString& aValue,
|
|||
!(aFlags & nsTextEditorState::eSetValue_BySetUserInput)) {
|
||||
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
||||
if (frame) {
|
||||
frame->UpdateInputBoxValue();
|
||||
frame->OnValueChanged();
|
||||
}
|
||||
}
|
||||
if (mDoneCreating) {
|
||||
|
|
|
@ -846,6 +846,13 @@ public:
|
|||
*/
|
||||
void UpdateValidityState();
|
||||
|
||||
/*
|
||||
* The following are called from datetime input box binding to get the
|
||||
* corresponding computed values.
|
||||
*/
|
||||
double GetStepAsDouble() { return GetStep().toDouble(); }
|
||||
double GetStepBaseAsDouble() { return GetStepBase().toDouble(); }
|
||||
|
||||
HTMLInputElement* GetOwnerNumberControl();
|
||||
|
||||
void StartNumberControlSpinnerSpin();
|
||||
|
|
|
@ -3399,24 +3399,34 @@ HTMLMediaElement::AddCaptureMediaTrackToOutputStream(MediaTrack* aTrack,
|
|||
track.get(), destinationTrackID, inputTrack, port.get()));
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::CanBeCaptured(bool aCaptureAudio)
|
||||
{
|
||||
// Don't bother capturing when the document has gone away
|
||||
nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prevent capturing restricted video
|
||||
if (!aCaptureAudio && ContainsRestrictedContent()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMediaStream>
|
||||
HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
|
||||
bool aCaptureAudio,
|
||||
MediaStreamGraph* aGraph)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(aGraph);
|
||||
MOZ_ASSERT(CanBeCaptured(aCaptureAudio));
|
||||
|
||||
MarkAsContentSource(CallerAPI::CAPTURE_STREAM);
|
||||
MarkAsTainted();
|
||||
|
||||
nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!aCaptureAudio && ContainsRestrictedContent()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We don't support routing to a different graph.
|
||||
if (!mOutputStreams.IsEmpty() &&
|
||||
aGraph != mOutputStreams[0].mStream->GetInputStream()->Graph()) {
|
||||
return nullptr;
|
||||
|
@ -3424,6 +3434,7 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
|
|||
|
||||
OutputMediaStream* out = mOutputStreams.AppendElement();
|
||||
MediaStreamTrackSourceGetter* getter = new CaptureStreamTrackSourceGetter(this);
|
||||
nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
|
||||
out->mStream = DOMMediaStream::CreateTrackUnionStreamAsInput(window, aGraph, getter);
|
||||
out->mStream->SetInactiveOnFinish();
|
||||
out->mFinishWhenEnded = aFinishWhenEnded;
|
||||
|
@ -3530,8 +3541,21 @@ HTMLMediaElement::MozCaptureStream(ErrorResult& aRv)
|
|||
MediaStreamGraph::GraphDriverType graphDriverType =
|
||||
HasAudio() ? MediaStreamGraph::AUDIO_THREAD_DRIVER
|
||||
: MediaStreamGraph::SYSTEM_THREAD_DRIVER;
|
||||
|
||||
|
||||
nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!CanBeCaptured(false)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MediaStreamGraph* graph =
|
||||
MediaStreamGraph::GetInstance(graphDriverType, mAudioChannel);
|
||||
MediaStreamGraph::GetInstance(graphDriverType, mAudioChannel, window);
|
||||
|
||||
RefPtr<DOMMediaStream> stream =
|
||||
CaptureStreamInternal(false, false, graph);
|
||||
|
@ -3549,8 +3573,20 @@ HTMLMediaElement::MozCaptureStreamUntilEnded(ErrorResult& aRv)
|
|||
MediaStreamGraph::GraphDriverType graphDriverType =
|
||||
HasAudio() ? MediaStreamGraph::AUDIO_THREAD_DRIVER
|
||||
: MediaStreamGraph::SYSTEM_THREAD_DRIVER;
|
||||
|
||||
nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!CanBeCaptured(false)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MediaStreamGraph* graph =
|
||||
MediaStreamGraph::GetInstance(graphDriverType, mAudioChannel);
|
||||
MediaStreamGraph::GetInstance(graphDriverType, mAudioChannel, window);
|
||||
|
||||
RefPtr<DOMMediaStream> stream =
|
||||
CaptureStreamInternal(true, false, graph);
|
||||
|
@ -4833,8 +4869,7 @@ public:
|
|||
mBlocked(false),
|
||||
mFinished(false),
|
||||
mMutex(aName),
|
||||
mPendingNotifyOutput(false),
|
||||
mAbstractMainThread(aElement->AbstractMainThread())
|
||||
mPendingNotifyOutput(false)
|
||||
{}
|
||||
void Forget()
|
||||
{
|
||||
|
@ -4902,14 +4937,12 @@ public:
|
|||
this,
|
||||
&StreamListener::DoNotifyUnblocked);
|
||||
}
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
event.forget());
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
|
||||
}
|
||||
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph) override
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
mAbstractMainThread,
|
||||
NewRunnableMethod(
|
||||
"dom::HTMLMediaElement::StreamListener::DoNotifyHaveCurrentData",
|
||||
this,
|
||||
|
@ -4923,7 +4956,6 @@ public:
|
|||
return;
|
||||
mPendingNotifyOutput = true;
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
mAbstractMainThread,
|
||||
NewRunnableMethod("dom::HTMLMediaElement::StreamListener::DoNotifyOutput",
|
||||
this,
|
||||
&StreamListener::DoNotifyOutput));
|
||||
|
@ -4939,7 +4971,6 @@ private:
|
|||
// mMutex protects the fields below; they can be accessed on any thread
|
||||
Mutex mMutex;
|
||||
bool mPendingNotifyOutput;
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
};
|
||||
|
||||
class HTMLMediaElement::MediaStreamTracksAvailableCallback:
|
||||
|
@ -7176,7 +7207,7 @@ HTMLMediaElement::AudioCaptureStreamChange(bool aCapture)
|
|||
uint64_t id = window->WindowID();
|
||||
MediaStreamGraph* msg =
|
||||
MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER,
|
||||
mAudioChannel);
|
||||
mAudioChannel, window);
|
||||
|
||||
if (GetSrcMediaStream()) {
|
||||
mCaptureStreamPort = msg->ConnectToCaptureStream(id, GetSrcMediaStream());
|
||||
|
|
|
@ -1266,6 +1266,9 @@ protected:
|
|||
// Anything we need to check after played success and not related with spec.
|
||||
void UpdateCustomPolicyAfterPlayed();
|
||||
|
||||
// True if this element can be captured, false otherwise.
|
||||
bool CanBeCaptured(bool aCaptureAudio);
|
||||
|
||||
class nsAsyncEventRunner;
|
||||
class nsNotifyAboutPlayingRunner;
|
||||
class nsResolveOrRejectPendingPlayPromisesRunner;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class RadioNodeList : public nsSimpleContentList
|
||||
class RadioNodeList final : public nsSimpleContentList
|
||||
{
|
||||
public:
|
||||
explicit RadioNodeList(HTMLFormElement* aForm) : nsSimpleContentList(aForm) { }
|
||||
|
|
|
@ -102,6 +102,17 @@ DateTimeInputTypeBase::HasBadInput() const
|
|||
return frame->HasBadInput();;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DateTimeInputTypeBase::MinMaxStepAttrChanged()
|
||||
{
|
||||
nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
|
||||
if (frame) {
|
||||
frame->OnMinMaxStepAttrChanged();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
DateTimeInputTypeBase::GetTimeFromMs(double aValue, uint16_t* aHours,
|
||||
uint16_t* aMinutes, uint16_t* aSeconds,
|
||||
|
|
|
@ -20,6 +20,8 @@ public:
|
|||
bool HasStepMismatch(bool aUseZeroIfValueNaN) const override;
|
||||
bool HasBadInput() const override;
|
||||
|
||||
nsresult MinMaxStepAttrChanged() override;
|
||||
|
||||
protected:
|
||||
explicit DateTimeInputTypeBase(mozilla::dom::HTMLInputElement* aInputElement)
|
||||
: InputType(aInputElement)
|
||||
|
|
|
@ -14,6 +14,12 @@ interface nsIDateTimeInputArea : nsISupports
|
|||
*/
|
||||
void notifyInputElementValueChanged();
|
||||
|
||||
/**
|
||||
* Called from DOM/Layout when input element min, max or step attribute has
|
||||
* changed.
|
||||
*/
|
||||
void notifyMinMaxStepAttrChanged();
|
||||
|
||||
/**
|
||||
* Called when date/time picker value has changed.
|
||||
*/
|
||||
|
|
|
@ -74,6 +74,8 @@ skip-if = os == "android"
|
|||
[test_input_textarea_set_value_no_scroll.html]
|
||||
[test_input_time_key_events.html]
|
||||
skip-if = os == "android"
|
||||
[test_input_time_sec_millisec_field.html]
|
||||
skip-if = os == "android"
|
||||
[test_input_types_pref.html]
|
||||
[test_input_typing_sanitization.html]
|
||||
[test_input_untrusted_key_events.html]
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1374967
|
||||
-->
|
||||
<head>
|
||||
<title>Test second and millisecond fields in input type=time</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1374967">Mozilla Bug 1374967</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<input id="input1" type="time">
|
||||
<input id="input2" type="time" value="12:30:40">
|
||||
<input id="input3" type="time" value="12:30:40.567">
|
||||
<input id="input4" type="time" step="1">
|
||||
<input id="input5" type="time" step="61">
|
||||
<input id="input6" type="time" step="120">
|
||||
<input id="input7" type="time" step="0.01">
|
||||
<input id="input8" type="time" step="0.001">
|
||||
<input id="input9" type="time" step="1.001">
|
||||
<input id="input10" type="time" min="01:30:05">
|
||||
<input id="input11" type="time" min="01:30:05.100">
|
||||
<input id="dummy">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(function() {
|
||||
test();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
const NUM_OF_FIELDS_DEFAULT = 3;
|
||||
const NUM_OF_FIELDS_WITH_SECOND = NUM_OF_FIELDS_DEFAULT + 1;
|
||||
const NUM_OF_FIELDS_WITH_MILLISEC = NUM_OF_FIELDS_WITH_SECOND + 1;
|
||||
|
||||
function countNumberOfFields(aElement) {
|
||||
is(aElement.type, "time", "Input element type should be 'time'");
|
||||
|
||||
let inputRect = aElement.getBoundingClientRect();
|
||||
let firstField_X = 15;
|
||||
let firstField_Y = inputRect.height / 2;
|
||||
|
||||
// Make sure to start on the first field.
|
||||
synthesizeMouse(aElement, firstField_X, firstField_Y, {});
|
||||
is(document.activeElement, aElement, "Input element should be focused");
|
||||
|
||||
let n = 0;
|
||||
while (document.activeElement == aElement) {
|
||||
n++;
|
||||
synthesizeKey("VK_TAB", {});
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
function test() {
|
||||
// Normal input time element.
|
||||
let elem = document.getElementById("input1");
|
||||
is(countNumberOfFields(elem), NUM_OF_FIELDS_DEFAULT, "Default input time");
|
||||
|
||||
// Dynamically changing the value with second part.
|
||||
elem.value = "10:20:30";
|
||||
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND,
|
||||
"Input time after changing value with second part");
|
||||
|
||||
// Dynamically changing the step to 1 millisecond.
|
||||
elem.step = "0.001";
|
||||
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC,
|
||||
"Input time after changing step to 1 millisecond");
|
||||
|
||||
// Input time with value with second part.
|
||||
elem = document.getElementById("input2");
|
||||
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND,
|
||||
"Input time with value with second part");
|
||||
|
||||
// Input time with value with second and millisecond part.
|
||||
elem = document.getElementById("input3");
|
||||
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC,
|
||||
"Input time with value with second and millisecond part");
|
||||
|
||||
// Input time with step set as 1 second.
|
||||
elem = document.getElementById("input4");
|
||||
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND,
|
||||
"Input time with step set as 1 second");
|
||||
|
||||
// Input time with step set as 61 seconds.
|
||||
elem = document.getElementById("input5");
|
||||
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND,
|
||||
"Input time with step set as 61 seconds");
|
||||
|
||||
// Input time with step set as 2 minutes.
|
||||
elem = document.getElementById("input6");
|
||||
is(countNumberOfFields(elem), NUM_OF_FIELDS_DEFAULT,
|
||||
"Input time with step set as 2 minutes");
|
||||
|
||||
// Input time with step set as 10 milliseconds.
|
||||
elem = document.getElementById("input7");
|
||||
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC,
|
||||
"Input time with step set as 10 milliseconds");
|
||||
|
||||
// Input time with step set as 100 milliseconds.
|
||||
elem = document.getElementById("input8");
|
||||
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC,
|
||||
"Input time with step set as 100 milliseconds");
|
||||
|
||||
// Input time with step set as 1001 milliseconds.
|
||||
elem = document.getElementById("input9");
|
||||
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC,
|
||||
"Input time with step set as 1001 milliseconds");
|
||||
|
||||
// Input time with min with second part and default step (60 seconds). Note
|
||||
// that step base is min, when there is a min.
|
||||
elem = document.getElementById("input10");
|
||||
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND,
|
||||
"Input time with min with second part");
|
||||
|
||||
// Input time with min with second and millisecond part and default step (60
|
||||
// seconds). Note that step base is min, when there is a min.
|
||||
elem = document.getElementById("input11");
|
||||
is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC,
|
||||
"Input time with min with second and millisecond part");
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -3061,11 +3061,9 @@ TabChild::ReinitRenderingForDeviceReset()
|
|||
InvalidateLayers();
|
||||
|
||||
RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
|
||||
ClientLayerManager* clm = lm->AsClientLayerManager();
|
||||
if (!clm) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (WebRenderLayerManager* wlm = lm->AsWebRenderLayerManager()) {
|
||||
wlm->DoDestroy(/* aIsSync */ true);
|
||||
} else if (ClientLayerManager* clm = lm->AsClientLayerManager()) {
|
||||
if (ShadowLayerForwarder* fwd = clm->AsShadowForwarder()) {
|
||||
// Force the LayerTransactionChild to synchronously shutdown. It is
|
||||
// okay to do this early, we'll simply stop sending messages. This
|
||||
|
@ -3073,6 +3071,9 @@ TabChild::ReinitRenderingForDeviceReset()
|
|||
// are trying to attach two layer trees to the same ID.
|
||||
fwd->SynchronouslyShutdown();
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Proceed with destroying and recreating the layer manager.
|
||||
ReinitRendering();
|
||||
|
|
|
@ -30,8 +30,11 @@ namespace mozilla
|
|||
// We are mixing to mono until PeerConnection can accept stereo
|
||||
static const uint32_t MONO = 1;
|
||||
|
||||
AudioCaptureStream::AudioCaptureStream(TrackID aTrackId, AbstractThread* aMainThread)
|
||||
: ProcessedMediaStream(aMainThread), mTrackId(aTrackId), mStarted(false), mTrackCreated(false)
|
||||
AudioCaptureStream::AudioCaptureStream(TrackID aTrackId)
|
||||
: ProcessedMediaStream()
|
||||
, mTrackId(aTrackId)
|
||||
, mStarted(false)
|
||||
, mTrackCreated(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_COUNT_CTOR(AudioCaptureStream);
|
||||
|
|
|
@ -24,7 +24,7 @@ class AudioCaptureStream : public ProcessedMediaStream,
|
|||
public MixerCallbackReceiver
|
||||
{
|
||||
public:
|
||||
AudioCaptureStream(TrackID aTrackId, AbstractThread* aMainThread);
|
||||
explicit AudioCaptureStream(TrackID aTrackId);
|
||||
virtual ~AudioCaptureStream();
|
||||
|
||||
void Start();
|
||||
|
|
|
@ -280,7 +280,8 @@ CanvasCaptureMediaStream::CreateSourceStream(nsPIDOMWindowInner* aWindow,
|
|||
RefPtr<CanvasCaptureMediaStream> stream = new CanvasCaptureMediaStream(aWindow, aCanvas);
|
||||
MediaStreamGraph* graph =
|
||||
MediaStreamGraph::GetInstance(MediaStreamGraph::SYSTEM_THREAD_DRIVER,
|
||||
AudioChannel::Normal);
|
||||
AudioChannel::Normal,
|
||||
aWindow);
|
||||
stream->InitSourceStream(graph);
|
||||
return stream.forget();
|
||||
}
|
||||
|
|
|
@ -143,7 +143,6 @@ class DOMMediaStream::OwnedStreamListener : public MediaStreamListener {
|
|||
public:
|
||||
explicit OwnedStreamListener(DOMMediaStream* aStream)
|
||||
: mStream(aStream)
|
||||
, mAbstractMainThread(aStream->mAbstractMainThread)
|
||||
{}
|
||||
|
||||
void Forget() { mStream = nullptr; }
|
||||
|
@ -224,7 +223,6 @@ public:
|
|||
{
|
||||
if (aTrackEvents & TrackEventCommand::TRACK_EVENT_CREATED) {
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
mAbstractMainThread,
|
||||
NewRunnableMethod<TrackID,
|
||||
MediaSegment::Type,
|
||||
RefPtr<MediaStream>,
|
||||
|
@ -238,7 +236,6 @@ public:
|
|||
aInputTrackID));
|
||||
} else if (aTrackEvents & TrackEventCommand::TRACK_EVENT_ENDED) {
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
mAbstractMainThread,
|
||||
NewRunnableMethod<RefPtr<MediaStream>, TrackID, TrackID>(
|
||||
"DOMMediaStream::OwnedStreamListener::DoNotifyTrackEnded",
|
||||
this,
|
||||
|
@ -252,8 +249,6 @@ public:
|
|||
private:
|
||||
// These fields may only be accessed on the main thread
|
||||
DOMMediaStream* mStream;
|
||||
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -265,7 +260,6 @@ class DOMMediaStream::PlaybackStreamListener : public MediaStreamListener {
|
|||
public:
|
||||
explicit PlaybackStreamListener(DOMMediaStream* aStream)
|
||||
: mStream(aStream)
|
||||
, mAbstractMainThread(aStream->mAbstractMainThread)
|
||||
{}
|
||||
|
||||
void Forget()
|
||||
|
@ -309,7 +303,6 @@ public:
|
|||
void NotifyFinishedTrackCreation(MediaStreamGraph* aGraph) override
|
||||
{
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
mAbstractMainThread,
|
||||
NewRunnableMethod(
|
||||
"DOMMediaStream::PlaybackStreamListener::DoNotifyFinishedTrackCreation",
|
||||
this,
|
||||
|
@ -322,7 +315,6 @@ public:
|
|||
{
|
||||
if (event == MediaStreamGraphEvent::EVENT_FINISHED) {
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
mAbstractMainThread,
|
||||
NewRunnableMethod(
|
||||
"DOMMediaStream::PlaybackStreamListener::DoNotifyFinished",
|
||||
this,
|
||||
|
@ -333,8 +325,6 @@ public:
|
|||
private:
|
||||
// These fields may only be accessed on the main thread
|
||||
DOMMediaStream* mStream;
|
||||
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
};
|
||||
|
||||
class DOMMediaStream::PlaybackTrackListener : public MediaStreamTrackConsumer
|
||||
|
@ -436,8 +426,7 @@ DOMMediaStream::DOMMediaStream(nsPIDOMWindowInner* aWindow,
|
|||
mTracksPendingRemoval(0), mTrackSourceGetter(aTrackSourceGetter),
|
||||
mPlaybackTrackListener(MakeAndAddRef<PlaybackTrackListener>(this)),
|
||||
mTracksCreated(false), mNotifiedOfMediaStreamGraphShutdown(false),
|
||||
mActive(false), mSetInactiveOnFinish(false),
|
||||
mAbstractMainThread(aWindow ? aWindow->GetDocGroup()->AbstractMainThreadFor(TaskCategory::Other) : nullptr)
|
||||
mActive(false), mSetInactiveOnFinish(false)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIUUIDGenerator> uuidgen =
|
||||
|
@ -570,7 +559,7 @@ DOMMediaStream::Constructor(const GlobalObject& aGlobal,
|
|||
MOZ_ASSERT(aTracks.IsEmpty());
|
||||
MediaStreamGraph* graph =
|
||||
MediaStreamGraph::GetInstance(MediaStreamGraph::SYSTEM_THREAD_DRIVER,
|
||||
AudioChannel::Normal);
|
||||
AudioChannel::Normal, ownerWindow);
|
||||
newStream->InitPlaybackStreamCommon(graph);
|
||||
}
|
||||
|
||||
|
@ -881,8 +870,7 @@ DOMMediaStream::SetInactiveOnFinish()
|
|||
void
|
||||
DOMMediaStream::InitSourceStream(MediaStreamGraph* aGraph)
|
||||
{
|
||||
MOZ_ASSERT(mAbstractMainThread);
|
||||
InitInputStreamCommon(aGraph->CreateSourceStream(mAbstractMainThread), aGraph);
|
||||
InitInputStreamCommon(aGraph->CreateSourceStream(), aGraph);
|
||||
InitOwnedStreamCommon(aGraph);
|
||||
InitPlaybackStreamCommon(aGraph);
|
||||
}
|
||||
|
@ -890,8 +878,7 @@ DOMMediaStream::InitSourceStream(MediaStreamGraph* aGraph)
|
|||
void
|
||||
DOMMediaStream::InitTrackUnionStream(MediaStreamGraph* aGraph)
|
||||
{
|
||||
MOZ_ASSERT(mAbstractMainThread);
|
||||
InitInputStreamCommon(aGraph->CreateTrackUnionStream(mAbstractMainThread), aGraph);
|
||||
InitInputStreamCommon(aGraph->CreateTrackUnionStream(), aGraph);
|
||||
InitOwnedStreamCommon(aGraph);
|
||||
InitPlaybackStreamCommon(aGraph);
|
||||
}
|
||||
|
@ -899,14 +886,13 @@ DOMMediaStream::InitTrackUnionStream(MediaStreamGraph* aGraph)
|
|||
void
|
||||
DOMMediaStream::InitAudioCaptureStream(nsIPrincipal* aPrincipal, MediaStreamGraph* aGraph)
|
||||
{
|
||||
MOZ_ASSERT(mAbstractMainThread);
|
||||
const TrackID AUDIO_TRACK = 1;
|
||||
|
||||
RefPtr<BasicTrackSource> audioCaptureSource =
|
||||
new BasicTrackSource(aPrincipal, MediaSourceEnum::AudioCapture);
|
||||
|
||||
AudioCaptureStream* audioCaptureStream =
|
||||
static_cast<AudioCaptureStream*>(aGraph->CreateAudioCaptureStream(AUDIO_TRACK, mAbstractMainThread));
|
||||
static_cast<AudioCaptureStream*>(aGraph->CreateAudioCaptureStream(AUDIO_TRACK));
|
||||
InitInputStreamCommon(audioCaptureStream, aGraph);
|
||||
InitOwnedStreamCommon(aGraph);
|
||||
InitPlaybackStreamCommon(aGraph);
|
||||
|
@ -930,10 +916,9 @@ DOMMediaStream::InitInputStreamCommon(MediaStream* aStream,
|
|||
void
|
||||
DOMMediaStream::InitOwnedStreamCommon(MediaStreamGraph* aGraph)
|
||||
{
|
||||
MOZ_ASSERT(mAbstractMainThread);
|
||||
MOZ_ASSERT(!mPlaybackStream, "Owned stream must be initialized before playback stream");
|
||||
|
||||
mOwnedStream = aGraph->CreateTrackUnionStream(mAbstractMainThread);
|
||||
mOwnedStream = aGraph->CreateTrackUnionStream();
|
||||
mOwnedStream->SetAutofinish(true);
|
||||
mOwnedStream->RegisterUser();
|
||||
if (mInputStream) {
|
||||
|
@ -948,8 +933,7 @@ DOMMediaStream::InitOwnedStreamCommon(MediaStreamGraph* aGraph)
|
|||
void
|
||||
DOMMediaStream::InitPlaybackStreamCommon(MediaStreamGraph* aGraph)
|
||||
{
|
||||
MOZ_ASSERT(mAbstractMainThread);
|
||||
mPlaybackStream = aGraph->CreateTrackUnionStream(mAbstractMainThread);
|
||||
mPlaybackStream = aGraph->CreateTrackUnionStream();
|
||||
mPlaybackStream->SetAutofinish(true);
|
||||
mPlaybackStream->RegisterUser();
|
||||
if (mOwnedStream) {
|
||||
|
@ -1576,7 +1560,7 @@ DOMHwMediaStream::CreateHwStream(nsPIDOMWindowInner* aWindow,
|
|||
|
||||
MediaStreamGraph* graph =
|
||||
MediaStreamGraph::GetInstance(MediaStreamGraph::SYSTEM_THREAD_DRIVER,
|
||||
AudioChannel::Normal);
|
||||
AudioChannel::Normal, aWindow);
|
||||
stream->InitSourceStream(graph);
|
||||
stream->Init(stream->GetInputStream(), aImage);
|
||||
|
||||
|
|
|
@ -590,8 +590,6 @@ public:
|
|||
// a dead pointer. Main thread only.
|
||||
void UnregisterTrackListener(TrackListener* aListener);
|
||||
|
||||
AbstractThread* AbstractMainThread() const { return mAbstractMainThread; }
|
||||
|
||||
protected:
|
||||
virtual ~DOMMediaStream();
|
||||
|
||||
|
@ -756,7 +754,6 @@ private:
|
|||
nsCOMPtr<nsIPrincipal> mVideoPrincipal;
|
||||
nsTArray<dom::PrincipalChangeObserver<DOMMediaStream>*> mPrincipalChangeObservers;
|
||||
CORSMode mCORSMode;
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(DOMMediaStream,
|
||||
|
|
|
@ -1157,8 +1157,6 @@ AudioCallbackDriver::DeviceChangedCallback() {
|
|||
void
|
||||
AudioCallbackDriver::SetMicrophoneActive(bool aActive)
|
||||
{
|
||||
MonitorAutoLock mon(mGraphImpl->GetMonitor());
|
||||
|
||||
mMicrophoneActive = aActive;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
|
|
|
@ -536,7 +536,7 @@ private:
|
|||
/**
|
||||
* True if microphone is being used by this process. This is synchronized by
|
||||
* the graph's monitor. */
|
||||
bool mMicrophoneActive;
|
||||
Atomic<bool> mMicrophoneActive;
|
||||
/* True if this driver was created from a driver created because of a previous
|
||||
* AudioCallbackDriver failure. */
|
||||
bool mFromFallback;
|
||||
|
|
|
@ -1068,7 +1068,7 @@ public:
|
|||
: MediaStreamGraph::SYSTEM_THREAD_DRIVER;
|
||||
MediaStreamGraph* msg =
|
||||
MediaStreamGraph::GetInstance(graphDriverType,
|
||||
dom::AudioChannel::Normal);
|
||||
dom::AudioChannel::Normal, window);
|
||||
|
||||
RefPtr<DOMMediaStream> domStream;
|
||||
RefPtr<SourceMediaStream> stream;
|
||||
|
@ -1084,8 +1084,7 @@ public:
|
|||
domStream =
|
||||
DOMMediaStream::CreateAudioCaptureStreamAsInput(window, principal, msg);
|
||||
|
||||
stream = msg->CreateSourceStream(
|
||||
globalWindow->AbstractMainThreadFor(TaskCategory::Other)); // Placeholder
|
||||
stream = msg->CreateSourceStream(); // Placeholder
|
||||
msg->RegisterCaptureStreamForWindow(
|
||||
mWindowID, domStream->GetInputStream()->AsProcessedStream());
|
||||
window->SetAudioCapture(true);
|
||||
|
@ -3669,7 +3668,7 @@ SourceListener::StopSharing()
|
|||
window->SetAudioCapture(false);
|
||||
MediaStreamGraph* graph =
|
||||
MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER,
|
||||
dom::AudioChannel::Normal);
|
||||
dom::AudioChannel::Normal, window);
|
||||
graph->UnregisterCaptureStreamForWindow(windowID);
|
||||
mStream->Destroy();
|
||||
}
|
||||
|
|
|
@ -433,7 +433,6 @@ public:
|
|||
, mIsStartEventFired(false)
|
||||
, mNeedSessionEndTask(true)
|
||||
, mSelectedVideoTrackID(TRACK_NONE)
|
||||
, mAbstractMainThread(aRecorder->mAbstractMainThread)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -489,7 +488,7 @@ public:
|
|||
// Create a Track Union Stream
|
||||
MediaStreamGraph* gm = mRecorder->GetSourceMediaStream()->Graph();
|
||||
TrackRate trackRate = gm->GraphRate();
|
||||
mTrackUnionStream = gm->CreateTrackUnionStream(mAbstractMainThread);
|
||||
mTrackUnionStream = gm->CreateTrackUnionStream();
|
||||
MOZ_ASSERT(mTrackUnionStream, "CreateTrackUnionStream failed");
|
||||
|
||||
mTrackUnionStream->SetAutofinish(true);
|
||||
|
@ -952,7 +951,6 @@ private:
|
|||
// Main thread only.
|
||||
bool mNeedSessionEndTask;
|
||||
TrackID mSelectedVideoTrackID;
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(MediaRecorder::Session, nsIObserver)
|
||||
|
@ -971,7 +969,6 @@ MediaRecorder::MediaRecorder(DOMMediaStream& aSourceMediaStream,
|
|||
nsPIDOMWindowInner* aOwnerWindow)
|
||||
: DOMEventTargetHelper(aOwnerWindow)
|
||||
, mState(RecordingState::Inactive)
|
||||
, mAbstractMainThread(aSourceMediaStream.AbstractMainThread())
|
||||
{
|
||||
MOZ_ASSERT(aOwnerWindow);
|
||||
MOZ_ASSERT(aOwnerWindow->IsInnerWindow());
|
||||
|
@ -985,7 +982,6 @@ MediaRecorder::MediaRecorder(AudioNode& aSrcAudioNode,
|
|||
nsPIDOMWindowInner* aOwnerWindow)
|
||||
: DOMEventTargetHelper(aOwnerWindow)
|
||||
, mState(RecordingState::Inactive)
|
||||
, mAbstractMainThread(aSrcAudioNode.AbstractMainThread())
|
||||
{
|
||||
MOZ_ASSERT(aOwnerWindow);
|
||||
MOZ_ASSERT(aOwnerWindow->IsInnerWindow());
|
||||
|
|
|
@ -159,7 +159,6 @@ protected:
|
|||
uint32_t mVideoBitsPerSecond;
|
||||
uint32_t mBitsPerSecond;
|
||||
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
private:
|
||||
// Register MediaRecorder into Document to listen the activity changes.
|
||||
void RegisterActivityObserver();
|
||||
|
|
|
@ -580,26 +580,6 @@ MediaStreamGraphImpl::UpdateStreamOrder()
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_WEBRTC
|
||||
// Whenever we change AEC state, notify the current driver, which also
|
||||
// will sample the state when the driver inits
|
||||
if (shouldAEC && !mFarendObserverRef && gFarendObserver) {
|
||||
mFarendObserverRef = gFarendObserver;
|
||||
mMixer.AddCallback(mFarendObserverRef);
|
||||
if (CurrentDriver()->AsAudioCallbackDriver()) {
|
||||
CurrentDriver()->AsAudioCallbackDriver()->SetMicrophoneActive(true);
|
||||
}
|
||||
} else if (!shouldAEC && mFarendObserverRef){
|
||||
if (mMixer.FindCallback(mFarendObserverRef)) {
|
||||
mMixer.RemoveCallback(mFarendObserverRef);
|
||||
mFarendObserverRef = nullptr;
|
||||
if (CurrentDriver()->AsAudioCallbackDriver()) {
|
||||
CurrentDriver()->AsAudioCallbackDriver()->SetMicrophoneActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!mStreamOrderDirty) {
|
||||
return;
|
||||
}
|
||||
|
@ -1009,6 +989,7 @@ MediaStreamGraphImpl::OpenAudioInputImpl(int aID,
|
|||
MonitorAutoLock mon(mMonitor);
|
||||
if (mLifecycleState == LIFECYCLE_RUNNING) {
|
||||
AudioCallbackDriver* driver = new AudioCallbackDriver(this);
|
||||
driver->SetMicrophoneActive(true);
|
||||
LOG(
|
||||
LogLevel::Debug,
|
||||
("OpenAudioInput: starting new AudioCallbackDriver(input) %p", driver));
|
||||
|
@ -1031,9 +1012,12 @@ MediaStreamGraphImpl::OpenAudioInput(int aID,
|
|||
{
|
||||
// So, so, so annoying. Can't AppendMessage except on Mainthread
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_DispatchToMainThread(WrapRunnable(this,
|
||||
RefPtr<nsIRunnable> runnable =
|
||||
WrapRunnable(this,
|
||||
&MediaStreamGraphImpl::OpenAudioInput,
|
||||
aID, RefPtr<AudioDataListener>(aListener)));
|
||||
aID,
|
||||
RefPtr<AudioDataListener>(aListener));
|
||||
mAbstractMainThread->Dispatch(runnable.forget());
|
||||
return NS_OK;
|
||||
}
|
||||
class Message : public ControlMessage {
|
||||
|
@ -1101,9 +1085,11 @@ MediaStreamGraphImpl::CloseAudioInput(AudioDataListener *aListener)
|
|||
{
|
||||
// So, so, so annoying. Can't AppendMessage except on Mainthread
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_DispatchToMainThread(WrapRunnable(this,
|
||||
RefPtr<nsIRunnable> runnable =
|
||||
WrapRunnable(this,
|
||||
&MediaStreamGraphImpl::CloseAudioInput,
|
||||
RefPtr<AudioDataListener>(aListener)));
|
||||
RefPtr<AudioDataListener>(aListener));
|
||||
mAbstractMainThread->Dispatch(runnable.forget());
|
||||
return;
|
||||
}
|
||||
class Message : public ControlMessage {
|
||||
|
@ -1120,7 +1106,6 @@ MediaStreamGraphImpl::CloseAudioInput(AudioDataListener *aListener)
|
|||
this->AppendMessage(MakeUnique<Message>(this, aListener));
|
||||
}
|
||||
|
||||
|
||||
// All AudioInput listeners get the same speaker data (at least for now).
|
||||
void
|
||||
MediaStreamGraph::NotifyOutputData(AudioDataValue* aBuffer, size_t aFrames,
|
||||
|
@ -1723,13 +1708,16 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG)
|
|||
LOG(LogLevel::Debug,
|
||||
("Sending MediaStreamGraphShutDownRunnable %p", this));
|
||||
nsCOMPtr<nsIRunnable> event = new MediaStreamGraphShutDownRunnable(this );
|
||||
NS_DispatchToMainThread(event.forget());
|
||||
mAbstractMainThread->Dispatch(event.forget());
|
||||
|
||||
LOG(LogLevel::Debug, ("Disconnecting MediaStreamGraph %p", this));
|
||||
MediaStreamGraphImpl* graph;
|
||||
if (gGraphs.Get(uint32_t(mAudioChannel), &graph) && graph == this) {
|
||||
// null out gGraph if that's the graph being shut down
|
||||
gGraphs.Remove(uint32_t(mAudioChannel));
|
||||
|
||||
// Find the graph in the hash table and remove it.
|
||||
for (auto iter = gGraphs.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (iter.UserData() == this) {
|
||||
iter.Remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1803,7 +1791,7 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG)
|
|||
// we have outstanding DOM objects that may need it.
|
||||
mLifecycleState = LIFECYCLE_WAITING_FOR_THREAD_SHUTDOWN;
|
||||
nsCOMPtr<nsIRunnable> event = new MediaStreamGraphShutDownRunnable(this);
|
||||
NS_DispatchToMainThread(event.forget());
|
||||
mAbstractMainThread->Dispatch(event.forget());
|
||||
}
|
||||
|
||||
mDetectedNotRunning = mLifecycleState > LIFECYCLE_RUNNING;
|
||||
|
@ -1851,7 +1839,7 @@ MediaStreamGraphImpl::EnsureStableStateEventPosted()
|
|||
return;
|
||||
mPostedRunInStableStateEvent = true;
|
||||
nsCOMPtr<nsIRunnable> event = new MediaStreamGraphStableStateRunnable(this, true);
|
||||
NS_DispatchToMainThread(event.forget());
|
||||
mAbstractMainThread->Dispatch(event.forget());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1881,9 +1869,12 @@ MediaStreamGraphImpl::AppendMessage(UniquePtr<ControlMessage> aMessage)
|
|||
if (IsEmpty() &&
|
||||
mLifecycleState >= LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION) {
|
||||
|
||||
MediaStreamGraphImpl* graph;
|
||||
if (gGraphs.Get(uint32_t(mAudioChannel), &graph) && graph == this) {
|
||||
gGraphs.Remove(uint32_t(mAudioChannel));
|
||||
// Find the graph in the hash table and remove it.
|
||||
for (auto iter = gGraphs.Iter(); !iter.Done(); iter.Next()) {
|
||||
if (iter.UserData() == this) {
|
||||
iter.Remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Destroy();
|
||||
|
@ -1895,7 +1886,13 @@ MediaStreamGraphImpl::AppendMessage(UniquePtr<ControlMessage> aMessage)
|
|||
EnsureRunInStableState();
|
||||
}
|
||||
|
||||
MediaStream::MediaStream(AbstractThread* aMainThread)
|
||||
void
|
||||
MediaStreamGraphImpl::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable)
|
||||
{
|
||||
mAbstractMainThread->Dispatch(Move(aRunnable));
|
||||
}
|
||||
|
||||
MediaStream::MediaStream()
|
||||
: mTracksStartTime(0)
|
||||
, mStartBlocking(GRAPH_TIME_MAX)
|
||||
, mSuspendedCount(0)
|
||||
|
@ -1911,7 +1908,6 @@ MediaStream::MediaStream(AbstractThread* aMainThread)
|
|||
, mNrOfMainThreadUsers(0)
|
||||
, mGraph(nullptr)
|
||||
, mAudioChannelType(dom::AudioChannel::Normal)
|
||||
, mAbstractMainThread(aMainThread)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaStream);
|
||||
}
|
||||
|
@ -2559,17 +2555,13 @@ MediaStream::RunAfterPendingUpdates(already_AddRefed<nsIRunnable> aRunnable)
|
|||
|
||||
class Message : public ControlMessage {
|
||||
public:
|
||||
Message(MediaStream* aStream,
|
||||
already_AddRefed<nsIRunnable> aRunnable,
|
||||
AbstractThread* aMainThread)
|
||||
Message(MediaStream* aStream, already_AddRefed<nsIRunnable> aRunnable)
|
||||
: ControlMessage(aStream)
|
||||
, mRunnable(aRunnable)
|
||||
, mAbstractMainThread(aMainThread)
|
||||
{}
|
||||
void Run() override
|
||||
{
|
||||
mStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
mStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
mRunnable.forget());
|
||||
}
|
||||
void RunDuringShutdown() override
|
||||
|
@ -2577,15 +2569,13 @@ MediaStream::RunAfterPendingUpdates(already_AddRefed<nsIRunnable> aRunnable)
|
|||
// Don't run mRunnable now as it may call AppendMessage() which would
|
||||
// assume that there are no remaining controlMessagesToRunDuringShutdown.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_DispatchToCurrentThread(mRunnable);
|
||||
mStream->GraphImpl()->Dispatch(mRunnable.forget());
|
||||
}
|
||||
private:
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
};
|
||||
|
||||
graph->AppendMessage(
|
||||
MakeUnique<Message>(this, runnable.forget(), mAbstractMainThread));
|
||||
graph->AppendMessage(MakeUnique<Message>(this, runnable.forget()));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2697,16 +2687,16 @@ MediaStream::AddMainThreadListener(MainThreadMediaStreamListener* aListener)
|
|||
};
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new NotifyRunnable(this);
|
||||
Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable.forget())));
|
||||
GraphImpl()->Dispatch(runnable.forget());
|
||||
}
|
||||
|
||||
SourceMediaStream::SourceMediaStream(AbstractThread* aMainThread) :
|
||||
MediaStream(aMainThread),
|
||||
mMutex("mozilla::media::SourceMediaStream"),
|
||||
mUpdateKnownTracksTime(0),
|
||||
mPullEnabled(false),
|
||||
mUpdateFinished(false),
|
||||
mNeedsMixing(false)
|
||||
SourceMediaStream::SourceMediaStream()
|
||||
: MediaStream()
|
||||
, mMutex("mozilla::media::SourceMediaStream")
|
||||
, mUpdateKnownTracksTime(0)
|
||||
, mPullEnabled(false)
|
||||
, mUpdateFinished(false)
|
||||
, mNeedsMixing(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -3312,17 +3302,19 @@ MediaInputPort::BlockSourceTrackId(TrackID aTrackId, BlockingMode aBlockingMode)
|
|||
Message(MediaInputPort* aPort,
|
||||
TrackID aTrackId,
|
||||
BlockingMode aBlockingMode,
|
||||
already_AddRefed<nsIRunnable> aRunnable,
|
||||
AbstractThread* aMainThread)
|
||||
: ControlMessage(aPort->GetDestination()),
|
||||
mPort(aPort), mTrackId(aTrackId), mBlockingMode(aBlockingMode),
|
||||
mRunnable(aRunnable), mAbstractMainThread(aMainThread) {}
|
||||
already_AddRefed<nsIRunnable> aRunnable)
|
||||
: ControlMessage(aPort->GetDestination())
|
||||
, mPort(aPort)
|
||||
, mTrackId(aTrackId)
|
||||
, mBlockingMode(aBlockingMode)
|
||||
, mRunnable(aRunnable)
|
||||
{
|
||||
}
|
||||
void Run() override
|
||||
{
|
||||
mPort->BlockSourceTrackIdImpl(mTrackId, mBlockingMode);
|
||||
if (mRunnable) {
|
||||
mStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
mStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
mRunnable.forget());
|
||||
}
|
||||
}
|
||||
|
@ -3334,7 +3326,6 @@ MediaInputPort::BlockSourceTrackId(TrackID aTrackId, BlockingMode aBlockingMode)
|
|||
TrackID mTrackId;
|
||||
BlockingMode mBlockingMode;
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
};
|
||||
|
||||
MOZ_ASSERT(IsTrackIDExplicit(aTrackId),
|
||||
|
@ -3346,9 +3337,8 @@ MediaInputPort::BlockSourceTrackId(TrackID aTrackId, BlockingMode aBlockingMode)
|
|||
pledge->Resolve(true);
|
||||
return NS_OK;
|
||||
});
|
||||
GraphImpl()->AppendMessage(MakeUnique<Message>(this, aTrackId, aBlockingMode,
|
||||
runnable.forget(),
|
||||
mAbstractMainThread));
|
||||
GraphImpl()->AppendMessage(
|
||||
MakeUnique<Message>(this, aTrackId, aBlockingMode, runnable.forget()));
|
||||
return pledge.forget();
|
||||
}
|
||||
|
||||
|
@ -3386,9 +3376,8 @@ ProcessedMediaStream::AllocateInputPort(MediaStream* aStream, TrackID aTrackID,
|
|||
"Only TRACK_ANY and explicit ID are allowed for destination track");
|
||||
MOZ_ASSERT(aTrackID != TRACK_ANY || aDestTrackID == TRACK_ANY,
|
||||
"Generic MediaInputPort cannot produce a single destination track");
|
||||
RefPtr<MediaInputPort> port =
|
||||
new MediaInputPort(aStream, aTrackID, this, aDestTrackID,
|
||||
aInputNumber, aOutputNumber, mAbstractMainThread);
|
||||
RefPtr<MediaInputPort> port = new MediaInputPort(
|
||||
aStream, aTrackID, this, aDestTrackID, aInputNumber, aOutputNumber);
|
||||
if (aBlockedTracks) {
|
||||
for (TrackID trackID : *aBlockedTracks) {
|
||||
port->BlockSourceTrackIdImpl(trackID, BlockingMode::CREATION);
|
||||
|
@ -3450,7 +3439,8 @@ ProcessedMediaStream::DestroyImpl()
|
|||
|
||||
MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
|
||||
TrackRate aSampleRate,
|
||||
dom::AudioChannel aChannel)
|
||||
dom::AudioChannel aChannel,
|
||||
AbstractThread* aMainThread)
|
||||
: MediaStreamGraph(aSampleRate)
|
||||
, mPortCount(0)
|
||||
, mInputWanted(false)
|
||||
|
@ -3470,6 +3460,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
|
|||
, mNonRealtimeProcessing(false)
|
||||
, mStreamOrderDirty(false)
|
||||
, mLatencyLog(AsyncLatencyLogger::Get())
|
||||
, mAbstractMainThread(aMainThread)
|
||||
#ifdef MOZ_WEBRTC
|
||||
, mFarendObserverRef(nullptr)
|
||||
#endif
|
||||
|
@ -3495,6 +3486,13 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
|
|||
RegisterWeakAsyncMemoryReporter(this);
|
||||
}
|
||||
|
||||
AbstractThread*
|
||||
MediaStreamGraph::AbstractMainThread()
|
||||
{
|
||||
MOZ_ASSERT(static_cast<MediaStreamGraphImpl*>(this)->mAbstractMainThread);
|
||||
return static_cast<MediaStreamGraphImpl*>(this)->mAbstractMainThread;
|
||||
}
|
||||
|
||||
void
|
||||
MediaStreamGraphImpl::Destroy()
|
||||
{
|
||||
|
@ -3505,16 +3503,36 @@ MediaStreamGraphImpl::Destroy()
|
|||
mSelfRef = nullptr;
|
||||
}
|
||||
|
||||
static
|
||||
uint32_t ChannelAndWindowToHash(dom::AudioChannel aChannel,
|
||||
nsPIDOMWindowInner* aWindow)
|
||||
{
|
||||
uint32_t hashkey = 0;
|
||||
|
||||
hashkey = AddToHash(hashkey, static_cast<uint32_t>(aChannel));
|
||||
hashkey = AddToHash(hashkey, aWindow);
|
||||
|
||||
return hashkey;
|
||||
}
|
||||
|
||||
MediaStreamGraph*
|
||||
MediaStreamGraph::GetInstance(MediaStreamGraph::GraphDriverType aGraphDriverRequested,
|
||||
dom::AudioChannel aChannel)
|
||||
dom::AudioChannel aChannel,
|
||||
nsPIDOMWindowInner* aWindow)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Main thread only");
|
||||
|
||||
uint32_t channel = static_cast<uint32_t>(aChannel);
|
||||
MediaStreamGraphImpl* graph = nullptr;
|
||||
|
||||
if (!gGraphs.Get(channel, &graph)) {
|
||||
// We hash the AudioChannel and the nsPIDOMWindowInner together to form a key
|
||||
// to the gloabl MediaStreamGraph hashtable. Effectively, this means there is
|
||||
// a graph per document and AudioChannel.
|
||||
|
||||
|
||||
uint32_t hashkey = ChannelAndWindowToHash(aChannel, aWindow);
|
||||
|
||||
if (!gGraphs.Get(hashkey, &graph)) {
|
||||
if (!gMediaStreamGraphShutdownBlocker) {
|
||||
|
||||
class Blocker : public media::ShutdownBlocker
|
||||
|
@ -3550,30 +3568,41 @@ MediaStreamGraph::GetInstance(MediaStreamGraph::GraphDriverType aGraphDriverRequ
|
|||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
AbstractThread* mainThread;
|
||||
if (aWindow) {
|
||||
nsCOMPtr<nsIGlobalObject> parentObject = do_QueryInterface(aWindow);
|
||||
mainThread = parentObject->AbstractMainThreadFor(TaskCategory::Other);
|
||||
} else {
|
||||
// Uncommon case, only for some old configuration of webspeech.
|
||||
mainThread = AbstractThread::MainThread();
|
||||
}
|
||||
graph = new MediaStreamGraphImpl(aGraphDriverRequested,
|
||||
CubebUtils::PreferredSampleRate(),
|
||||
aChannel);
|
||||
aChannel,
|
||||
mainThread);
|
||||
|
||||
gGraphs.Put(channel, graph);
|
||||
gGraphs.Put(hashkey, graph);
|
||||
|
||||
LOG(LogLevel::Debug,
|
||||
("Starting up MediaStreamGraph %p for channel %s",
|
||||
graph,
|
||||
AudioChannelValues::strings[channel].value));
|
||||
("Starting up MediaStreamGraph %p for channel %s and window %p",
|
||||
graph, AudioChannelValues::strings[channel].value, aWindow));
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
MediaStreamGraph*
|
||||
MediaStreamGraph::CreateNonRealtimeInstance(TrackRate aSampleRate)
|
||||
MediaStreamGraph::CreateNonRealtimeInstance(TrackRate aSampleRate,
|
||||
nsPIDOMWindowInner* aWindow)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Main thread only");
|
||||
|
||||
MediaStreamGraphImpl* graph =
|
||||
new MediaStreamGraphImpl(OFFLINE_THREAD_DRIVER,
|
||||
nsCOMPtr<nsIGlobalObject> parentObject = do_QueryInterface(aWindow);
|
||||
MediaStreamGraphImpl* graph = new MediaStreamGraphImpl(
|
||||
OFFLINE_THREAD_DRIVER,
|
||||
aSampleRate,
|
||||
AudioChannel::Normal);
|
||||
AudioChannel::Normal,
|
||||
parentObject->AbstractMainThreadFor(TaskCategory::Other));
|
||||
|
||||
LOG(LogLevel::Debug, ("Starting up Offline MediaStreamGraph %p", graph));
|
||||
|
||||
|
@ -3693,7 +3722,7 @@ MediaStreamGraphImpl::CollectSizesForMemoryReport(
|
|||
}
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(runnable.forget());
|
||||
mAbstractMainThread->Dispatch(runnable.forget());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3744,25 +3773,25 @@ FinishCollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
|
|||
}
|
||||
|
||||
SourceMediaStream*
|
||||
MediaStreamGraph::CreateSourceStream(AbstractThread* aMainThread)
|
||||
MediaStreamGraph::CreateSourceStream()
|
||||
{
|
||||
SourceMediaStream* stream = new SourceMediaStream(aMainThread);
|
||||
SourceMediaStream* stream = new SourceMediaStream();
|
||||
AddStream(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
ProcessedMediaStream*
|
||||
MediaStreamGraph::CreateTrackUnionStream(AbstractThread* aMainThread)
|
||||
MediaStreamGraph::CreateTrackUnionStream()
|
||||
{
|
||||
TrackUnionStream* stream = new TrackUnionStream(aMainThread);
|
||||
TrackUnionStream* stream = new TrackUnionStream();
|
||||
AddStream(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
ProcessedMediaStream*
|
||||
MediaStreamGraph::CreateAudioCaptureStream(TrackID aTrackId, AbstractThread* aMainThread)
|
||||
MediaStreamGraph::CreateAudioCaptureStream(TrackID aTrackId)
|
||||
{
|
||||
AudioCaptureStream* stream = new AudioCaptureStream(aTrackId, aMainThread);
|
||||
AudioCaptureStream* stream = new AudioCaptureStream(aTrackId);
|
||||
AddStream(stream);
|
||||
return stream;
|
||||
}
|
||||
|
@ -3817,11 +3846,11 @@ MediaStreamGraph::NotifyWhenGraphStarted(AudioNodeStream* aStream)
|
|||
if (graphImpl->CurrentDriver()->AsAudioCallbackDriver()) {
|
||||
nsCOMPtr<nsIRunnable> event = new dom::StateChangeTask(
|
||||
mStream->AsAudioNodeStream(), nullptr, AudioContextState::Running);
|
||||
NS_DispatchToMainThread(event.forget());
|
||||
graphImpl->Dispatch(event.forget());
|
||||
} else {
|
||||
nsCOMPtr<nsIRunnable> event = new GraphStartedRunnable(
|
||||
mStream->AsAudioNodeStream(), mStream->Graph());
|
||||
NS_DispatchToMainThread(event.forget());
|
||||
graphImpl->Dispatch(event.forget());
|
||||
}
|
||||
}
|
||||
void RunDuringShutdown() override
|
||||
|
@ -3920,7 +3949,7 @@ MediaStreamGraphImpl::AudioContextOperationCompleted(MediaStream* aStream,
|
|||
|
||||
nsCOMPtr<nsIRunnable> event = new dom::StateChangeTask(
|
||||
aStream->AsAudioNodeStream(), aPromise, state);
|
||||
NS_DispatchToMainThread(event.forget());
|
||||
mAbstractMainThread->Dispatch(event.forget());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -4165,14 +4194,12 @@ MediaStreamGraphImpl::ConnectToCaptureStream(uint64_t aWindowId,
|
|||
}
|
||||
|
||||
void
|
||||
MediaStreamGraph::
|
||||
DispatchToMainThreadAfterStreamStateUpdate(AbstractThread* aMainThread,
|
||||
MediaStreamGraph::DispatchToMainThreadAfterStreamStateUpdate(
|
||||
already_AddRefed<nsIRunnable> aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(aMainThread);
|
||||
AssertOnGraphThreadOrNotRunning();
|
||||
*mPendingUpdateRunnables.AppendElement() =
|
||||
aMainThread->CreateDirectTaskDrainer(Move(aRunnable));
|
||||
AbstractMainThread()->CreateDirectTaskDrainer(Move(aRunnable));
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include <speex/speex_resampler.h>
|
||||
|
||||
class nsIRunnable;
|
||||
class nsIGlobalObject;
|
||||
class nsPIDOMWindowInner;
|
||||
|
||||
template <>
|
||||
class nsAutoRefTraits<SpeexResamplerState> : public nsPointerRefTraits<SpeexResamplerState>
|
||||
|
@ -75,7 +77,6 @@ namespace media {
|
|||
* reprocess it. This is triggered automatically by the MediaStreamGraph.
|
||||
*/
|
||||
|
||||
class AbstractThread;
|
||||
class AudioNodeEngine;
|
||||
class AudioNodeExternalInputStream;
|
||||
class AudioNodeStream;
|
||||
|
@ -253,7 +254,7 @@ class MediaStream : public mozilla::LinkedListElement<MediaStream>
|
|||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStream)
|
||||
|
||||
explicit MediaStream(AbstractThread* aMainThread);
|
||||
explicit MediaStream();
|
||||
|
||||
protected:
|
||||
// Protected destructor, to discourage deletion outside of Release():
|
||||
|
@ -663,8 +664,6 @@ protected:
|
|||
MediaStreamGraphImpl* mGraph;
|
||||
|
||||
dom::AudioChannel mAudioChannelType;
|
||||
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -676,7 +675,7 @@ protected:
|
|||
class SourceMediaStream : public MediaStream
|
||||
{
|
||||
public:
|
||||
explicit SourceMediaStream(AbstractThread* aMainThread);
|
||||
explicit SourceMediaStream();
|
||||
|
||||
SourceMediaStream* AsSourceStream() override { return this; }
|
||||
|
||||
|
@ -957,10 +956,12 @@ class MediaInputPort final
|
|||
{
|
||||
private:
|
||||
// Do not call this constructor directly. Instead call aDest->AllocateInputPort.
|
||||
MediaInputPort(MediaStream* aSource, TrackID& aSourceTrack,
|
||||
ProcessedMediaStream* aDest, TrackID& aDestTrack,
|
||||
uint16_t aInputNumber, uint16_t aOutputNumber,
|
||||
AbstractThread* aMainThread)
|
||||
MediaInputPort(MediaStream* aSource,
|
||||
TrackID& aSourceTrack,
|
||||
ProcessedMediaStream* aDest,
|
||||
TrackID& aDestTrack,
|
||||
uint16_t aInputNumber,
|
||||
uint16_t aOutputNumber)
|
||||
: mSource(aSource)
|
||||
, mSourceTrack(aSourceTrack)
|
||||
, mDest(aDest)
|
||||
|
@ -968,7 +969,6 @@ private:
|
|||
, mInputNumber(aInputNumber)
|
||||
, mOutputNumber(aOutputNumber)
|
||||
, mGraph(nullptr)
|
||||
, mAbstractMainThread(aMainThread)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaInputPort);
|
||||
}
|
||||
|
@ -1111,8 +1111,6 @@ private:
|
|||
|
||||
// Our media stream graph
|
||||
MediaStreamGraphImpl* mGraph;
|
||||
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1123,8 +1121,10 @@ private:
|
|||
class ProcessedMediaStream : public MediaStream
|
||||
{
|
||||
public:
|
||||
explicit ProcessedMediaStream(AbstractThread* aMainThread)
|
||||
: MediaStream(aMainThread), mAutofinish(false), mCycleMarker(0)
|
||||
explicit ProcessedMediaStream()
|
||||
: MediaStream()
|
||||
, mAutofinish(false)
|
||||
, mCycleMarker(0)
|
||||
{}
|
||||
|
||||
// Control API.
|
||||
|
@ -1248,7 +1248,7 @@ protected:
|
|||
};
|
||||
|
||||
/**
|
||||
* There can be multiple MediaStreamGraph per process: one per AudioChannel.
|
||||
* There is a single MediaStreamGraph per window.
|
||||
* Additionaly, each OfflineAudioContext object creates its own MediaStreamGraph
|
||||
* object too..
|
||||
*/
|
||||
|
@ -1275,8 +1275,16 @@ public:
|
|||
|
||||
// Main thread only
|
||||
static MediaStreamGraph* GetInstance(GraphDriverType aGraphDriverRequested,
|
||||
dom::AudioChannel aChannel);
|
||||
static MediaStreamGraph* CreateNonRealtimeInstance(TrackRate aSampleRate);
|
||||
dom::AudioChannel aChannel,
|
||||
nsPIDOMWindowInner* aWindow);
|
||||
static MediaStreamGraph* CreateNonRealtimeInstance(
|
||||
TrackRate aSampleRate,
|
||||
nsPIDOMWindowInner* aWindowId);
|
||||
|
||||
// Return the correct main thread for this graph. This always returns
|
||||
// something that is valid. Thread safe.
|
||||
AbstractThread* AbstractMainThread();
|
||||
|
||||
// Idempotent
|
||||
static void DestroyNonRealtimeInstance(MediaStreamGraph* aGraph);
|
||||
|
||||
|
@ -1291,7 +1299,7 @@ public:
|
|||
* Create a stream that a media decoder (or some other source of
|
||||
* media data, such as a camera) can write to.
|
||||
*/
|
||||
SourceMediaStream* CreateSourceStream(AbstractThread* aMainThread);
|
||||
SourceMediaStream* CreateSourceStream();
|
||||
/**
|
||||
* Create a stream that will form the union of the tracks of its input
|
||||
* streams.
|
||||
|
@ -1306,12 +1314,11 @@ public:
|
|||
* TODO at some point we will probably need to add API to select
|
||||
* particular tracks of each input stream.
|
||||
*/
|
||||
ProcessedMediaStream* CreateTrackUnionStream(AbstractThread* aMainThread);
|
||||
ProcessedMediaStream* CreateTrackUnionStream();
|
||||
/**
|
||||
* Create a stream that will mix all its audio input.
|
||||
*/
|
||||
ProcessedMediaStream* CreateAudioCaptureStream(TrackID aTrackId,
|
||||
AbstractThread* aMainThread);
|
||||
ProcessedMediaStream* CreateAudioCaptureStream(TrackID aTrackId);
|
||||
|
||||
/**
|
||||
* Add a new stream to the graph. Main thread.
|
||||
|
@ -1349,18 +1356,8 @@ public:
|
|||
*
|
||||
* Should only be called during MediaStreamListener callbacks or during
|
||||
* ProcessedMediaStream::ProcessInput().
|
||||
*
|
||||
* |aMainThread| is the corresponding AbstractThread on the main thread to
|
||||
* drain the direct tasks generated by |aRunnable|.
|
||||
* Note: The reasons for assigning proper |aMainThread| are
|
||||
* - MSG serves media elements in multiple windows run on main thread.
|
||||
* - DocGroup-specific AbstractMainThread is introduced to cluster the tasks
|
||||
* of the same window for prioritizing tasks among different windows.
|
||||
* - Proper |aMainThread| ensures that tasks dispatched to the main thread are
|
||||
* clustered to the right queue and are executed in right order.
|
||||
*/
|
||||
virtual void
|
||||
DispatchToMainThreadAfterStreamStateUpdate(AbstractThread* aMainThread,
|
||||
virtual void DispatchToMainThreadAfterStreamStateUpdate(
|
||||
already_AddRefed<nsIRunnable> aRunnable);
|
||||
|
||||
/**
|
||||
|
|
|
@ -116,7 +116,8 @@ public:
|
|||
*/
|
||||
explicit MediaStreamGraphImpl(GraphDriverType aGraphDriverRequested,
|
||||
TrackRate aSampleRate,
|
||||
dom::AudioChannel aChannel);
|
||||
dom::AudioChannel aChannel,
|
||||
AbstractThread* aWindow);
|
||||
|
||||
/**
|
||||
* Unregisters memory reporting and deletes this instance. This should be
|
||||
|
@ -149,6 +150,12 @@ public:
|
|||
*/
|
||||
void AppendMessage(UniquePtr<ControlMessage> aMessage);
|
||||
|
||||
/**
|
||||
* Dispatches a runnable from any thread to the correct main thread for this
|
||||
* MediaStreamGraph.
|
||||
*/
|
||||
void Dispatch(already_AddRefed<nsIRunnable>&& aRunnable);
|
||||
|
||||
// Shutdown helpers.
|
||||
|
||||
static already_AddRefed<nsIAsyncShutdownClient>
|
||||
|
@ -805,6 +812,7 @@ public:
|
|||
*/
|
||||
RefPtr<AsyncLatencyLogger> mLatencyLog;
|
||||
AudioMixer mMixer;
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
#ifdef MOZ_WEBRTC
|
||||
RefPtr<AudioOutputObserver> mFarendObserverRef;
|
||||
#endif
|
||||
|
|
|
@ -88,7 +88,6 @@ class MediaStreamTrack::PrincipalHandleListener : public MediaStreamTrackListene
|
|||
public:
|
||||
explicit PrincipalHandleListener(MediaStreamTrack* aTrack)
|
||||
: mTrack(aTrack)
|
||||
, mAbstractMainThread(aTrack->mOwningStream->AbstractMainThread())
|
||||
{}
|
||||
|
||||
void Forget()
|
||||
|
@ -112,7 +111,6 @@ public:
|
|||
const PrincipalHandle& aNewPrincipalHandle) override
|
||||
{
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
mAbstractMainThread,
|
||||
NewRunnableMethod<StoreCopyPassByConstLRef<PrincipalHandle>>(
|
||||
"dom::MediaStreamTrack::PrincipalHandleListener::"
|
||||
"DoNotifyPrincipalHandleChanged",
|
||||
|
@ -124,7 +122,6 @@ public:
|
|||
protected:
|
||||
// These fields may only be accessed on the main thread
|
||||
MediaStreamTrack* mTrack;
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
};
|
||||
|
||||
MediaStreamTrack::MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
|
||||
|
|
|
@ -46,8 +46,9 @@ namespace mozilla {
|
|||
LazyLogModule gTrackUnionStreamLog("TrackUnionStream");
|
||||
#define STREAM_LOG(type, msg) MOZ_LOG(gTrackUnionStreamLog, type, msg)
|
||||
|
||||
TrackUnionStream::TrackUnionStream(AbstractThread* aMainThread) :
|
||||
ProcessedMediaStream(aMainThread), mNextAvailableTrackID(1)
|
||||
TrackUnionStream::TrackUnionStream()
|
||||
: ProcessedMediaStream()
|
||||
, mNextAvailableTrackID(1)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace mozilla {
|
|||
*/
|
||||
class TrackUnionStream : public ProcessedMediaStream {
|
||||
public:
|
||||
explicit TrackUnionStream(AbstractThread* aMainThread);
|
||||
explicit TrackUnionStream();
|
||||
|
||||
virtual TrackUnionStream* AsTrackUnionStream() override { return this; }
|
||||
friend class DOMMediaStream;
|
||||
|
|
|
@ -59,7 +59,6 @@ public:
|
|||
{
|
||||
if (event == MediaStreamGraphEvent::EVENT_FINISHED) {
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
mAbstractMainThread,
|
||||
NewRunnableMethod("DecodedStreamGraphListener::DoNotifyFinished",
|
||||
this,
|
||||
&DecodedStreamGraphListener::DoNotifyFinished));
|
||||
|
@ -183,7 +182,7 @@ DecodedStreamData::DecodedStreamData(OutputStreamManager* aOutputStreamManager,
|
|||
, mHaveSentFinish(false)
|
||||
, mHaveSentFinishAudio(false)
|
||||
, mHaveSentFinishVideo(false)
|
||||
, mStream(aOutputStreamManager->Graph()->CreateSourceStream(aMainThread))
|
||||
, mStream(aOutputStreamManager->Graph()->CreateSourceStream())
|
||||
// DecodedStreamGraphListener will resolve this promise.
|
||||
, mListener(new DecodedStreamGraphListener(mStream, Move(aPromise), aMainThread))
|
||||
// mPlaying is initially true because MDSM won't start playback until playing
|
||||
|
|
|
@ -168,8 +168,7 @@ public:
|
|||
|
||||
aNode->ResolvePromise(renderedBuffer);
|
||||
|
||||
mAbstractMainThread->Dispatch(do_AddRef(new OnCompleteTask(context,
|
||||
renderedBuffer)));
|
||||
context->Dispatch(do_AddRef(new OnCompleteTask(context, renderedBuffer)));
|
||||
|
||||
context->OnStateChanged(nullptr, AudioContextState::Closed);
|
||||
}
|
||||
|
@ -261,8 +260,7 @@ public:
|
|||
|
||||
RefPtr<InputMutedRunnable> runnable =
|
||||
new InputMutedRunnable(aStream, newInputMuted);
|
||||
aStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
runnable.forget());
|
||||
}
|
||||
}
|
||||
|
@ -335,9 +333,12 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext,
|
|||
, mCaptured(false)
|
||||
, mAudible(AudioChannelService::AudibleState::eAudible)
|
||||
{
|
||||
MediaStreamGraph* graph = aIsOffline ?
|
||||
MediaStreamGraph::CreateNonRealtimeInstance(aSampleRate) :
|
||||
MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER, aChannel);
|
||||
nsPIDOMWindowInner* window = aContext->GetParentObject();
|
||||
MediaStreamGraph* graph =
|
||||
aIsOffline
|
||||
? MediaStreamGraph::CreateNonRealtimeInstance(aSampleRate, window)
|
||||
: MediaStreamGraph::GetInstance(
|
||||
MediaStreamGraph::AUDIO_THREAD_DRIVER, aChannel, window);
|
||||
AudioNodeEngine* engine = aIsOffline ?
|
||||
new OfflineDestinationNodeEngine(this, aNumberOfChannels,
|
||||
aLength, aSampleRate) :
|
||||
|
|
|
@ -15,8 +15,9 @@ using namespace mozilla::dom;
|
|||
namespace mozilla {
|
||||
|
||||
AudioNodeExternalInputStream::AudioNodeExternalInputStream(
|
||||
AudioNodeEngine* aEngine, TrackRate aSampleRate, AbstractThread* aMainThread)
|
||||
: AudioNodeStream(aEngine, NO_STREAM_FLAGS, aSampleRate, aMainThread)
|
||||
AudioNodeEngine* aEngine,
|
||||
TrackRate aSampleRate)
|
||||
: AudioNodeStream(aEngine, NO_STREAM_FLAGS, aSampleRate)
|
||||
{
|
||||
MOZ_COUNT_CTOR(AudioNodeExternalInputStream);
|
||||
}
|
||||
|
@ -28,15 +29,14 @@ AudioNodeExternalInputStream::~AudioNodeExternalInputStream()
|
|||
|
||||
/* static */ already_AddRefed<AudioNodeExternalInputStream>
|
||||
AudioNodeExternalInputStream::Create(MediaStreamGraph* aGraph,
|
||||
AudioNodeEngine* aEngine,
|
||||
AbstractThread* aMainThread)
|
||||
AudioNodeEngine* aEngine)
|
||||
{
|
||||
AudioContext* ctx = aEngine->NodeMainThread()->Context();
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aGraph->GraphRate() == ctx->SampleRate());
|
||||
|
||||
RefPtr<AudioNodeExternalInputStream> stream =
|
||||
new AudioNodeExternalInputStream(aEngine, aGraph->GraphRate(), aMainThread);
|
||||
new AudioNodeExternalInputStream(aEngine, aGraph->GraphRate());
|
||||
stream->mSuspendedCount += ctx->ShouldSuspendNewStream();
|
||||
aGraph->AddStream(stream);
|
||||
return stream.forget();
|
||||
|
|
|
@ -23,12 +23,12 @@ class AbstractThread;
|
|||
class AudioNodeExternalInputStream final : public AudioNodeStream
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<AudioNodeExternalInputStream>
|
||||
Create(MediaStreamGraph* aGraph, AudioNodeEngine* aEngine, AbstractThread* aMainThread);
|
||||
static already_AddRefed<AudioNodeExternalInputStream> Create(
|
||||
MediaStreamGraph* aGraph,
|
||||
AudioNodeEngine* aEngine);
|
||||
|
||||
protected:
|
||||
AudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate,
|
||||
AbstractThread* aMainThread);
|
||||
AudioNodeExternalInputStream(AudioNodeEngine* aEngine, TrackRate aSampleRate);
|
||||
~AudioNodeExternalInputStream();
|
||||
|
||||
public:
|
||||
|
|
|
@ -29,17 +29,16 @@ namespace mozilla {
|
|||
|
||||
AudioNodeStream::AudioNodeStream(AudioNodeEngine* aEngine,
|
||||
Flags aFlags,
|
||||
TrackRate aSampleRate,
|
||||
AbstractThread* aMainThread)
|
||||
: ProcessedMediaStream(aMainThread),
|
||||
mEngine(aEngine),
|
||||
mSampleRate(aSampleRate),
|
||||
mFlags(aFlags),
|
||||
mNumberOfInputChannels(2),
|
||||
mIsActive(aEngine->IsActive()),
|
||||
mMarkAsFinishedAfterThisBlock(false),
|
||||
mAudioParamStream(false),
|
||||
mPassThrough(false)
|
||||
TrackRate aSampleRate)
|
||||
: ProcessedMediaStream()
|
||||
, mEngine(aEngine)
|
||||
, mSampleRate(aSampleRate)
|
||||
, mFlags(aFlags)
|
||||
, mNumberOfInputChannels(2)
|
||||
, mIsActive(aEngine->IsActive())
|
||||
, mMarkAsFinishedAfterThisBlock(false)
|
||||
, mAudioParamStream(false)
|
||||
, mPassThrough(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mSuspendedCount = !(mIsActive || mFlags & EXTERNAL_OUTPUT);
|
||||
|
@ -78,8 +77,7 @@ AudioNodeStream::Create(AudioContext* aCtx, AudioNodeEngine* aEngine,
|
|||
AudioNode* node = aEngine->NodeMainThread();
|
||||
|
||||
RefPtr<AudioNodeStream> stream =
|
||||
new AudioNodeStream(aEngine, aFlags, aGraph->GraphRate(),
|
||||
aCtx->GetOwnerGlobal()->AbstractMainThreadFor(TaskCategory::Other));
|
||||
new AudioNodeStream(aEngine, aFlags, aGraph->GraphRate());
|
||||
stream->mSuspendedCount += aCtx->ShouldSuspendNewStream();
|
||||
if (node) {
|
||||
stream->SetChannelMixingParametersImpl(node->ChannelCount(),
|
||||
|
|
|
@ -76,8 +76,7 @@ protected:
|
|||
*/
|
||||
AudioNodeStream(AudioNodeEngine* aEngine,
|
||||
Flags aFlags,
|
||||
TrackRate aSampleRate,
|
||||
AbstractThread* aMainThread);
|
||||
TrackRate aSampleRate);
|
||||
|
||||
~AudioNodeStream();
|
||||
|
||||
|
|
|
@ -159,8 +159,7 @@ public:
|
|||
|
||||
RefPtr<PlayingRefChangeHandler> refchanged =
|
||||
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::RELEASE);
|
||||
aStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
refchanged.forget());
|
||||
}
|
||||
|
||||
|
@ -174,8 +173,7 @@ public:
|
|||
if (mBiquads.IsEmpty()) {
|
||||
RefPtr<PlayingRefChangeHandler> refchanged =
|
||||
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::ADDREF);
|
||||
aStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
refchanged.forget());
|
||||
} else { // Help people diagnose bug 924718
|
||||
WebAudioUtils::LogToDeveloperConsole(mWindowID,
|
||||
|
|
|
@ -125,8 +125,7 @@ public:
|
|||
aStream->ScheduleCheckForInactive();
|
||||
RefPtr<PlayingRefChanged> refchanged =
|
||||
new PlayingRefChanged(aStream, PlayingRefChanged::RELEASE);
|
||||
aStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
refchanged.forget());
|
||||
}
|
||||
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
|
@ -147,8 +146,7 @@ public:
|
|||
if (mLeftOverData <= 0) {
|
||||
RefPtr<PlayingRefChanged> refchanged =
|
||||
new PlayingRefChanged(aStream, PlayingRefChanged::ADDREF);
|
||||
aStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
refchanged.forget());
|
||||
}
|
||||
mLeftOverData = mBufferLength;
|
||||
|
|
|
@ -82,8 +82,7 @@ public:
|
|||
if (mLeftOverData <= 0) {
|
||||
RefPtr<PlayingRefChanged> refchanged =
|
||||
new PlayingRefChanged(aStream, PlayingRefChanged::ADDREF);
|
||||
aStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
refchanged.forget());
|
||||
}
|
||||
mLeftOverData = mBuffer.MaxDelayTicks();
|
||||
|
@ -99,8 +98,7 @@ public:
|
|||
|
||||
RefPtr<PlayingRefChanged> refchanged =
|
||||
new PlayingRefChanged(aStream, PlayingRefChanged::RELEASE);
|
||||
aStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
refchanged.forget());
|
||||
}
|
||||
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
|
|
|
@ -56,8 +56,7 @@ public:
|
|||
|
||||
RefPtr<PlayingRefChangeHandler> refchanged =
|
||||
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::RELEASE);
|
||||
aStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
refchanged.forget());
|
||||
|
||||
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
|
@ -70,8 +69,7 @@ public:
|
|||
if (mIIRFilters.IsEmpty()) {
|
||||
RefPtr<PlayingRefChangeHandler> refchanged =
|
||||
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::ADDREF);
|
||||
aStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
refchanged.forget());
|
||||
} else {
|
||||
WebAudioUtils::LogToDeveloperConsole(mWindowID,
|
||||
|
|
|
@ -84,9 +84,7 @@ MediaStreamAudioSourceNode::Init(DOMMediaStream* aMediaStream, ErrorResult& aRv)
|
|||
|
||||
mInputStream = aMediaStream;
|
||||
AudioNodeEngine* engine = new MediaStreamAudioSourceNodeEngine(this);
|
||||
mStream =
|
||||
AudioNodeExternalInputStream::Create(graph, engine,
|
||||
aMediaStream->AbstractMainThread());
|
||||
mStream = AudioNodeExternalInputStream::Create(graph, engine);
|
||||
mInputStream->AddConsumerToKeepAlive(static_cast<nsIDOMEventTarget*>(this));
|
||||
|
||||
mInputStream->RegisterTrackListener(this);
|
||||
|
|
|
@ -208,8 +208,7 @@ public:
|
|||
|
||||
RefPtr<PlayingRefChangeHandler> refchanged =
|
||||
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::RELEASE);
|
||||
aStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
refchanged.forget());
|
||||
}
|
||||
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
|
||||
|
@ -219,8 +218,7 @@ public:
|
|||
if (mLeftOverData == INT_MIN) {
|
||||
RefPtr<PlayingRefChangeHandler> refchanged =
|
||||
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::ADDREF);
|
||||
aStream->Graph()->
|
||||
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
|
||||
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
refchanged.forget());
|
||||
}
|
||||
mLeftOverData = mHRTFPanner->maxTailFrames();
|
||||
|
|
|
@ -21,23 +21,18 @@ typedef struct FarEndAudioChunk_ {
|
|||
int16_t mData[1]; // variable-length
|
||||
} FarEndAudioChunk;
|
||||
|
||||
// XXX Really a singleton currently
|
||||
class AudioOutputObserver : public MixerCallbackReceiver
|
||||
// This class is used to packetize and send the mixed audio from an MSG, in
|
||||
// int16, to the AEC module of WebRTC.org.
|
||||
class AudioOutputObserver
|
||||
{
|
||||
public:
|
||||
AudioOutputObserver();
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioOutputObserver);
|
||||
|
||||
void MixerCallback(AudioDataValue* aMixedBuffer,
|
||||
AudioSampleFormat aFormat,
|
||||
uint32_t aChannels,
|
||||
uint32_t aFrames,
|
||||
uint32_t aSampleRate) override;
|
||||
|
||||
void Clear();
|
||||
void InsertFarEnd(const AudioDataValue *aBuffer, uint32_t aFrames, bool aOverran,
|
||||
int aFreq, int aChannels, AudioSampleFormat aFormat);
|
||||
int aFreq, int aChannels);
|
||||
uint32_t PlayoutFrequency() { return mPlayoutFreq; }
|
||||
uint32_t PlayoutChannels() { return mPlayoutChannels; }
|
||||
|
||||
|
|
|
@ -118,8 +118,6 @@ MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs &aPrefs)
|
|||
if (compMgr) {
|
||||
compMgr->IsContractIDRegistered(NS_TABSOURCESERVICE_CONTRACTID, &mHasTabVideoSource);
|
||||
}
|
||||
// XXX
|
||||
gFarendObserver = new AudioOutputObserver();
|
||||
|
||||
camera::GetChildAndCall(
|
||||
&camera::CamerasChild::AddDeviceChangeCallback,
|
||||
|
|
|
@ -598,6 +598,7 @@ private:
|
|||
webrtc::VoiceEngine* mVoiceEngine;
|
||||
RefPtr<mozilla::AudioInput> mAudioInput;
|
||||
RefPtr<WebRTCAudioDataListener> mListener;
|
||||
RefPtr<AudioOutputObserver> mAudioOutputObserver;
|
||||
|
||||
// Note: shared across all microphone sources - we don't want to Terminate()
|
||||
// the VoEBase until there are no active captures
|
||||
|
@ -607,6 +608,7 @@ private:
|
|||
static ScopedCustomReleasePtr<webrtc::VoENetwork> mVoENetwork;
|
||||
static ScopedCustomReleasePtr<webrtc::VoEAudioProcessing> mVoEProcessing;
|
||||
|
||||
|
||||
// accessed from the GraphDriver thread except for deletion
|
||||
nsAutoPtr<AudioPacketizer<AudioDataValue, int16_t>> mPacketizer;
|
||||
ScopedCustomReleasePtr<webrtc::VoEExternalMedia> mVoERenderListener;
|
||||
|
@ -664,9 +666,7 @@ public:
|
|||
void EnumerateAudioDevices(dom::MediaSourceEnum,
|
||||
nsTArray<RefPtr<MediaEngineAudioSource>>*) override;
|
||||
private:
|
||||
~MediaEngineWebRTC() {
|
||||
gFarendObserver = nullptr;
|
||||
}
|
||||
~MediaEngineWebRTC() {}
|
||||
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
|
||||
|
|
|
@ -51,9 +51,6 @@ LogModule* AudioLogModule() {
|
|||
NS_IMPL_ISUPPORTS0(MediaEngineWebRTCMicrophoneSource)
|
||||
NS_IMPL_ISUPPORTS0(MediaEngineWebRTCAudioCaptureSource)
|
||||
|
||||
// XXX temp until MSG supports registration
|
||||
StaticRefPtr<AudioOutputObserver> gFarendObserver;
|
||||
|
||||
int MediaEngineWebRTCMicrophoneSource::sChannelsOpen = 0;
|
||||
ScopedCustomReleasePtr<webrtc::VoEBase> MediaEngineWebRTCMicrophoneSource::mVoEBase;
|
||||
ScopedCustomReleasePtr<webrtc::VoEExternalMedia> MediaEngineWebRTCMicrophoneSource::mVoERender;
|
||||
|
@ -99,23 +96,10 @@ AudioOutputObserver::Size()
|
|||
return mPlayoutFifo->size();
|
||||
}
|
||||
|
||||
void
|
||||
AudioOutputObserver::MixerCallback(AudioDataValue* aMixedBuffer,
|
||||
AudioSampleFormat aFormat,
|
||||
uint32_t aChannels,
|
||||
uint32_t aFrames,
|
||||
uint32_t aSampleRate)
|
||||
{
|
||||
if (gFarendObserver) {
|
||||
gFarendObserver->InsertFarEnd(aMixedBuffer, aFrames, false,
|
||||
aSampleRate, aChannels, aFormat);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
AudioOutputObserver::InsertFarEnd(const AudioDataValue *aBuffer, uint32_t aFrames, bool aOverran,
|
||||
int aFreq, int aChannels, AudioSampleFormat aFormat)
|
||||
int aFreq, int aChannels)
|
||||
{
|
||||
if (mPlayoutChannels != 0) {
|
||||
if (mPlayoutChannels != static_cast<uint32_t>(aChannels)) {
|
||||
|
@ -414,6 +398,11 @@ MediaEngineWebRTCMicrophoneSource::UpdateSingleSource(
|
|||
mSkipProcessing = !(prefs.mAecOn || prefs.mAgcOn || prefs.mNoiseOn);
|
||||
if (mSkipProcessing) {
|
||||
mSampleFrequency = MediaEngine::USE_GRAPH_RATE;
|
||||
mAudioOutputObserver = nullptr;
|
||||
} else {
|
||||
// make sure we route a copy of the mixed audio output of this MSG to the
|
||||
// AEC
|
||||
mAudioOutputObserver = new AudioOutputObserver();
|
||||
}
|
||||
SetLastPrefs(prefs);
|
||||
return NS_OK;
|
||||
|
@ -500,10 +489,8 @@ MediaEngineWebRTCMicrophoneSource::Start(SourceMediaStream *aStream,
|
|||
// Make sure logger starts before capture
|
||||
AsyncLatencyLogger::Get(true);
|
||||
|
||||
// Register output observer
|
||||
// XXX
|
||||
MOZ_ASSERT(gFarendObserver);
|
||||
gFarendObserver->Clear();
|
||||
MOZ_ASSERT(mAudioOutputObserver);
|
||||
mAudioOutputObserver->Clear();
|
||||
|
||||
if (mVoEBase->StartReceive(mChannel)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -590,6 +577,10 @@ MediaEngineWebRTCMicrophoneSource::NotifyOutputData(MediaStreamGraph* aGraph,
|
|||
TrackRate aRate,
|
||||
uint32_t aChannels)
|
||||
{
|
||||
if (mAudioOutputObserver) {
|
||||
mAudioOutputObserver->InsertFarEnd(aBuffer, aFrames, false,
|
||||
aRate, aChannels);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -924,18 +915,18 @@ MediaEngineWebRTCMicrophoneSource::Process(int channel,
|
|||
// input code with "old" audio.
|
||||
if (!mStarted) {
|
||||
mStarted = true;
|
||||
while (gFarendObserver->Size() > 1) {
|
||||
free(gFarendObserver->Pop()); // only call if size() > 0
|
||||
while (mAudioOutputObserver->Size() > 1) {
|
||||
free(mAudioOutputObserver->Pop()); // only call if size() > 0
|
||||
}
|
||||
}
|
||||
|
||||
while (gFarendObserver->Size() > 0) {
|
||||
FarEndAudioChunk *buffer = gFarendObserver->Pop(); // only call if size() > 0
|
||||
while (mAudioOutputObserver->Size() > 0) {
|
||||
FarEndAudioChunk *buffer = mAudioOutputObserver->Pop(); // only call if size() > 0
|
||||
if (buffer) {
|
||||
int length = buffer->mSamples;
|
||||
int res = mVoERender->ExternalPlayoutData(buffer->mData,
|
||||
gFarendObserver->PlayoutFrequency(),
|
||||
gFarendObserver->PlayoutChannels(),
|
||||
mAudioOutputObserver->PlayoutFrequency(),
|
||||
mAudioOutputObserver->PlayoutChannels(),
|
||||
mPlayoutDelay,
|
||||
length);
|
||||
free(buffer);
|
||||
|
|
|
@ -37,7 +37,6 @@ public:
|
|||
: mSpeechTask(aSpeechTask)
|
||||
, mStream(aStream)
|
||||
, mStarted(false)
|
||||
, mAbstractMainThread(aMainThread)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -65,14 +64,12 @@ public:
|
|||
if (!mStarted) {
|
||||
mStarted = true;
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
mAbstractMainThread,
|
||||
NewRunnableMethod("dom::SynthStreamListener::DoNotifyStarted",
|
||||
this,
|
||||
&SynthStreamListener::DoNotifyStarted));
|
||||
}
|
||||
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
mAbstractMainThread,
|
||||
NewRunnableMethod("dom::SynthStreamListener::DoNotifyFinished",
|
||||
this,
|
||||
&SynthStreamListener::DoNotifyFinished));
|
||||
|
@ -93,7 +90,6 @@ public:
|
|||
if (aBlocked == MediaStreamListener::UNBLOCKED && !mStarted) {
|
||||
mStarted = true;
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
|
||||
mAbstractMainThread,
|
||||
NewRunnableMethod("dom::SynthStreamListener::DoNotifyStarted",
|
||||
this,
|
||||
&SynthStreamListener::DoNotifyStarted));
|
||||
|
@ -108,8 +104,6 @@ private:
|
|||
RefPtr<MediaStream> mStream;
|
||||
|
||||
bool mStarted;
|
||||
|
||||
const RefPtr<AbstractThread> mAbstractMainThread;
|
||||
};
|
||||
|
||||
// nsSpeechTask
|
||||
|
@ -172,9 +166,11 @@ nsSpeechTask::~nsSpeechTask()
|
|||
void
|
||||
nsSpeechTask::InitDirectAudio()
|
||||
{
|
||||
// nullptr as final argument here means that this is not tied to a window.
|
||||
// This is a global MSG.
|
||||
mStream = MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER,
|
||||
AudioChannel::Normal)->
|
||||
CreateSourceStream(AbstractThread::MainThread() /* Non DocGroup-version for the task in parent. */);
|
||||
AudioChannel::Normal, nullptr)->
|
||||
CreateSourceStream();
|
||||
mIndirectAudio = false;
|
||||
mInited = true;
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче