Merge mozilla-central to autoland

This commit is contained in:
Carsten "Tomcat" Book 2017-06-30 15:18:23 +02:00
Родитель af984342cd daa67cc9e3
Коммит c3e7ae1ce7
290 изменённых файлов: 3442 добавлений и 1864 удалений

Просмотреть файл

@ -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"),
"Pref should be synced for 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,7 +244,11 @@ UIEvent::GetRangeParent()
nsIFrame* targetFrame = nullptr;
if (mPresContext) {
targetFrame = mPresContext->EventStateManager()->GetEventTarget();
nsCOMPtr<nsIPresShell> shell = mPresContext->GetPresShell();
if (shell) {
shell->FlushPendingNotifications(FlushType::Layout);
targetFrame = mPresContext->EventStateManager()->GetEventTarget();
}
}
if (targetFrame) {
@ -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,19 +3061,20 @@ TabChild::ReinitRenderingForDeviceReset()
InvalidateLayers();
RefPtr<LayerManager> lm = mPuppetWidget->GetLayerManager();
ClientLayerManager* clm = lm->AsClientLayerManager();
if (!clm) {
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
// step is necessary since otherwise the compositor will think we
// are trying to attach two layer trees to the same ID.
fwd->SynchronouslyShutdown();
}
} else {
return;
}
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
// step is necessary since otherwise the compositor will think we
// are trying to attach two layer trees to the same ID.
fwd->SynchronouslyShutdown();
}
// 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,
&MediaStreamGraphImpl::OpenAudioInput,
aID, RefPtr<AudioDataListener>(aListener)));
RefPtr<nsIRunnable> runnable =
WrapRunnable(this,
&MediaStreamGraphImpl::OpenAudioInput,
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,
&MediaStreamGraphImpl::CloseAudioInput,
RefPtr<AudioDataListener>(aListener)));
RefPtr<nsIRunnable> runnable =
WrapRunnable(this,
&MediaStreamGraphImpl::CloseAudioInput,
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,33 +2555,27 @@ 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,
mRunnable.forget());
mStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
mRunnable.forget());
}
void RunDuringShutdown() override
{
// 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,18 +3302,20 @@ 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,
mRunnable.forget());
mStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
mRunnable.forget());
}
}
void RunDuringShutdown() override
@ -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,
aSampleRate,
AudioChannel::Normal);
nsCOMPtr<nsIGlobalObject> parentObject = do_QueryInterface(aWindow);
MediaStreamGraphImpl* graph = new MediaStreamGraphImpl(
OFFLINE_THREAD_DRIVER,
aSampleRate,
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,
already_AddRefed<nsIRunnable> aRunnable)
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,19 +1356,9 @@ 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,
already_AddRefed<nsIRunnable> aRunnable);
virtual void DispatchToMainThreadAfterStreamStateUpdate(
already_AddRefed<nsIRunnable> aRunnable);
/**
* Returns graph sample rate in Hz.

Просмотреть файл

@ -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,9 +260,8 @@ public:
RefPtr<InputMutedRunnable> runnable =
new InputMutedRunnable(aStream, newInputMuted);
aStream->Graph()->
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
runnable.forget());
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,9 +159,8 @@ public:
RefPtr<PlayingRefChangeHandler> refchanged =
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::RELEASE);
aStream->Graph()->
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
refchanged.forget());
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
refchanged.forget());
}
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
@ -174,9 +173,8 @@ public:
if (mBiquads.IsEmpty()) {
RefPtr<PlayingRefChangeHandler> refchanged =
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::ADDREF);
aStream->Graph()->
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
refchanged.forget());
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
refchanged.forget());
} else { // Help people diagnose bug 924718
WebAudioUtils::LogToDeveloperConsole(mWindowID,
"BiquadFilterChannelCountChangeWarning");

Просмотреть файл

@ -125,9 +125,8 @@ public:
aStream->ScheduleCheckForInactive();
RefPtr<PlayingRefChanged> refchanged =
new PlayingRefChanged(aStream, PlayingRefChanged::RELEASE);
aStream->Graph()->
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
refchanged.forget());
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
refchanged.forget());
}
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
return;
@ -147,9 +146,8 @@ public:
if (mLeftOverData <= 0) {
RefPtr<PlayingRefChanged> refchanged =
new PlayingRefChanged(aStream, PlayingRefChanged::ADDREF);
aStream->Graph()->
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
refchanged.forget());
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
refchanged.forget());
}
mLeftOverData = mBufferLength;
MOZ_ASSERT(mLeftOverData > 0);

Просмотреть файл

@ -82,9 +82,8 @@ public:
if (mLeftOverData <= 0) {
RefPtr<PlayingRefChanged> refchanged =
new PlayingRefChanged(aStream, PlayingRefChanged::ADDREF);
aStream->Graph()->
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
refchanged.forget());
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
refchanged.forget());
}
mLeftOverData = mBuffer.MaxDelayTicks();
} else if (mLeftOverData > 0) {
@ -99,9 +98,8 @@ public:
RefPtr<PlayingRefChanged> refchanged =
new PlayingRefChanged(aStream, PlayingRefChanged::RELEASE);
aStream->Graph()->
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
refchanged.forget());
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
refchanged.forget());
}
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
return;

Просмотреть файл

@ -56,9 +56,8 @@ public:
RefPtr<PlayingRefChangeHandler> refchanged =
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::RELEASE);
aStream->Graph()->
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
refchanged.forget());
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
refchanged.forget());
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
return;
@ -70,9 +69,8 @@ public:
if (mIIRFilters.IsEmpty()) {
RefPtr<PlayingRefChangeHandler> refchanged =
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::ADDREF);
aStream->Graph()->
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
refchanged.forget());
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
refchanged.forget());
} else {
WebAudioUtils::LogToDeveloperConsole(mWindowID,
"IIRFilterChannelCountChangeWarning");

Просмотреть файл

@ -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,9 +208,8 @@ public:
RefPtr<PlayingRefChangeHandler> refchanged =
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::RELEASE);
aStream->Graph()->
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
refchanged.forget());
aStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(
refchanged.forget());
}
aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
return;
@ -219,9 +218,8 @@ public:
if (mLeftOverData == INT_MIN) {
RefPtr<PlayingRefChangeHandler> refchanged =
new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::ADDREF);
aStream->Graph()->
DispatchToMainThreadAfterStreamStateUpdate(mAbstractMainThread,
refchanged.forget());
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;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше