merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2016-07-07 11:41:27 +02:00
commit 1e5237c994
359 changed files with 6063 additions and 3500 deletions

View File

@ -299,10 +299,10 @@ pref("ui.dragThresholdY", 25);
// they're not maintained anywhere else.
#ifndef MOZ_WIDGET_GONK
pref("dom.ipc.tabs.disabled", true);
pref("layers.async-pan-zoom.enabled", false);
#else
pref("dom.ipc.tabs.disabled", false);
pref("layers.acceleration.disabled", false);
pref("layers.async-pan-zoom.enabled", true);
pref("gfx.content.azure.backends", "cairo");
#endif

View File

@ -26,9 +26,6 @@
#ifdef XP_WIN
// we want a wmain entry point
#include "nsWindowsWMain.cpp"
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define snprintf _snprintf
#endif
#define strcasecmp _stricmp
#endif

View File

@ -36,9 +36,6 @@
#define XRE_DONT_SUPPORT_XPSP2
#endif
#define XRE_WANT_ENVIRON
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define snprintf _snprintf
#endif
#define strcasecmp _stricmp
#ifdef MOZ_SANDBOX
#include "mozilla/sandboxing/SandboxInitialization.h"

View File

@ -973,6 +973,26 @@ pref("security.sandbox.windows.log.stackTraceDepth", 0);
pref("security.sandbox.content.level", 1);
#endif
#if defined(XP_LINUX) && defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX)
// This pref is introduced as part of bug 742434, the naming is inspired from
// its Windows/Mac counterpart, but on Linux it's an integer which means:
// 0 -> "no sandbox"
// 1 -> "content sandbox using seccomp-bpf when available"
// 2 -> "seccomp-bpf + file broker"
// Content sandboxing on Linux is currently in the stage of
// 'just getting it enabled', which includes a very permissive whitelist. We
// enable seccomp-bpf on nightly to see if everything is running, or if we need
// to whitelist more system calls.
//
// So the purpose of this setting is to allow nightly users to disable the
// sandbox while we fix their problems. This way, they won't have to wait for
// another nightly release which disables seccomp-bpf again.
//
// This setting may not be required anymore once we decide to permanently
// enable the content sandbox.
pref("security.sandbox.content.level", 1);
#endif
#if defined(XP_MACOSX) || defined(XP_WIN)
#if defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX)
// ID (a UUID when set by gecko) that is used to form the name of a
@ -1366,10 +1386,6 @@ pref("browser.tabs.crashReporting.includeURL", false);
pref("browser.tabs.crashReporting.emailMe", false);
pref("browser.tabs.crashReporting.email", "");
#ifndef MOZ_MULET
pref("layers.async-pan-zoom.enabled", true);
#endif
// Enable e10s add-on interposition by default.
pref("extensions.interposition.enabled", true);
pref("extensions.interposition.prefetching", true);

View File

@ -369,7 +369,9 @@ var CookieStore = {
}
for (let pathToNamesMap of this._hosts.get(host).values()) {
cookies.push(...pathToNamesMap.values());
for (let nameToCookiesMap of pathToNamesMap.values()) {
cookies.push(...nameToCookiesMap.values());
}
}
}
@ -455,7 +457,14 @@ var CookieStore = {
this._hosts.set(cookie.host, new Map());
}
let pathToNamesMap = this._hosts.get(cookie.host);
let originAttributesMap = this._hosts.get(cookie.host);
// If cookie.originAttributes is null, originAttributes will be an empty string.
let originAttributes = ChromeUtils.originAttributesToSuffix(cookie.originAttributes);
if (!originAttributesMap.has(originAttributes)) {
originAttributesMap.set(originAttributes, new Map());
}
let pathToNamesMap = originAttributesMap.get(originAttributes);
if (!pathToNamesMap.has(cookie.path)) {
pathToNamesMap.set(cookie.path, new Map());

View File

@ -69,3 +69,73 @@ add_task(function* () {
yield promiseRemoveTab(tab2);
});
// Opens "uri" in a new tab with the provided userContextId and focuses it.
// Returns the newly opened tab.
function* openTabInUserContext(userContextId) {
// Open the tab in the correct userContextId.
let tab = gBrowser.addTab("http://example.com", { userContextId });
// Select tab and make sure its browser is focused.
gBrowser.selectedTab = tab;
tab.ownerDocument.defaultView.focus();
let browser = gBrowser.getBrowserForTab(tab);
yield BrowserTestUtils.browserLoaded(browser);
return { tab, browser };
}
function waitForNewCookie() {
return new Promise(resolve => {
Services.obs.addObserver(function observer(subj, topic, data) {
let cookie = subj.QueryInterface(Ci.nsICookie2);
if (data == "added") {
Services.obs.removeObserver(observer, topic);
resolve();
}
}, "cookie-changed", false);
});
}
add_task(function* test() {
const USER_CONTEXTS = [
"default",
"personal",
"work",
];
const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
const { TabStateFlusher } = Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
// Make sure userContext is enabled.
yield SpecialPowers.pushPrefEnv({
"set": [ [ "privacy.userContext.enabled", true ] ]
});
let lastSessionRestore;
for (let userContextId of Object.keys(USER_CONTEXTS)) {
// Load the page in 3 different contexts and set a cookie
// which should only be visible in that context.
let cookie = USER_CONTEXTS[userContextId];
// Open our tab in the given user context.
let { tab, browser } = yield* openTabInUserContext(userContextId);
yield Promise.all([
waitForNewCookie(),
ContentTask.spawn(browser, cookie, cookie => content.document.cookie = cookie)
]);
// Ensure the tab's session history is up-to-date.
yield TabStateFlusher.flush(browser);
lastSessionRestore = ss.getWindowState(window);
// Remove the tab.
gBrowser.removeTab(tab);
}
let state = JSON.parse(lastSessionRestore);
is(state.windows[0].cookies.length, USER_CONTEXTS.length,
"session restore should have each container's cookie");
});

View File

@ -2430,12 +2430,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
text-align: center;
}
@media (min-resolution: 1.1dppx) {
.tab-throbber[progress] {
list-style-image: url("chrome://global/skin/icons/loading@2x.png");
}
}
@media (-moz-mac-yosemite-theme) {
/* image preloading hack from shared/tabs.inc.css */
#tabbrowser-tabs::before {

View File

@ -557,4 +557,8 @@
.tab-icon-image {
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png");
}
.tab-throbber[progress] {
list-style-image: url("chrome://global/skin/icons/loading@2x.png");
}
}

View File

@ -1917,12 +1917,6 @@ html|span.ac-emphasize-text-url {
%include ../shared/tabs.inc.css
@media (min-resolution: 1.1dppx) {
.tab-throbber[progress] {
list-style-image: url("chrome://global/skin/icons/loading@2x.png");
}
}
/* Remove border between tab strip and navigation toolbar on Windows 10+ */
@media not all and (-moz-os-version: windows-xp) {
@media not all and (-moz-os-version: windows-vista) {

View File

@ -640,4 +640,48 @@ def debug_flags(env_debug_flags, enable_debug_flags, default_debug_flags):
set_config('MOZ_DEBUG_FLAGS', debug_flags)
add_old_configure_assignment('MOZ_DEBUG_FLAGS', debug_flags)
# Some standard library headers (notably bionic on Android) declare standard
# functions (e.g. getchar()) and also #define macros for those standard
# functions. libc++ deals with this by doing something like the following
# (explanatory comments added):
#
# #ifdef FUNC
# // Capture the definition of FUNC.
# inline _LIBCPP_INLINE_VISIBILITY int __libcpp_FUNC(...) { return FUNC(...); }
# #undef FUNC
# // Use a real inline definition.
# inline _LIBCPP_INLINE_VISIBILITY int FUNC(...) { return _libcpp_FUNC(...); }
# #endif
#
# _LIBCPP_INLINE_VISIBILITY is typically defined as:
#
# __attribute__((__visibility__("hidden"), __always_inline__))
#
# Unfortunately, this interacts badly with our system header wrappers, as the:
#
# #pragma GCC visibility push(default)
#
# that they do prior to including the actual system header is treated by the
# compiler as an explicit declaration of visibility on every function declared
# in the header. Therefore, when the libc++ code above is encountered, it is
# as though the compiler has effectively seen:
#
# int FUNC(...) __attribute__((__visibility__("default")));
# int FUNC(...) __attribute__((__visibility__("hidden")));
#
# and the compiler complains about the mismatched visibility declarations.
#
# However, libc++ will only define _LIBCPP_INLINE_VISIBILITY if there is no
# existing definition. We can therefore define it to the empty string (since
# we are properly managing visibility ourselves) and avoid this whole mess.
# Note that we don't need to do this with gcc, as libc++ detects gcc and
# effectively does the same thing we are doing here.
@depends(c_compiler, target)
def libcxx_inline_visibility(c_compiler, target):
if c_compiler.type == 'clang' and target.os == 'Android':
return ''
set_define('_LIBCPP_INLINE_VISIBILITY', libcxx_inline_visibility)
set_define('_LIBCPP_INLINE_VISIBILITY_EXCEPT_GCC49', libcxx_inline_visibility)
include('rust.configure')

View File

@ -7,59 +7,74 @@
const TEST_URI = URL_ROOT + "browser_toolbox_options_disable_js.html";
var doc;
var toolbox;
function test() {
gBrowser.selectedTab = gBrowser.addTab();
let target = TargetFactory.forTab(gBrowser.selectedTab);
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
doc = content.document;
gDevTools.showToolbox(target).then(testSelectTool);
}, true);
content.location = TEST_URI;
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, TEST_URI);
}
function testSelectTool(aToolbox) {
toolbox = aToolbox;
toolbox.once("options-selected", testJSEnabled);
function testSelectTool(toolbox) {
toolbox.once("options-selected", () => testToggleJS(toolbox));
toolbox.selectTool("options");
}
function testJSEnabled(event, tool, secondPass) {
let testToggleJS = Task.async(function* (toolbox) {
ok(true, "Toolbox selected via selectTool method");
yield testJSEnabled();
yield testJSEnabledIframe();
// Disable JS.
yield toggleJS(toolbox);
yield testJSDisabled();
yield testJSDisabledIframe();
// Re-enable JS.
yield toggleJS(toolbox);
yield testJSEnabled();
yield testJSEnabledIframe();
finishUp(toolbox);
});
function* testJSEnabled() {
info("Testing that JS is enabled");
// We use executeSoon here because switching docSehll.allowJavascript to true
// We use waitForTick here because switching docShell.allowJavascript to true
// takes a while to become live.
executeSoon(function () {
yield waitForTick();
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function () {
let doc = content.document;
let output = doc.getElementById("output");
doc.querySelector("#logJSEnabled").click();
is(output.textContent, "JavaScript Enabled", 'Output is "JavaScript Enabled"');
testJSEnabledIframe(secondPass);
});
}
function testJSEnabledIframe(secondPass) {
function* testJSEnabledIframe() {
info("Testing that JS is enabled in the iframe");
let iframe = doc.querySelector("iframe");
let iframeDoc = iframe.contentDocument;
let output = iframeDoc.getElementById("output");
iframeDoc.querySelector("#logJSEnabled").click();
is(output.textContent, "JavaScript Enabled",
'Output is "JavaScript Enabled" in iframe');
if (secondPass) {
finishUp();
} else {
toggleJS().then(testJSDisabled);
}
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function () {
let doc = content.document;
let iframe = doc.querySelector("iframe");
let iframeDoc = iframe.contentDocument;
let output = iframeDoc.getElementById("output");
iframeDoc.querySelector("#logJSEnabled").click();
is(output.textContent, "JavaScript Enabled",
'Output is "JavaScript Enabled" in iframe');
});
}
let toggleJS = Task.async(function* () {
function* toggleJS(toolbox) {
let panel = toolbox.getCurrentPanel();
let cbx = panel.panelDoc.getElementById("devtools-disable-javascript");
@ -72,38 +87,38 @@ let toggleJS = Task.async(function* () {
let browserLoaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
cbx.click();
yield browserLoaded;
doc = content.document;
});
function testJSDisabled() {
info("Testing that JS is disabled");
let output = doc.getElementById("output");
doc.querySelector("#logJSDisabled").click();
ok(output.textContent !== "JavaScript Disabled",
'output is not "JavaScript Disabled"');
testJSDisabledIframe();
}
function testJSDisabledIframe() {
info("Testing that JS is disabled in the iframe");
function* testJSDisabled() {
info("Testing that JS is disabled");
let iframe = doc.querySelector("iframe");
let iframeDoc = iframe.contentDocument;
let output = iframeDoc.getElementById("output");
iframeDoc.querySelector("#logJSDisabled").click();
ok(output.textContent !== "JavaScript Disabled",
'output is not "JavaScript Disabled" in iframe');
toggleJS().then(function () {
testJSEnabled(null, null, true);
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function () {
let doc = content.document;
let output = doc.getElementById("output");
doc.querySelector("#logJSDisabled").click();
ok(output.textContent !== "JavaScript Disabled",
'output is not "JavaScript Disabled"');
});
}
function finishUp() {
function* testJSDisabledIframe() {
info("Testing that JS is disabled in the iframe");
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function () {
let doc = content.document;
let iframe = doc.querySelector("iframe");
let iframeDoc = iframe.contentDocument;
let output = iframeDoc.getElementById("output");
iframeDoc.querySelector("#logJSDisabled").click();
ok(output.textContent !== "JavaScript Disabled",
'output is not "JavaScript Disabled" in iframe');
});
}
function finishUp(toolbox) {
toolbox.destroy().then(function () {
gBrowser.removeCurrentTab();
toolbox = doc = null;
finish();
});
}

View File

@ -33,6 +33,8 @@ const nodeConstants = require("devtools/shared/dom-node-constants");
const MAX_STRING_GRIP_LENGTH = 36;
const ELLIPSIS = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
const validProtocols = /^(http|https|ftp|data|javascript|resource|chrome):/i;
// Constants for compatibility with the Web Console output implementation before
// bug 778766.
// TODO: remove these once bug 778766 is fixed.
@ -2223,9 +2225,11 @@ Widgets.URLString.prototype = extend(Widgets.BaseWidget.prototype, {
*/
_isURL: function (token) {
try {
let url = new URL(token);
return ["http:", "https:", "ftp:", "data:", "javascript:",
"resource:", "chrome:"].includes(url.protocol);
if (!validProtocols.test(token)) {
return false;
}
new URL(token);
return true;
} catch (e) {
return false;
}

View File

@ -63,9 +63,9 @@ GetCurrentThreadDebuggerMallocSizeOf()
{
auto ccrt = CycleCollectedJSRuntime::Get();
MOZ_ASSERT(ccrt);
auto rt = ccrt->Runtime();
MOZ_ASSERT(rt);
auto mallocSizeOf = JS::dbg::GetDebuggerMallocSizeOf(rt);
auto cx = ccrt->Context();
MOZ_ASSERT(cx);
auto mallocSizeOf = JS::dbg::GetDebuggerMallocSizeOf(cx);
MOZ_ASSERT(mallocSizeOf);
return mallocSizeOf;
}
@ -1246,8 +1246,7 @@ public:
return false;
}
JSRuntime* rt = JS_GetRuntime(cx);
mozilla::MallocSizeOf mallocSizeOf = dbg::GetDebuggerMallocSizeOf(rt);
mozilla::MallocSizeOf mallocSizeOf = dbg::GetDebuggerMallocSizeOf(cx);
MOZ_ASSERT(mallocSizeOf);
protobufNode.set_size(ubiNode.size(mallocSizeOf));

View File

@ -60,11 +60,19 @@ GetComputedTimingDictionary(const ComputedTiming& aComputedTiming,
namespace dom {
NS_IMPL_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadOnly,
AnimationEffectReadOnly,
mTarget,
mAnimation,
mTiming)
NS_IMPL_CYCLE_COLLECTION_CLASS(KeyframeEffectReadOnly)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(KeyframeEffectReadOnly,
AnimationEffectReadOnly)
if (tmp->mTiming) {
tmp->mTiming->Unlink();
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTarget, mAnimation, mTiming)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(KeyframeEffectReadOnly,
AnimationEffectReadOnly)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTarget, mAnimation, mTiming)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(KeyframeEffectReadOnly,
AnimationEffectReadOnly)
@ -517,6 +525,29 @@ KeyframeEffectReadOnly::HasAnimationOfProperties(
return false;
}
#ifdef DEBUG
bool
SpecifiedKeyframeArraysAreEqual(const nsTArray<Keyframe>& aA,
const nsTArray<Keyframe>& aB)
{
if (aA.Length() != aB.Length()) {
return false;
}
for (size_t i = 0; i < aA.Length(); i++) {
const Keyframe& a = aA[i];
const Keyframe& b = aB[i];
if (a.mOffset != b.mOffset ||
a.mTimingFunction != b.mTimingFunction ||
a.mPropertyValues != b.mPropertyValues) {
return false;
}
}
return true;
}
#endif
void
KeyframeEffectReadOnly::UpdateProperties(nsStyleContext* aStyleContext)
{
@ -524,20 +555,37 @@ KeyframeEffectReadOnly::UpdateProperties(nsStyleContext* aStyleContext)
nsTArray<AnimationProperty> properties;
if (mTarget) {
// When GetComputedKeyframeValues or GetAnimationPropertiesFromKeyframes
// calculate computed values from |mKeyframes|, they could possibly
// trigger a subsequent restyle in which we rebuild animations. If that
// happens we could find that |mKeyframes| is overwritten while it is
// being iterated over. Normally that shouldn't happen but just in case we
// make a copy of |mKeyframes| first and iterate over that instead.
auto keyframesCopy(mKeyframes);
nsTArray<ComputedKeyframeValues> computedValues =
KeyframeUtils::GetComputedKeyframeValues(mKeyframes, mTarget->mElement,
KeyframeUtils::GetComputedKeyframeValues(keyframesCopy,
mTarget->mElement,
aStyleContext);
if (mEffectOptions.mSpacingMode == SpacingMode::paced) {
KeyframeUtils::ApplySpacing(mKeyframes, SpacingMode::paced,
KeyframeUtils::ApplySpacing(keyframesCopy, SpacingMode::paced,
mEffectOptions.mPacedProperty,
computedValues);
}
properties =
KeyframeUtils::GetAnimationPropertiesFromKeyframes(mKeyframes,
KeyframeUtils::GetAnimationPropertiesFromKeyframes(keyframesCopy,
computedValues,
aStyleContext);
#ifdef DEBUG
MOZ_ASSERT(SpecifiedKeyframeArraysAreEqual(mKeyframes, keyframesCopy),
"Apart from the computed offset members, the keyframes array"
" should not be modified");
#endif
mKeyframes.SwapElements(keyframesCopy);
}
if (mProperties == properties) {

View File

@ -16,6 +16,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/Attr.h"
#include "mozilla/dom/Grid.h"
#include "nsDOMAttributeMap.h"
#include "nsIAtom.h"
#include "nsIContentInlines.h"
@ -953,7 +954,6 @@ Element::GetClientRects()
return rectList.forget();
}
//----------------------------------------------------------------------
void
@ -3289,6 +3289,21 @@ Element::MozRequestPointerLock()
OwnerDoc()->RequestPointerLock(this);
}
void
Element::GetGridFragments(nsTArray<RefPtr<Grid>>& aResult)
{
nsIFrame* frame = GetPrimaryFrame();
if (frame && (frame->GetType() == nsGkAtoms::gridContainerFrame)) {
// If primary frame is a nsGridContainerFrame, all the next frames
// in flow will also be nsGridContainerFrame.
for (; frame != nullptr; frame = frame->GetNextInFlow()) {
aResult.AppendElement(
new Grid(this, static_cast<nsGridContainerFrame*>(frame))
);
}
}
}
already_AddRefed<Animation>
Element::Animate(JSContext* aContext,
JS::Handle<JSObject*> aKeyframes,

View File

@ -140,6 +140,7 @@ class UndoManager;
class DOMRect;
class DOMRectList;
class DestinationInsertionPointList;
class Grid;
// IID for the dom::Element interface
#define NS_ELEMENT_IID \
@ -830,6 +831,8 @@ public:
0;
}
void GetGridFragments(nsTArray<RefPtr<Grid>>& aResult);
virtual already_AddRefed<UndoManager> GetUndoManager()
{
return nullptr;

View File

@ -11152,15 +11152,14 @@ nsGlobalWindow::ShowSlowScriptDialog()
buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2;
// Null out the operation callback while we're re-entering JS here.
JSRuntime* rt = JS_GetRuntime(cx);
JSInterruptCallback old = JS_SetInterruptCallback(rt, nullptr);
JSInterruptCallback old = JS_SetInterruptCallback(cx, nullptr);
// Open the dialog.
rv = prompt->ConfirmEx(title, msg, buttonFlags, waitButton, stopButton,
debugButton, neverShowDlg, &neverShowDlgChk,
&buttonPressed);
JS_SetInterruptCallback(rt, old);
JS_SetInterruptCallback(cx, old);
if (NS_SUCCEEDED(rv) && (buttonPressed == 0)) {
return neverShowDlgChk ? AlwaysContinueSlowScript : ContinueSlowScript;

View File

@ -58,7 +58,7 @@ public:
explicit CallbackObject(JSContext* aCx, JS::Handle<JSObject*> aCallback,
nsIGlobalObject* aIncumbentGlobal)
{
if (aCx && JS::RuntimeOptionsRef(aCx).asyncStack()) {
if (aCx && JS::ContextOptionsRef(aCx).asyncStack()) {
JS::RootedObject stack(aCx);
if (!JS::CaptureCurrentStack(aCx, &stack)) {
JS_ClearPendingException(aCx);
@ -230,7 +230,7 @@ protected:
nsIGlobalObject* aIncumbentGlobal,
const FastCallbackConstructor&)
{
if (aCx && JS::RuntimeOptionsRef(aCx).asyncStack()) {
if (aCx && JS::ContextOptionsRef(aCx).asyncStack()) {
JS::RootedObject stack(aCx);
if (!JS::CaptureCurrentStack(aCx, &stack)) {
JS_ClearPendingException(aCx);

View File

@ -74,6 +74,7 @@ LOCAL_INCLUDES += [
'/dom/xul',
'/js/xpconnect/src',
'/js/xpconnect/wrappers',
'/layout/generic',
'/layout/style',
'/layout/xul/tree',
'/media/mtransport',

View File

@ -5,6 +5,7 @@
#include "CameraPreviewMediaStream.h"
#include "CameraCommon.h"
#include "MediaStreamListener.h"
/**
* Maximum number of outstanding invalidates before we start to drop frames;
@ -89,7 +90,7 @@ CameraPreviewMediaStream::RemoveListener(MediaStreamListener* aListener)
RefPtr<MediaStreamListener> listener(aListener);
mListeners.RemoveElement(aListener);
listener->NotifyEvent(mFakeMediaStreamGraph, MediaStreamListener::EVENT_REMOVED);
listener->NotifyEvent(mFakeMediaStreamGraph, MediaStreamGraphEvent::EVENT_REMOVED);
}
void
@ -103,7 +104,7 @@ CameraPreviewMediaStream::OnPreviewStateChange(bool aActive)
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
MediaStreamListener* l = mListeners[j];
l->NotifyQueuedTrackChanges(mFakeMediaStreamGraph, TRACK_VIDEO, 0,
MediaStreamListener::TRACK_EVENT_CREATED,
TrackEventCommand::TRACK_EVENT_CREATED,
tmpSegment);
l->NotifyFinishedTrackCreation(mFakeMediaStreamGraph);
}

View File

@ -67,12 +67,12 @@ public:
}
void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset, uint32_t aTrackEvents,
StreamTime aTrackOffset, TrackEventCommand aTrackEvents,
const MediaSegment& aQueuedMedia,
MediaStream* aInputStream,
TrackID aInputTrackID) override
{
if (aTrackEvents & TRACK_EVENT_CREATED) {
if (aTrackEvents & TrackEventCommand::TRACK_EVENT_CREATED) {
aGraph->DispatchToMainThreadAfterStreamStateUpdate(NewRunnableMethod<TrackID>(
this, &TrackCreatedListener::DoNotifyTrackCreated, aID));
}

View File

@ -1437,9 +1437,9 @@ protected:
CheckedUint32 GetUnpackSize(bool isFunc3D, uint32_t width, uint32_t height,
uint32_t depth, uint8_t bytesPerPixel);
CheckedUint32 GetPackSize(uint32_t width, uint32_t height, uint8_t bytesPerPixel,
CheckedUint32* const out_startOffset,
CheckedUint32* const out_rowStride);
bool ValidatePackSize(const char* funcName, uint32_t width, uint32_t height,
uint8_t bytesPerPixel, uint32_t* const out_rowStride,
uint32_t* const out_endOffset);
GLenum mPixelStore_ColorspaceConversion;
bool mPixelStore_FlipY;

View File

@ -1224,30 +1224,33 @@ WebGLContext::DoReadPixelsAndConvert(GLint x, GLint y, GLsizei width, GLsizei he
if (gl->WorkAroundDriverBugs() &&
gl->IsANGLE() &&
gl->Version() < 300 && // ANGLE ES2 doesn't support HALF_FLOAT reads properly.
readType == LOCAL_GL_FLOAT &&
auxReadFormat == destFormat &&
auxReadType == LOCAL_GL_HALF_FLOAT)
{
MOZ_RELEASE_ASSERT(!IsWebGL2()); // No SKIP_PIXELS, etc.
readType = auxReadType;
const char funcName[] = "readPixels";
const auto readBytesPerPixel = webgl::BytesPerPixel({readFormat, readType});
const auto destBytesPerPixel = webgl::BytesPerPixel({destFormat, destType});
CheckedUint32 readOffset;
CheckedUint32 readStride;
const CheckedUint32 readSize = GetPackSize(width, height, readBytesPerPixel,
&readOffset, &readStride);
CheckedUint32 destOffset;
CheckedUint32 destStride;
const CheckedUint32 destSize = GetPackSize(width, height, destBytesPerPixel,
&destOffset, &destStride);
if (!readSize.isValid() || !destSize.isValid()) {
uint32_t readStride;
uint32_t readByteCount;
uint32_t destStride;
uint32_t destByteCount;
if (!ValidatePackSize(funcName, width, height, readBytesPerPixel, &readStride,
&readByteCount) ||
!ValidatePackSize(funcName, width, height, destBytesPerPixel, &destStride,
&destByteCount))
{
ErrorOutOfMemory("readPixels: Overflow calculating sizes for conversion.");
return false;
}
UniqueBuffer readBuffer = malloc(readSize.value());
UniqueBuffer readBuffer = malloc(readByteCount);
if (!readBuffer) {
ErrorOutOfMemory("readPixels: Failed to alloc temp buffer for conversion.");
return false;
@ -1268,11 +1271,11 @@ WebGLContext::DoReadPixelsAndConvert(GLint x, GLint y, GLsizei width, GLsizei he
return false;
}
size_t channelsPerRow = std::min(readStride.value() / sizeof(uint16_t),
destStride.value() / sizeof(float));
size_t channelsPerRow = std::min(readStride / sizeof(uint16_t),
destStride / sizeof(float));
const uint8_t* srcRow = (uint8_t*)(readBuffer.get()) + readOffset.value();
uint8_t* dstRow = (uint8_t*)(destBytes) + destOffset.value();
const uint8_t* srcRow = (uint8_t*)readBuffer.get();
uint8_t* dstRow = (uint8_t*)destBytes;
for (size_t j = 0; j < (size_t)height; j++) {
auto src = (const uint16_t*)srcRow;
@ -1285,8 +1288,8 @@ WebGLContext::DoReadPixelsAndConvert(GLint x, GLint y, GLsizei width, GLsizei he
++dst;
}
srcRow += readStride.value();
dstRow += destStride.value();
srcRow += readStride;
dstRow += destStride;
}
return true;
@ -1391,35 +1394,47 @@ IsIntegerFormatAndTypeUnpackable(GLenum format, GLenum type)
}
CheckedUint32
WebGLContext::GetPackSize(uint32_t width, uint32_t height, uint8_t bytesPerPixel,
CheckedUint32* const out_startOffset,
CheckedUint32* const out_rowStride)
bool
WebGLContext::ValidatePackSize(const char* funcName, uint32_t width, uint32_t height,
uint8_t bytesPerPixel, uint32_t* const out_rowStride,
uint32_t* const out_endOffset)
{
if (!width || !height) {
*out_startOffset = 0;
*out_rowStride = 0;
return 0;
*out_endOffset = 0;
return true;
}
const CheckedUint32 pixelsPerRow = (mPixelStore_PackRowLength ? mPixelStore_PackRowLength
: width);
const CheckedUint32 skipPixels = mPixelStore_PackSkipPixels;
const CheckedUint32 skipRows = mPixelStore_PackSkipRows;
const CheckedUint32 alignment = mPixelStore_PackAlignment;
// GLES 3.0.4, p116 (PACK_ functions like UNPACK_)
const auto totalBytesPerRow = bytesPerPixel * pixelsPerRow;
const auto rowStride = RoundUpToMultipleOf(totalBytesPerRow, alignment);
const auto startOffset = rowStride * skipRows + bytesPerPixel * skipPixels;
const auto usedBytesPerRow = bytesPerPixel * width;
const auto rowLength = (mPixelStore_PackRowLength ? mPixelStore_PackRowLength
: width);
const auto skipPixels = mPixelStore_PackSkipPixels;
const auto skipRows = mPixelStore_PackSkipRows;
const auto alignment = mPixelStore_PackAlignment;
const auto bytesNeeded = startOffset + rowStride * (height - 1) + usedBytesPerRow;
const auto usedPixelsPerRow = CheckedUint32(skipPixels) + width;
const auto usedRowsPerImage = CheckedUint32(skipRows) + height;
*out_startOffset = startOffset;
*out_rowStride = rowStride;
return bytesNeeded;
if (!usedPixelsPerRow.isValid() || usedPixelsPerRow.value() > rowLength) {
ErrorInvalidOperation("%s: SKIP_PIXELS + width > ROW_LENGTH.", funcName);
return false;
}
const auto rowLengthBytes = CheckedUint32(rowLength) * bytesPerPixel;
const auto rowStride = RoundUpToMultipleOf(rowLengthBytes, alignment);
const auto usedBytesPerRow = usedPixelsPerRow * bytesPerPixel;
const auto usedBytesPerImage = (usedRowsPerImage - 1) * rowStride + usedBytesPerRow;
if (!rowStride.isValid() || !usedBytesPerImage.isValid()) {
ErrorInvalidOperation("%s: Invalid UNPACK_ params.", funcName);
return false;
}
*out_rowStride = rowStride.value();
*out_endOffset = usedBytesPerImage.value();
return true;
}
void
@ -1428,6 +1443,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
const dom::Nullable<dom::ArrayBufferView>& pixels,
ErrorResult& out_error)
{
const char funcName[] = "readPixels";
if (IsContextLost())
return;
@ -1539,6 +1555,8 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
MOZ_CRASH("GFX: bad `type`");
}
//////
const auto& view = pixels.Value();
// Compute length and data. Don't reenter after this point, lest the
@ -1552,27 +1570,29 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
if (dataType != requiredDataType)
return ErrorInvalidOperation("readPixels: Mismatched type/pixels types");
CheckedUint32 startOffset;
CheckedUint32 rowStride;
const auto bytesNeeded = GetPackSize(width, height, bytesPerPixel, &startOffset,
&rowStride);
if (!bytesNeeded.isValid()) {
ErrorInvalidOperation("readPixels: Integer overflow computing the needed buffer"
" size.");
return;
}
if (bytesNeeded.value() > bytesAvailable) {
ErrorInvalidOperation("readPixels: buffer too small");
return;
}
if (!data) {
ErrorOutOfMemory("readPixels: buffer storage is null. Did we run out of memory?");
out_error.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
//////
uint32_t rowStride;
uint32_t bytesNeeded;
if (!ValidatePackSize(funcName, width, height, bytesPerPixel, &rowStride,
&bytesNeeded))
{
return;
}
if (bytesNeeded > bytesAvailable) {
ErrorInvalidOperation("readPixels: buffer too small");
return;
}
//////
MakeContextCurrent();
const webgl::FormatUsageInfo* srcFormat;
@ -1643,7 +1663,6 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight);
if (rwWidth == uint32_t(width) && rwHeight == uint32_t(height)) {
// Warning: Possibly shared memory. See bug 1225033.
DoReadPixelsAndConvert(x, y, width, height, format, type, data, auxReadFormat,
auxReadType);
return;
@ -1659,34 +1678,6 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
GenerateWarning("readPixels: Out-of-bounds reads with readPixels are deprecated, and"
" may be slow.");
// Currently, the spec dictates that we need to zero the out-of-bounds pixels.
// Ideally we could just ReadPixels into the buffer, then zero the undefined parts.
// However, we can't do this for *shared* ArrayBuffers, as they can have racey
// accesses from Workers.
// We can use a couple tricks to do this faster, but we shouldn't encourage this
// anyway. Why not just do it the really safe, dead-simple way, even if it is
// hilariously slow?
////////////////////////////////////
// Clear the targetted pixels to zero.
if (mPixelStore_PackRowLength ||
mPixelStore_PackSkipPixels ||
mPixelStore_PackSkipRows)
{
// Targetted bytes might not be contiguous, so do it row-by-row.
uint8_t* row = (uint8_t*)data + startOffset.value();
const auto bytesPerRow = bytesPerPixel * width;
for (uint32_t j = 0; j < uint32_t(height); j++) {
std::memset(row, 0, bytesPerRow);
row += rowStride.value();
}
} else {
std::memset(data, 0, bytesNeeded.value());
}
////////////////////////////////////
// Read only the in-bounds pixels.
@ -1698,7 +1689,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
if (IsWebGL2()) {
if (!mPixelStore_PackRowLength) {
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, width);
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mPixelStore_PackSkipPixels + width);
}
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mPixelStore_PackSkipPixels + writeX);
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore_PackSkipRows + writeY);
@ -1712,12 +1703,12 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
} else {
// I *did* say "hilariously slow".
uint8_t* row = (uint8_t*)data + startOffset.value() + writeX * bytesPerPixel;
row += writeY * rowStride.value();
uint8_t* row = (uint8_t*)data + writeX * bytesPerPixel;
row += writeY * rowStride;
for (uint32_t j = 0; j < rwHeight; j++) {
DoReadPixelsAndConvert(readX, readY+j, rwWidth, 1, format, type, row,
auxReadFormat, auxReadType);
row += rowStride.value();
row += rowStride;
}
}
}

View File

@ -43,11 +43,7 @@ WebGLExtensionColorBufferHalfFloat::~WebGLExtensionColorBufferHalfFloat()
bool
WebGLExtensionColorBufferHalfFloat::IsSupported(const WebGLContext* webgl)
{
gl::GLContext* gl = webgl->GL();
// ANGLE doesn't support ReadPixels from a RGBA16F with RGBA/FLOAT.
return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float) ||
gl->IsANGLE();
return webgl->GL()->IsSupported(gl::GLFeature::renderbuffer_color_half_float);
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionColorBufferHalfFloat, EXT_color_buffer_half_float)

View File

@ -28,7 +28,6 @@ support-files =
support-files = pointerevent_pointercancel_touch-manual.html
[test_pointerevent_pointerdown-manual.html]
support-files = pointerevent_pointerdown-manual.html
disabled = should be investigated
[test_pointerevent_pointerenter_does_not_bubble-manual.html]
support-files = pointerevent_pointerenter_does_not_bubble-manual.html
[test_pointerevent_pointerenter_nohover-manual.html]
@ -41,7 +40,6 @@ support-files =
support-files = pointerevent_pointerleave_after_pointerup_nohover-manual.html
[test_pointerevent_pointerleave_descendant_over-manual.html]
support-files = pointerevent_pointerleave_descendant_over-manual.html
skip-if = (os == 'linux') # Bug 1180188 - Issue on Linux
[test_pointerevent_pointerleave_descendants-manual.html]
support-files = pointerevent_pointerleave_descendants-manual.html
[test_pointerevent_pointerleave_does_not_bubble-manual.html]
@ -53,7 +51,6 @@ support-files =
disabled = should be investigated
[test_pointerevent_pointerleave_touch-manual.html]
support-files = pointerevent_pointerleave_touch-manual.html
skip-if = (os == 'linux') # Bug 1180188 - Issue on Linux
[test_pointerevent_pointermove-manual.html]
support-files = pointerevent_pointermove-manual.html
[test_pointerevent_pointermove_isprimary_same_as_pointerdown-manual.html]
@ -97,7 +94,6 @@ support-files =
support-files = pointerevent_setpointercapture_disconnected-manual.html
[test_pointerevent_setpointercapture_inactive_button_mouse-manual.html]
support-files = pointerevent_setpointercapture_inactive_button_mouse-manual.html
skip-if = (os == 'linux') && e10s # Bug 1180188 - Issue on Linux
[test_pointerevent_setpointercapture_invalid_pointerid-manual.html]
support-files = pointerevent_setpointercapture_invalid_pointerid-manual.html
[test_pointerevent_setpointercapture_relatedtarget-manual.html]
@ -110,7 +106,6 @@ support-files =
disabled = disabled
[test_pointerevent_touch-action-illegal.html]
support-files = pointerevent_touch-action-illegal.html
disabled = disabled
[test_pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html]
support-files = pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html
disabled = disabled

View File

@ -10,7 +10,6 @@
#include "mozilla/Telemetry.h"
#include "nsAutoPtr.h"
#include "nsISettingsService.h"
#include "nsGeolocation.h"
#include "nsDOMClassInfoID.h"
@ -32,7 +31,6 @@
#include "mozilla/dom/Event.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/SettingChangeNotificationBinding.h"
#include "mozilla/dom/WakeLock.h"
class nsIPrincipal;
@ -62,9 +60,6 @@ class nsIPrincipal;
// that a window can make.
#define MAX_GEO_REQUESTS_PER_WINDOW 1500
// The settings key.
#define GEO_SETTINGS_ENABLED "geolocation.enabled"
using mozilla::Unused; // <snicker>
using namespace mozilla;
using namespace mozilla::dom;
@ -150,53 +145,6 @@ CreatePositionOptionsCopy(const PositionOptions& aOptions)
return geoOptions.forget();
}
class GeolocationSettingsCallback : public nsISettingsServiceCallback
{
virtual ~GeolocationSettingsCallback() {
MOZ_COUNT_DTOR(GeolocationSettingsCallback);
}
public:
NS_DECL_ISUPPORTS
GeolocationSettingsCallback() {
MOZ_COUNT_CTOR(GeolocationSettingsCallback);
}
NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult) override
{
MOZ_ASSERT(NS_IsMainThread());
// The geolocation is enabled by default:
bool value = true;
if (aResult.isBoolean()) {
value = aResult.toBoolean();
}
MozSettingValue(value);
return NS_OK;
}
NS_IMETHOD HandleError(const nsAString& aName) override
{
NS_WARNING("Unable to get value for '" GEO_SETTINGS_ENABLED "'");
// Default it's enabled:
MozSettingValue(true);
return NS_OK;
}
void MozSettingValue(const bool aValue)
{
RefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
if (gs) {
gs->HandleMozsettingValue(aValue);
}
}
};
NS_IMPL_ISUPPORTS(GeolocationSettingsCallback, nsISettingsServiceCallback)
class RequestPromptEvent : public Runnable
{
public:
@ -382,12 +330,14 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGeolocationRequest)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGeolocationRequest)
NS_IMPL_CYCLE_COLLECTION(nsGeolocationRequest, mCallback, mErrorCallback, mLocator)
void
nsGeolocationRequest::Notify()
{
SetTimeoutTimer();
NotifyErrorAndShutdown(nsIDOMGeoPositionError::TIMEOUT);
}
void
nsGeolocationRequest::NotifyErrorAndShutdown(uint16_t aErrorCode)
{
@ -559,6 +509,7 @@ nsGeolocationRequest::GetRequester(nsIContentPermissionRequester** aRequester)
nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
requester.forget(aRequester);
return NS_OK;
}
@ -646,6 +597,7 @@ nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
MOZ_ASSERT(mShutdown || mIsWatchPositionRequest,
"non-shutdown getCurrentPosition request after callback!");
}
nsIPrincipal*
nsGeolocationRequest::GetPrincipal()
{
@ -662,6 +614,7 @@ nsGeolocationRequest::Update(nsIDOMGeoPosition* aPosition)
NS_DispatchToMainThread(ev);
return NS_OK;
}
NS_IMETHODIMP
nsGeolocationRequest::NotifyError(uint16_t aErrorCode)
{
@ -703,6 +656,7 @@ nsGeolocationRequest::TimerCallbackHolder::Notify(nsITimer*)
RefPtr<nsGeolocationRequest> request(mRequest);
request->Notify();
}
return NS_OK;
}
@ -721,7 +675,6 @@ NS_IMPL_RELEASE(nsGeolocationService)
static bool sGeoEnabled = true;
static bool sGeoInitPending = true;
static int32_t sProviderTimeout = 6000; // Time, in milliseconds, to wait for the location provider to spin up.
nsresult nsGeolocationService::Init()
@ -734,28 +687,9 @@ nsresult nsGeolocationService::Init()
}
if (XRE_IsContentProcess()) {
sGeoInitPending = false;
return NS_OK;
}
// check if the geolocation service is enable from settings
nsCOMPtr<nsISettingsService> settings =
do_GetService("@mozilla.org/settingsService;1");
if (settings) {
nsCOMPtr<nsISettingsServiceLock> settingsLock;
nsresult rv = settings->CreateLock(nullptr, getter_AddRefs(settingsLock));
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<GeolocationSettingsCallback> callback = new GeolocationSettingsCallback();
rv = settingsLock->Get(GEO_SETTINGS_ENABLED, callback);
NS_ENSURE_SUCCESS(rv, rv);
} else {
// If we cannot obtain the settings service, we continue
// assuming that the geolocation is enabled:
sGeoInitPending = false;
}
// geolocation service can be enabled -> now register observer
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (!obs) {
@ -763,7 +697,6 @@ nsresult nsGeolocationService::Init()
}
obs->AddObserver(this, "xpcom-shutdown", false);
obs->AddObserver(this, "mozsettings-changed", false);
#ifdef MOZ_ENABLE_QT5GEOPOSITION
mProvider = new QTMLocationProvider();
@ -820,47 +753,6 @@ nsGeolocationService::~nsGeolocationService()
{
}
void
nsGeolocationService::HandleMozsettingChanged(nsISupports* aSubject)
{
// The string that we're interested in will be a JSON string that looks like:
// {"key":"gelocation.enabled","value":true}
RootedDictionary<SettingChangeNotification> setting(nsContentUtils::RootingCxForThread());
if (!WrappedJSToDictionary(aSubject, setting)) {
return;
}
if (!setting.mKey.EqualsASCII(GEO_SETTINGS_ENABLED)) {
return;
}
if (!setting.mValue.isBoolean()) {
return;
}
HandleMozsettingValue(setting.mValue.toBoolean());
}
void
nsGeolocationService::HandleMozsettingValue(const bool aValue)
{
if (!aValue) {
// turn things off
StopDevice();
Update(nullptr);
mLastPosition.position = nullptr;
sGeoEnabled = false;
} else {
sGeoEnabled = true;
}
if (sGeoInitPending) {
sGeoInitPending = false;
for (uint32_t i = 0, length = mGeolocators.Length(); i < length; ++i) {
mGeolocators[i]->ServiceReady();
}
}
}
NS_IMETHODIMP
nsGeolocationService::Observe(nsISupports* aSubject,
const char* aTopic,
@ -870,7 +762,6 @@ nsGeolocationService::Observe(nsISupports* aSubject,
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
obs->RemoveObserver(this, "xpcom-shutdown");
obs->RemoveObserver(this, "mozsettings-changed");
}
for (uint32_t i = 0; i< mGeolocators.Length(); i++) {
@ -881,11 +772,6 @@ nsGeolocationService::Observe(nsISupports* aSubject,
return NS_OK;
}
if (!strcmp("mozsettings-changed", aTopic)) {
HandleMozsettingChanged(aSubject);
return NS_OK;
}
if (!strcmp("timer-callback", aTopic)) {
// decide if we can close down the service.
for (uint32_t i = 0; i< mGeolocators.Length(); i++)
@ -909,17 +795,21 @@ nsGeolocationService::Update(nsIDOMGeoPosition *aSomewhere)
if (aSomewhere) {
SetCachedPosition(aSomewhere);
}
for (uint32_t i = 0; i< mGeolocators.Length(); i++) {
mGeolocators[i]->Update(aSomewhere);
}
return NS_OK;
}
NS_IMETHODIMP
nsGeolocationService::NotifyError(uint16_t aErrorCode)
{
for (uint32_t i = 0; i < mGeolocators.Length(); i++) {
mGeolocators[i]->NotifyError(aErrorCode);
}
return NS_OK;
}
@ -939,7 +829,7 @@ nsGeolocationService::GetCachedPosition()
nsresult
nsGeolocationService::StartDevice(nsIPrincipal *aPrincipal)
{
if (!sGeoEnabled || sGeoInitPending) {
if (!sGeoEnabled) {
return NS_ERROR_NOT_AVAILABLE;
}
@ -990,7 +880,6 @@ nsGeolocationService::StopDisconnectTimer()
}
}
void
nsGeolocationService::SetDisconnectTimer()
{
@ -1013,6 +902,7 @@ nsGeolocationService::HighAccuracyRequested()
return true;
}
}
return false;
}
@ -1026,17 +916,11 @@ nsGeolocationService::UpdateAccuracy(bool aForceHigh)
if (cpc->IsAlive()) {
cpc->SendSetGeolocationHigherAccuracy(highRequired);
}
return;
}
if (!mHigherAccuracy && highRequired) {
mProvider->SetHighAccuracy(true);
}
if (mHigherAccuracy && !highRequired) {
mProvider->SetHighAccuracy(false);
}
mProvider->SetHighAccuracy(!mHigherAccuracy && highRequired);
mHigherAccuracy = highRequired;
}
@ -1048,6 +932,7 @@ nsGeolocationService::StopDevice()
if (XRE_IsContentProcess()) {
ContentChild* cpc = ContentChild::GetSingleton();
cpc->SendRemoveGeolocationListener();
return; // bail early
}
@ -1083,8 +968,10 @@ nsGeolocationService::GetGeolocationService()
if (NS_FAILED(result->Init())) {
return nullptr;
}
ClearOnShutdown(&nsGeolocationService::sService);
nsGeolocationService::sService = result;
return result.forget();
}
@ -1187,21 +1074,21 @@ Geolocation::Init(nsPIDOMWindowInner* aContentDom)
if (mService) {
mService->AddLocator(this);
}
return NS_OK;
}
bool
Geolocation::ContainsRequest(nsGeolocationRequest* aRequest)
{
if (aRequest->IsWatch()) {
if (mWatchingCallbacks.Contains(aRequest)) {
if (aRequest->IsWatch() && mWatchingCallbacks.Contains(aRequest)) {
return true;
}
} else {
if (mPendingCallbacks.Contains(aRequest)) {
return true;
}
}
if (mPendingCallbacks.Contains(aRequest)) {
return true;
}
return false;
}
@ -1225,23 +1112,27 @@ Geolocation::HandleEvent(nsIDOMEvent* aEvent)
MOZ_ASSERT(XRE_IsContentProcess());
ContentChild* cpc = ContentChild::GetSingleton();
if (!info.lockingProcesses().Contains(cpc->GetID())) {
cpc->SendRemoveGeolocationListener();
mService->StopDisconnectTimer();
}
} else {
mService->SetDisconnectTimer();
// We will unconditionally allow all the requests in the callbacks
// because if a request is put into either of these two callbacks,
// it means that it has been allowed before.
// That's why when we resume them, we unconditionally allow them again.
for (uint32_t i = 0, length = mWatchingCallbacks.Length(); i < length; ++i) {
mWatchingCallbacks[i]->Allow(JS::UndefinedHandleValue);
}
for (uint32_t i = 0, length = mPendingCallbacks.Length(); i < length; ++i) {
mPendingCallbacks[i]->Allow(JS::UndefinedHandleValue);
}
return NS_OK;
}
mService->SetDisconnectTimer();
// We will unconditionally allow all the requests in the callbacks
// because if a request is put into either of these two callbacks,
// it means that it has been allowed before.
// That's why when we resume them, we unconditionally allow them again.
for (uint32_t i = 0, length = mWatchingCallbacks.Length(); i < length; ++i) {
mWatchingCallbacks[i]->Allow(JS::UndefinedHandleValue);
}
for (uint32_t i = 0, length = mPendingCallbacks.Length(); i < length; ++i) {
mPendingCallbacks[i]->Allow(JS::UndefinedHandleValue);
}
return NS_OK;
@ -1342,8 +1233,10 @@ Geolocation::Update(nsIDOMGeoPosition *aSomewhere)
for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
mWatchingCallbacks[i]->Update(aSomewhere);
}
return NS_OK;
}
NS_IMETHODIMP
Geolocation::NotifyError(uint16_t aErrorCode)
{
@ -1351,6 +1244,7 @@ Geolocation::NotifyError(uint16_t aErrorCode)
Shutdown();
return NS_OK;
}
mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_ERROR, true);
for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
@ -1374,6 +1268,7 @@ Geolocation::IsAlreadyCleared(nsGeolocationRequest* aRequest)
return true;
}
}
return false;
}
@ -1385,6 +1280,7 @@ Geolocation::ClearPendingRequest(nsGeolocationRequest* aRequest)
this->ClearWatch(aRequest->WatchId());
return true;
}
return false;
}
@ -1447,11 +1343,6 @@ Geolocation::GetCurrentPosition(GeoPositionCallback& callback,
return NS_ERROR_FAILURE;
}
if (sGeoInitPending) {
mPendingRequests.AppendElement(request);
return NS_OK;
}
return GetCurrentPositionReady(request);
}
@ -1541,11 +1432,6 @@ Geolocation::WatchPosition(GeoPositionCallback& aCallback,
return NS_ERROR_FAILURE;
}
if (sGeoInitPending) {
mPendingRequests.AppendElement(request);
return NS_OK;
}
return WatchPositionReady(request);
}

View File

@ -72,9 +72,6 @@ public:
nsresult Init();
void HandleMozsettingChanged(nsISupports* aSubject);
void HandleMozsettingValue(const bool aValue);
// Management of the Geolocation objects
void AddLocator(mozilla::dom::Geolocation* locator);
void RemoveLocator(mozilla::dom::Geolocation* locator);

65
dom/grid/Grid.cpp Normal file
View File

@ -0,0 +1,65 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Grid.h"
#include "GridDimension.h"
#include "mozilla/dom/GridBinding.h"
#include "nsGridContainerFrame.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Grid, mParent, mRows, mCols)
NS_IMPL_CYCLE_COLLECTING_ADDREF(Grid)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Grid)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Grid)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
Grid::Grid(nsISupports* aParent,
nsGridContainerFrame* aFrame)
: mParent(do_QueryInterface(aParent))
, mRows(new GridDimension(this))
, mCols(new GridDimension(this))
{
MOZ_ASSERT(aFrame,
"Should never be instantiated with a null nsGridContainerFrame");
const ComputedGridTrackInfo* rowTrackInfo = aFrame->GetComputedTemplateRows();
mRows->SetTrackInfo(rowTrackInfo);
mRows->SetLineInfo(rowTrackInfo);
const ComputedGridTrackInfo* colTrackInfo = aFrame->GetComputedTemplateColumns();
mCols->SetTrackInfo(colTrackInfo);
mCols->SetLineInfo(colTrackInfo);
}
Grid::~Grid()
{
}
JSObject*
Grid::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return GridBinding::Wrap(aCx, this, aGivenProto);
}
GridDimension*
Grid::Rows() const
{
return mRows;
}
GridDimension*
Grid::Cols() const
{
return mCols;
}
} // namespace dom
} // namespace mozilla

51
dom/grid/Grid.h Normal file
View File

@ -0,0 +1,51 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_Grid_h
#define mozilla_dom_Grid_h
#include "mozilla/dom/Element.h"
#include "nsGridContainerFrame.h"
#include "nsISupports.h"
#include "nsWrapperCache.h"
namespace mozilla {
namespace dom {
class GridDimension;
class Grid : public nsISupports
, public nsWrapperCache
{
public:
explicit Grid(nsISupports* aParent, nsGridContainerFrame* aFrame);
protected:
virtual ~Grid();
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Grid)
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
Element* GetParentObject()
{
return mParent;
}
GridDimension* Rows() const;
GridDimension* Cols() const;
protected:
nsCOMPtr<Element> mParent;
RefPtr<GridDimension> mRows;
RefPtr<GridDimension> mCols;
};
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_Grid_h */

View File

@ -0,0 +1,69 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GridDimension.h"
#include "Grid.h"
#include "GridLines.h"
#include "GridTracks.h"
#include "mozilla/dom/GridBinding.h"
#include "nsGridContainerFrame.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(GridDimension, mParent, mLines, mTracks)
NS_IMPL_CYCLE_COLLECTING_ADDREF(GridDimension)
NS_IMPL_CYCLE_COLLECTING_RELEASE(GridDimension)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GridDimension)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
GridDimension::GridDimension(Grid* aParent)
: mParent(aParent)
, mLines(new GridLines(this))
, mTracks(new GridTracks(this))
{
MOZ_ASSERT(aParent, "Should never be instantiated with a null Grid");
}
GridDimension::~GridDimension()
{
}
JSObject*
GridDimension::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return GridDimensionBinding::Wrap(aCx, this, aGivenProto);
}
GridLines*
GridDimension::Lines() const
{
return mLines;
}
GridTracks*
GridDimension::Tracks() const
{
return mTracks;
}
void
GridDimension::SetTrackInfo(const ComputedGridTrackInfo* aTrackInfo)
{
mTracks->SetTrackInfo(aTrackInfo);
}
void
GridDimension::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo)
{
mLines->SetLineInfo(aTrackInfo);
}
} // namespace dom
} // namespace mozilla

56
dom/grid/GridDimension.h Normal file
View File

@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_GridDimension_h
#define mozilla_dom_GridDimension_h
#include "nsWrapperCache.h"
namespace mozilla {
struct ComputedGridTrackInfo;
namespace dom {
class Grid;
class GridLines;
class GridTracks;
class GridDimension : public nsISupports
, public nsWrapperCache
{
public:
explicit GridDimension(Grid* aParent);
protected:
virtual ~GridDimension();
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(GridDimension)
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
Grid* GetParentObject()
{
return mParent;
}
GridLines* Lines() const;
GridTracks* Tracks() const;
void SetTrackInfo(const ComputedGridTrackInfo* aTrackInfo);
void SetLineInfo(const ComputedGridTrackInfo* aTrackInfo);
protected:
RefPtr<Grid> mParent;
RefPtr<GridLines> mLines;
RefPtr<GridTracks> mTracks;
};
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_GridDimension_h */

79
dom/grid/GridLine.cpp Normal file
View File

@ -0,0 +1,79 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GridLine.h"
#include "GridLines.h"
#include "mozilla/dom/GridBinding.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(GridLine, mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(GridLine)
NS_IMPL_CYCLE_COLLECTING_RELEASE(GridLine)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GridLine)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
GridLine::GridLine(GridLines *aParent)
: mParent(aParent)
, mStart(0.0)
, mBreadth(0.0)
, mNumber(0)
{
MOZ_ASSERT(aParent, "Should never be instantiated with a null GridLines");
}
GridLine::~GridLine()
{
}
void
GridLine::GetNames(nsTArray<nsString>& aNames) const
{
aNames = mNames;
}
JSObject*
GridLine::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return GridLineBinding::Wrap(aCx, this, aGivenProto);
}
double
GridLine::Start() const
{
return mStart;
}
double
GridLine::Breadth() const
{
return mBreadth;
}
uint32_t
GridLine::Number() const
{
return mNumber;
}
void
GridLine::SetLineValues(double aStart,
double aBreadth,
uint32_t aNumber,
const nsTArray<nsString>& aNames)
{
mStart = aStart;
mBreadth = aBreadth;
mNumber = aNumber;
mNames = aNames;
}
} // namespace dom
} // namespace mozilla

60
dom/grid/GridLine.h Normal file
View File

@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_GridLine_h
#define mozilla_dom_GridLine_h
#include "nsString.h"
#include "nsTArray.h"
#include "nsWrapperCache.h"
namespace mozilla {
namespace dom {
class GridLines;
class GridLine : public nsISupports
, public nsWrapperCache
{
public:
explicit GridLine(GridLines* aParent);
protected:
virtual ~GridLine();
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(GridLine)
void GetNames(nsTArray<nsString>& aNames) const;
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
GridLines* GetParentObject()
{
return mParent;
}
double Start() const;
double Breadth() const;
uint32_t Number() const;
void SetLineValues(double aStart,
double aBreadth,
uint32_t aNumber,
const nsTArray<nsString>& aNames);
protected:
RefPtr<GridLines> mParent;
double mStart;
double mBreadth;
uint32_t mNumber;
nsTArray<nsString> mNames;
};
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_GridLine_h */

108
dom/grid/GridLines.cpp Normal file
View File

@ -0,0 +1,108 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GridLines.h"
#include "GridDimension.h"
#include "GridLine.h"
#include "mozilla/dom/GridBinding.h"
#include "nsGridContainerFrame.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(GridLines, mParent, mLines)
NS_IMPL_CYCLE_COLLECTING_ADDREF(GridLines)
NS_IMPL_CYCLE_COLLECTING_RELEASE(GridLines)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GridLines)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
GridLines::GridLines(GridDimension* aParent)
: mParent(aParent)
{
MOZ_ASSERT(aParent,
"Should never be instantiated with a null GridDimension");
}
GridLines::~GridLines()
{
}
JSObject*
GridLines::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return GridLinesBinding::Wrap(aCx, this, aGivenProto);
}
uint32_t
GridLines::Length() const
{
return mLines.Length();
}
GridLine*
GridLines::Item(uint32_t aIndex)
{
return mLines.SafeElementAt(aIndex);
}
GridLine*
GridLines::IndexedGetter(uint32_t aIndex,
bool& aFound)
{
aFound = aIndex < mLines.Length();
if (!aFound) {
return nullptr;
}
return mLines[aIndex];
}
void
GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo)
{
mLines.Clear();
if (!aTrackInfo) {
return;
}
uint32_t trackCount = aTrackInfo->mEndFragmentTrack -
aTrackInfo->mStartFragmentTrack;
// If there is at least one track, line count is one more
// than the number of tracks.
if (trackCount > 0) {
double endOfLastTrack = 0.0;
double startOfNextTrack;
for (uint32_t i = aTrackInfo->mStartFragmentTrack;
i < aTrackInfo->mEndFragmentTrack + 1;
i++) {
startOfNextTrack = (i < aTrackInfo->mEndFragmentTrack) ?
aTrackInfo->mPositions[i] :
endOfLastTrack;
GridLine* line = new GridLine(this);
mLines.AppendElement(line);
line->SetLineValues(
nsPresContext::AppUnitsToDoubleCSSPixels(endOfLastTrack),
nsPresContext::AppUnitsToDoubleCSSPixels(startOfNextTrack -
endOfLastTrack),
i + 1,
nsTArray<nsString>()
);
if (i < aTrackInfo->mEndFragmentTrack) {
endOfLastTrack = aTrackInfo->mPositions[i] + aTrackInfo->mSizes[i];
}
}
}
}
} // namespace dom
} // namespace mozilla

52
dom/grid/GridLines.h Normal file
View File

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_GridLines_h
#define mozilla_dom_GridLines_h
#include "nsTArray.h"
#include "nsWrapperCache.h"
namespace mozilla {
namespace dom {
class GridDimension;
class GridLine;
class GridLines : public nsISupports
, public nsWrapperCache
{
public:
explicit GridLines(GridDimension* aParent);
protected:
virtual ~GridLines();
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(GridLines)
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
GridDimension* GetParentObject()
{
return mParent;
}
uint32_t Length() const;
GridLine* Item(uint32_t aIndex);
GridLine* IndexedGetter(uint32_t aIndex, bool& aFound);
void SetLineInfo(const ComputedGridTrackInfo* aTrackInfo);
protected:
RefPtr<GridDimension> mParent;
nsTArray<RefPtr<GridLine>> mLines;
};
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_GridLines_h */

80
dom/grid/GridTrack.cpp Normal file
View File

@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GridTrack.h"
#include "GridTracks.h"
#include "mozilla/dom/GridBinding.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(GridTrack, mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(GridTrack)
NS_IMPL_CYCLE_COLLECTING_RELEASE(GridTrack)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GridTrack)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
GridTrack::GridTrack(GridTracks* aParent)
: mParent(aParent)
, mStart(0.0)
, mBreadth(0.0)
, mType(GridTrackType::Implicit)
, mState(GridTrackState::Static)
{
MOZ_ASSERT(aParent, "Should never be instantiated with a null GridTracks");
}
GridTrack::~GridTrack()
{
}
JSObject*
GridTrack::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return GridTrackBinding::Wrap(aCx, this, aGivenProto);
}
double
GridTrack::Start() const
{
return mStart;
}
double
GridTrack::Breadth() const
{
return mBreadth;
}
GridTrackType
GridTrack::Type() const
{
return mType;
}
GridTrackState
GridTrack::State() const
{
return mState;
}
void
GridTrack::SetTrackValues(double aStart,
double aBreadth,
GridTrackType aType,
GridTrackState aState)
{
mStart = aStart;
mBreadth = aBreadth;
mType = aType;
mState = aState;
}
} // namespace dom
} // namespace mozilla

55
dom/grid/GridTrack.h Normal file
View File

@ -0,0 +1,55 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_GridTrack_h
#define mozilla_dom_GridTrack_h
#include "mozilla/dom/GridBinding.h"
#include "nsWrapperCache.h"
namespace mozilla {
namespace dom {
class GridTracks;
class GridTrack : public nsISupports
, public nsWrapperCache
{
public:
explicit GridTrack(GridTracks *parent);
protected:
virtual ~GridTrack();
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(GridTrack)
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
GridTracks* GetParentObject()
{
return mParent;
}
double Start() const;
double Breadth() const;
GridTrackType Type() const;
GridTrackState State() const;
void SetTrackValues(double aStart, double aBreadth, GridTrackType aType, GridTrackState aState);
protected:
RefPtr<GridTracks> mParent;
double mStart;
double mBreadth;
GridTrackType mType;
GridTrackState mState;
};
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_GridTrack_h */

98
dom/grid/GridTracks.cpp Normal file
View File

@ -0,0 +1,98 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GridTracks.h"
#include "GridDimension.h"
#include "GridTrack.h"
#include "mozilla/dom/GridBinding.h"
#include "nsGridContainerFrame.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(GridTracks, mParent, mTracks)
NS_IMPL_CYCLE_COLLECTING_ADDREF(GridTracks)
NS_IMPL_CYCLE_COLLECTING_RELEASE(GridTracks)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GridTracks)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
GridTracks::GridTracks(GridDimension *aParent)
: mParent(aParent)
{
MOZ_ASSERT(aParent,
"Should never be instantiated with a null GridDimension");
}
GridTracks::~GridTracks()
{
}
JSObject*
GridTracks::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return GridTracksBinding::Wrap(aCx, this, aGivenProto);
}
uint32_t
GridTracks::Length() const
{
return mTracks.Length();
}
GridTrack*
GridTracks::Item(uint32_t aIndex)
{
return mTracks.SafeElementAt(aIndex);
}
GridTrack*
GridTracks::IndexedGetter(uint32_t aIndex,
bool& aFound)
{
aFound = aIndex < mTracks.Length();
if (!aFound) {
return nullptr;
}
return mTracks[aIndex];
}
void
GridTracks::SetTrackInfo(const ComputedGridTrackInfo* aTrackInfo)
{
// rebuild the tracks based on aTrackInfo
mTracks.Clear();
if (!aTrackInfo) {
return;
}
for (size_t i = aTrackInfo->mStartFragmentTrack;
i < aTrackInfo->mEndFragmentTrack;
i++) {
GridTrack* track = new GridTrack(this);
mTracks.AppendElement(track);
track->SetTrackValues(
nsPresContext::AppUnitsToDoubleCSSPixels(aTrackInfo->mPositions[i]),
nsPresContext::AppUnitsToDoubleCSSPixels(aTrackInfo->mSizes[i]),
(
// Implicit if index is before the first explicit track, or after
// the last explicit track.
(i < aTrackInfo->mNumLeadingImplicitTracks) ||
(i >= aTrackInfo->mNumLeadingImplicitTracks +
aTrackInfo->mNumExplicitTracks) ?
GridTrackType::Implicit :
GridTrackType::Explicit
),
GridTrackState(aTrackInfo->mStates[i])
);
}
}
} // namespace dom
} // namespace mozilla

55
dom/grid/GridTracks.h Normal file
View File

@ -0,0 +1,55 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_GridTracks_h
#define mozilla_dom_GridTracks_h
#include "nsTArray.h"
#include "nsWrapperCache.h"
namespace mozilla {
struct ComputedGridTrackInfo;
namespace dom {
class GridDimension;
class GridTrack;
class GridTracks : public nsISupports
, public nsWrapperCache
{
public:
explicit GridTracks(GridDimension* aParent);
protected:
virtual ~GridTracks();
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(GridTracks)
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
GridDimension* GetParentObject()
{
return mParent;
}
uint32_t Length() const;
GridTrack* Item(uint32_t aIndex);
GridTrack* IndexedGetter(uint32_t aIndex, bool& aFound);
void SetTrackInfo(const mozilla::ComputedGridTrackInfo* aTrackInfo);
protected:
RefPtr<GridDimension> mParent;
nsTArray<RefPtr<GridTrack>> mTracks;
};
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_GridTracks_h */

31
dom/grid/moz.build Normal file
View File

@ -0,0 +1,31 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
EXPORTS.mozilla.dom += [
'Grid.h',
'GridDimension.h',
'GridLine.h',
'GridLines.h',
'GridTrack.h',
'GridTracks.h',
]
UNIFIED_SOURCES += [
'Grid.cpp',
'GridDimension.cpp',
'GridLine.cpp',
'GridLines.cpp',
'GridTrack.cpp',
'GridTracks.cpp',
]
LOCAL_INCLUDES += [
'/layout/generic',
]
FINAL_LIBRARY = 'xul'

3
dom/grid/test/chrome.ini Normal file
View File

@ -0,0 +1,3 @@
[chrome/test_grid_object.html]
[chrome/test_grid_state.html]
[chrome/test_grid_repeats.html]

View File

@ -0,0 +1,92 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<style>
body {
margin: 40px;
}
.wrapper {
display: grid;
width: 400px;
grid-gap: 10px;
grid-template-columns: 100px 1fr 1fr 100px;
background-color: #f00;
}
.box {
background-color: #444;
color: #fff;
}
</style>
<script>
'use strict';
SimpleTest.waitForExplicitFinish();
function runTests() {
var wrapper = document.getElementById("wrapper");
var boxA = document.getElementById("boxA");
var boxB = document.getElementById("boxB");
var boxC = document.getElementById("boxC");
// test function existence
is(typeof(wrapper.getGridFragments), "function",
"getGridFragments function exists."
);
// test that display:grid elements have grids and display:block elements don't
is(boxA.getGridFragments().length, 0, "No grid on display:block styled objects.");
is(wrapper.getGridFragments().length, 1,
"One grid on an un-fragmented display:grid styled object."
);
var grid = wrapper.getGridFragments()[0];
// test column and row track counts
is(grid.cols.tracks.length, 4,
"Grid.cols.tracks property has length that matches grid-template-columns."
);
is(grid.rows.tracks.length, 2,
"Grid.rows.tracks property has length that matches content."
);
// test column track position
is(grid.cols.tracks[1].start, 110, "Grid column track 1 position is as expected.");
// test column track width
is(grid.cols.tracks[0].breadth, boxA.offsetWidth,
"Grid column track width (fixed size) matches item width."
);
is(grid.cols.tracks[1].breadth, boxB.offsetWidth,
"Grid column track width (flexible size) matches item width."
);
is(grid.cols.tracks[1].breadth, grid.cols.tracks[2].breadth,
"Grid column track widths with equal proportion flexible size actually are same size."
);
// test explicit / implicit tracks
is(grid.cols.tracks[0].type, "explicit", "Grid column track 0 is explicit.");
is(grid.rows.tracks[0].type, "implicit", "Grid row track 0 is implicit.");
SimpleTest.finish();
}
</script>
</head>
<body onLoad="runTests();">
<div id="wrapper" class="wrapper">
<div id="boxA" class="box a">A</div>
<div id="boxB" class="box b">B</div>
<div id="boxC" class="box c">C</div>
<div class="box d">D</div>
<div class="box e">E</div>
<div class="box f">F</div>
<div class="box g">G</div>
<div class="box h">H</div>
</div>
</body>
</html>

View File

@ -0,0 +1,53 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<style>
body {
margin: 40px;
}
.wrapper {
display: grid;
width: 600px;
grid-gap: 10px;
grid-template-columns: repeat(2, 100px) repeat(auto-fill, 50px);
background-color: #f00;
}
.box {
background-color: #444;
color: #fff;
}
</style>
<script>
'use strict';
SimpleTest.waitForExplicitFinish();
function runTests() {
var wrapper = document.getElementById("wrapper");
var grid = wrapper.getGridFragments()[0];
// test state of tracks
is(grid.cols.tracks[1].state, "static", "Grid column track 1 is marked as static.");
is(grid.cols.tracks[2].state, "repeat", "Grid column track 2 is marked as repeat.");
SimpleTest.finish();
}
</script>
</head>
<body onLoad="runTests();">
<div id="wrapper" class="wrapper">
<div id="boxA" class="box a">A</div>
<div class="box b">B</div>
<div class="box c">C</div>
<div class="box d">D</div>
<div class="box e">E</div>
</div>
</body>
</html>

View File

@ -0,0 +1,54 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<style>
body {
margin: 40px;
}
.wrapper {
display: grid;
width: 600px;
grid-gap: 0px;
grid-template-columns: 50px repeat(auto-fit, 100px);
background-color: #f00;
}
.box {
background-color: #444;
color: #fff;
}
.a {
grid-column: 3;
}
</style>
<script>
'use strict';
SimpleTest.waitForExplicitFinish();
function runTests() {
var wrapper = document.getElementById("wrapper");
var grid = wrapper.getGridFragments()[0];
// test count after removal
is(grid.cols.tracks.length, 2, "Grid column track array compensates for removed auto-fit columns.");
// test state of tracks
is(grid.cols.tracks[0].state, "static", "Grid column track 0 is marked as static.");
is(grid.cols.tracks[1].state, "repeat", "Grid column track 1 is marked as repeat.");
SimpleTest.finish();
}
</script>
</head>
<body onLoad="runTests();">
<div id="wrapper" class="wrapper">
<div id="boxA" class="box a">A</div>
</div>
</body>
</html>

View File

@ -2253,7 +2253,7 @@ HTMLInputElement::ConvertStringToNumber(nsAString& aValue,
case NS_FORM_INPUT_DATE:
{
uint32_t year, month, day;
if (!GetValueAsDate(aValue, &year, &month, &day)) {
if (!ParseDate(aValue, &year, &month, &day)) {
return false;
}
@ -2510,7 +2510,7 @@ HTMLInputElement::GetValueAsDate(ErrorResult& aRv)
uint32_t year, month, day;
nsAutoString value;
GetValueInternal(value);
if (!GetValueAsDate(value, &year, &month, &day)) {
if (!ParseDate(value, &year, &month, &day)) {
return Nullable<Date>();
}
@ -5341,6 +5341,13 @@ HTMLInputElement::SanitizeValue(nsAString& aValue)
}
}
break;
case NS_FORM_INPUT_MONTH:
{
if (!aValue.IsEmpty() && !IsValidMonth(aValue)) {
aValue.Truncate();
}
}
break;
case NS_FORM_INPUT_COLOR:
{
if (IsValidSimpleColor(aValue)) {
@ -5371,19 +5378,57 @@ bool HTMLInputElement::IsValidSimpleColor(const nsAString& aValue) const
}
bool
HTMLInputElement::IsValidDate(const nsAString& aValue) const
HTMLInputElement::IsValidMonth(const nsAString& aValue) const
{
uint32_t year, month, day;
return GetValueAsDate(aValue, &year, &month, &day);
uint32_t year, month;
return ParseMonth(aValue, &year, &month);
}
bool
HTMLInputElement::GetValueAsDate(const nsAString& aValue,
HTMLInputElement::IsValidDate(const nsAString& aValue) const
{
uint32_t year, month, day;
return ParseDate(aValue, &year, &month, &day);
}
bool HTMLInputElement::ParseYear(const nsAString& aValue, uint32_t* aYear) const
{
if (aValue.Length() < 4) {
return false;
}
return DigitSubStringToNumber(aValue, 0, aValue.Length(), aYear) &&
*aYear > 0;
}
bool HTMLInputElement::ParseMonth(const nsAString& aValue,
uint32_t* aYear,
uint32_t* aMonth) const
{
// Parse the year, month values out a string formatted as 'yyyy-mm'.
if (aValue.Length() < 7) {
return false;
}
uint32_t endOfYearOffset = aValue.Length() - 3;
if (aValue[endOfYearOffset] != '-') {
return false;
}
const nsAString& yearStr = Substring(aValue, 0, endOfYearOffset);
if (!ParseYear(yearStr, aYear)) {
return false;
}
return DigitSubStringToNumber(aValue, endOfYearOffset + 1, 2, aMonth) &&
*aMonth > 0 && *aMonth <= 12;
}
bool HTMLInputElement::ParseDate(const nsAString& aValue,
uint32_t* aYear,
uint32_t* aMonth,
uint32_t* aDay) const
{
/*
* Parse the year, month, day values out a date string formatted as 'yyyy-mm-dd'.
* -The year must be 4 or more digits long, and year > 0
@ -5391,29 +5436,21 @@ HTMLInputElement::GetValueAsDate(const nsAString& aValue,
* -The day must be exactly 2 digit long, and 01 <= day <= maxday
* Where maxday is the number of days in the month 'month' and year 'year'
*/
if (aValue.Length() < 10) {
return false;
}
uint32_t endOfYearOffset = aValue.Length() - 6;
if (aValue[endOfYearOffset] != '-' ||
aValue[endOfYearOffset + 3] != '-') {
uint32_t endOfMonthOffset = aValue.Length() - 3;
if (aValue[endOfMonthOffset] != '-') {
return false;
}
if (!DigitSubStringToNumber(aValue, 0, endOfYearOffset, aYear) ||
*aYear < 1) {
const nsAString& yearMonthStr = Substring(aValue, 0, endOfMonthOffset);
if (!ParseMonth(yearMonthStr, aYear, aMonth)) {
return false;
}
if (!DigitSubStringToNumber(aValue, endOfYearOffset + 1, 2, aMonth) ||
*aMonth < 1 || *aMonth > 12) {
return false;
}
return DigitSubStringToNumber(aValue, endOfYearOffset + 4, 2, aDay) &&
return DigitSubStringToNumber(aValue, endOfMonthOffset + 1, 2, aDay) &&
*aDay > 0 && *aDay <= NumberOfDaysInMonth(*aMonth, *aYear);
}

View File

@ -1151,6 +1151,14 @@ protected:
*/
bool IsValidSimpleColor(const nsAString& aValue) const;
/**
* Parse a date string of the form yyyy-mm
* @param the string to be parsed.
* @return whether the string is a valid month.
* Note : this function does not consider the empty string as valid.
*/
bool IsValidMonth(const nsAString& aValue) const;
/**
* Parse a date string of the form yyyy-mm-dd
* @param the string to be parsed.
@ -1159,16 +1167,38 @@ protected:
*/
bool IsValidDate(const nsAString& aValue) const;
/**
* Parse a year string of the form yyyy
*
* @param the string to be parsed.
*
* @return the year in aYear.
* @return whether the parsing was successful.
*/
bool ParseYear(const nsAString& aValue, uint32_t* aYear) const;
/**
* Parse a month string of the form yyyy-mm
*
* @param the string to be parsed.
* @return the year and month in aYear and aMonth.
* @return whether the parsing was successful.
*/
bool ParseMonth(const nsAString& aValue,
uint32_t* aYear,
uint32_t* aMonth) const;
/**
* Parse a date string of the form yyyy-mm-dd
*
* @param the string to be parsed.
* @return the date in aYear, aMonth, aDay.
* @return whether the parsing was successful.
*/
bool GetValueAsDate(const nsAString& aValue,
uint32_t* aYear,
uint32_t* aMonth,
uint32_t* aDay) const;
bool ParseDate(const nsAString& aValue,
uint32_t* aYear,
uint32_t* aMonth,
uint32_t* aDay) const;
/**
* This methods returns the number of days in a given month, for a given year.

View File

@ -69,6 +69,7 @@
#include "mozilla/dom/MediaSource.h"
#include "MediaMetadataManager.h"
#include "MediaSourceDecoder.h"
#include "MediaStreamListener.h"
#include "DOMMediaStream.h"
#include "AudioStreamTrack.h"
#include "VideoStreamTrack.h"
@ -273,6 +274,56 @@ public:
}
};
/**
* This listener observes the first video frame to arrive with a non-empty size,
* and calls HTMLMediaElement::ReceivedMediaStreamInitialSize() with that size.
*/
class HTMLMediaElement::StreamSizeListener : public DirectMediaStreamTrackListener {
public:
explicit StreamSizeListener(HTMLMediaElement* aElement) :
mElement(aElement),
mInitialSizeFound(false)
{}
void Forget() { mElement = nullptr; }
void ReceivedSize(gfx::IntSize aSize)
{
if (!mElement) {
return;
}
RefPtr<HTMLMediaElement> deathGrip = mElement;
mElement->UpdateInitialMediaSize(aSize);
}
void NotifyRealtimeTrackData(MediaStreamGraph* aGraph,
StreamTime aTrackOffset,
const MediaSegment& aMedia) override
{
if (mInitialSizeFound || aMedia.GetType() != MediaSegment::VIDEO) {
return;
}
const VideoSegment& video = static_cast<const VideoSegment&>(aMedia);
for (VideoSegment::ConstChunkIterator c(video); !c.IsEnded(); c.Next()) {
if (c->mFrame.GetIntrinsicSize() != gfx::IntSize(0,0)) {
mInitialSizeFound = true;
nsCOMPtr<nsIRunnable> event =
NewRunnableMethod<gfx::IntSize>(
this, &StreamSizeListener::ReceivedSize,
c->mFrame.GetIntrinsicSize());
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
return;
}
}
}
private:
// These fields may only be accessed on the main thread
HTMLMediaElement* mElement;
// These fields may only be accessed on the MSG thread
bool mInitialSizeFound;
};
/**
* There is a reference cycle involving this class: MediaLoadListener
* holds a reference to the HTMLMediaElement, which holds a reference
@ -656,6 +707,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTM
#ifdef MOZ_EME
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeys)
#endif
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectedVideoStreamTrack)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
@ -682,6 +734,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLE
#ifdef MOZ_EME
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaKeys)
#endif
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectedVideoStreamTrack)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLMediaElement)
@ -880,6 +933,14 @@ void HTMLMediaElement::AbortExistingLoads()
bool fireTimeUpdate = false;
// We need to remove StreamSizeListener before VideoTracks get emptied.
if (mMediaStreamSizeListener) {
mSelectedVideoStreamTrack->RemoveDirectListener(mMediaStreamSizeListener);
mSelectedVideoStreamTrack = nullptr;
mMediaStreamSizeListener->Forget();
mMediaStreamSizeListener = nullptr;
}
// When aborting the existing loads, empty the objects in audio track list and
// video track list, no events (in particular, no removetrack events) are
// fired as part of this. Ending MediaStream sends track ended notifications,
@ -3336,9 +3397,9 @@ public:
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
}
virtual void NotifyEvent(MediaStreamGraph* aGraph,
MediaStreamListener::MediaStreamGraphEvent event) override
MediaStreamGraphEvent event) override
{
if (event == EVENT_FINISHED) {
if (event == MediaStreamGraphEvent::EVENT_FINISHED) {
nsCOMPtr<nsIRunnable> event =
NewRunnableMethod(this, &StreamListener::DoNotifyFinished);
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
@ -3375,59 +3436,6 @@ private:
bool mPendingNotifyOutput;
};
/**
* This listener observes the first video frame to arrive with a non-empty size,
* and calls HTMLMediaElement::ReceivedMediaStreamInitialSize() with that size.
*/
class HTMLMediaElement::StreamSizeListener : public MediaStreamListener {
public:
explicit StreamSizeListener(HTMLMediaElement* aElement) :
mElement(aElement),
mInitialSizeFound(false)
{}
void Forget() { mElement = nullptr; }
void ReceivedSize(gfx::IntSize aSize)
{
if (!mElement) {
return;
}
RefPtr<HTMLMediaElement> deathGrip = mElement;
mElement->UpdateInitialMediaSize(aSize);
}
void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset,
uint32_t aTrackEvents,
const MediaSegment& aQueuedMedia,
MediaStream* aInputStream,
TrackID aInputTrackID) override
{
if (mInitialSizeFound || aQueuedMedia.GetType() != MediaSegment::VIDEO) {
return;
}
const VideoSegment& video = static_cast<const VideoSegment&>(aQueuedMedia);
for (VideoSegment::ConstChunkIterator c(video); !c.IsEnded(); c.Next()) {
if (c->mFrame.GetIntrinsicSize() != gfx::IntSize(0,0)) {
mInitialSizeFound = true;
nsCOMPtr<nsIRunnable> event =
NewRunnableMethod<gfx::IntSize>(
this, &StreamSizeListener::ReceivedSize,
c->mFrame.GetIntrinsicSize());
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
return;
}
}
}
private:
// These fields may only be accessed on the main thread
HTMLMediaElement* mElement;
// These fields may only be accessed on the MSG thread
bool mInitialSizeFound;
};
class HTMLMediaElement::MediaStreamTracksAvailableCallback:
public OnTracksAvailableCallback
{
@ -3546,9 +3554,6 @@ void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
RefPtr<MediaStream> stream = GetSrcMediaStream();
if (stream) {
stream->SetAudioChannelType(mAudioChannel);
mMediaStreamSizeListener = new StreamSizeListener(this);
stream->AddListener(mMediaStreamSizeListener);
}
UpdateSrcMediaStreamPlaying();
@ -3579,10 +3584,8 @@ void HTMLMediaElement::EndSrcMediaStreamPlayback()
UpdateSrcMediaStreamPlaying(REMOVING_SRC_STREAM);
if (mMediaStreamSizeListener) {
RefPtr<MediaStream> stream = GetSrcMediaStream();
if (stream) {
stream->RemoveListener(mMediaStreamSizeListener);
}
mSelectedVideoStreamTrack->RemoveDirectListener(mMediaStreamSizeListener);
mSelectedVideoStreamTrack = nullptr;
mMediaStreamSizeListener->Forget();
mMediaStreamSizeListener = nullptr;
}
@ -3618,7 +3621,8 @@ CreateVideoTrack(VideoStreamTrack* aStreamTrack)
aStreamTrack->GetLabel(label);
return MediaTrackList::CreateVideoTrack(id, NS_LITERAL_STRING("main"),
label, EmptyString());
label, EmptyString(),
aStreamTrack);
}
void HTMLMediaElement::ConstructMediaTracks()
@ -3650,6 +3654,11 @@ void HTMLMediaElement::ConstructMediaTracks()
// must be selected.
int index = firstEnabledVideo >= 0 ? firstEnabledVideo : 0;
(*VideoTracks())[index]->SetEnabledInternal(true, MediaTrack::FIRE_NO_EVENTS);
VideoTrack* track = (*VideoTracks())[index];
VideoStreamTrack* streamTrack = track->GetVideoStreamTrack();
mMediaStreamSizeListener = new StreamSizeListener(this);
streamTrack->AddDirectListener(mMediaStreamSizeListener);
mSelectedVideoStreamTrack = streamTrack;
}
}
@ -3670,8 +3679,20 @@ HTMLMediaElement::NotifyMediaStreamTrackAdded(const RefPtr<MediaStreamTrack>& aT
RefPtr<AudioTrack> audioTrack = CreateAudioTrack(t);
AudioTracks()->AddTrack(audioTrack);
} else if (VideoStreamTrack* t = aTrack->AsVideoStreamTrack()) {
// TODO: Fix this per the spec on bug 1273443.
int32_t selectedIndex = VideoTracks()->SelectedIndex();
RefPtr<VideoTrack> videoTrack = CreateVideoTrack(t);
VideoTracks()->AddTrack(videoTrack);
// New MediaStreamTrack added, set the new added video track as selected
// video track when there is no selected track.
if (selectedIndex == -1) {
MOZ_ASSERT(!mSelectedVideoStreamTrack);
videoTrack->SetEnabledInternal(true, MediaTrack::FIRE_NO_EVENTS);
mMediaStreamSizeListener = new StreamSizeListener(this);
t->AddDirectListener(mMediaStreamSizeListener);
mSelectedVideoStreamTrack = t;
}
}
}
@ -3690,6 +3711,48 @@ HTMLMediaElement::NotifyMediaStreamTrackRemoved(const RefPtr<MediaStreamTrack>&
AudioTracks()->RemoveTrack(t);
} else if (MediaTrack* t = VideoTracks()->GetTrackById(id)) {
VideoTracks()->RemoveTrack(t);
// TODO: Fix this per the spec on bug 1273443.
// If the removed media stream track is selected video track and there are
// still video tracks, change the selected video track to the first
// remaining track.
if (aTrack == mSelectedVideoStreamTrack) {
// The mMediaStreamSizeListener might already reset to nullptr.
if (mMediaStreamSizeListener) {
mSelectedVideoStreamTrack->RemoveDirectListener(mMediaStreamSizeListener);
}
mSelectedVideoStreamTrack = nullptr;
MOZ_ASSERT(mSrcStream);
nsTArray<RefPtr<VideoStreamTrack>> tracks;
mSrcStream->GetVideoTracks(tracks);
for (const RefPtr<VideoStreamTrack>& track : tracks) {
if (track->Ended()) {
continue;
}
if (!track->Enabled()) {
continue;
}
nsAutoString trackId;
track->GetId(trackId);
MediaTrack* videoTrack = VideoTracks()->GetTrackById(trackId);
MOZ_ASSERT(videoTrack);
videoTrack->SetEnabledInternal(true, MediaTrack::FIRE_NO_EVENTS);
if (mMediaStreamSizeListener) {
track->AddDirectListener(mMediaStreamSizeListener);
}
mSelectedVideoStreamTrack = track;
return;
}
// There is no enabled video track existing, clean the
// mMediaStreamSizeListener.
if (mMediaStreamSizeListener) {
mMediaStreamSizeListener->Forget();
mMediaStreamSizeListener = nullptr;
}
}
} else {
// XXX (bug 1208328) Uncomment this when DOMMediaStream doesn't call
// NotifyTrackRemoved multiple times for the same track, i.e., when it
@ -4608,10 +4671,7 @@ void HTMLMediaElement::UpdateInitialMediaSize(const nsIntSize& aSize)
if (!mMediaStreamSizeListener) {
return;
}
RefPtr<MediaStream> stream = GetSrcMediaStream();
if (stream) {
stream->RemoveListener(mMediaStreamSizeListener);
}
mSelectedVideoStreamTrack->RemoveDirectListener(mMediaStreamSizeListener);
mMediaStreamSizeListener->Forget();
mMediaStreamSizeListener = nullptr;
}

View File

@ -1247,6 +1247,8 @@ protected:
// Holds a reference to the size-getting MediaStreamListener attached to
// mSrcStream.
RefPtr<StreamSizeListener> mMediaStreamSizeListener;
// The selected video stream track which contained mMediaStreamSizeListener.
RefPtr<VideoStreamTrack> mSelectedVideoStreamTrack;
const RefPtr<ShutdownObserver> mShutdownObserver;

View File

@ -74,7 +74,7 @@ var inputTypes =
[
"text", "password", "search", "tel", "hidden", "checkbox", "radio",
"submit", "image", "reset", "button", "email", "url", "number", "date",
"time", "range", "color"
"time", "range", "color", "month"
];
var todoTypes =
@ -176,6 +176,20 @@ function sanitizeValue(aType, aValue)
}
return aValue;
case "month":
// https://html.spec.whatwg.org/multipage/infrastructure.html#valid-month-string
var match = /^([0-9]{4,})-([0-9]{2})$/.exec(aValue);
if (!match) {
return "";
}
var year = Number(match[1]);
if (year === 0) {
return "";
}
var month = Number(match[2]);
if (month > 12 || month < 1) {
return "";
}
return aValue;
case "week":
case "datetime":
case "datetime-local":
@ -330,6 +344,27 @@ function checkSanitizing(element, inputTypeDescription)
"FFAAZZ",
"ABCDEF",
"#7654321",
// For month
"1970-01",
"1234-12",
"123456789-01",
"2013-13",
"0000-00",
"2015-00",
"0001-01",
"1-1",
"888-05",
"2013-3",
"2013-may",
"2000-1a",
"2013-03-13",
"december",
"abcdef",
"12",
" 2013-03",
"2013 - 03",
"2013 03",
"2013/03",
];
for (value of testData) {

View File

@ -181,6 +181,23 @@ function runTest()
'23:08:09.1012',
]
},
{
type: 'month',
validData: [
'0001-01',
'2012-12',
'100000-01',
],
invalidData: [
'1-01',
'-',
'december',
'2012-dec',
'2012/12',
'2012-99',
'2012-1',
]
},
{ type: 'week', todo: true },
{ type: 'datetime', todo: true },
{ type: 'datetime-local', todo: true },

View File

@ -47,7 +47,7 @@ var todoTypes = [
"datetime", "week", "datetime-local"
];
var nonTrivialSanitizing = [ 'number', 'date', 'time', 'color' ];
var nonTrivialSanitizing = [ 'number', 'date', 'time', 'color', 'month' ];
var length = testData.length;
for (var i=0; i<length; ++i) {
@ -60,7 +60,8 @@ for (var i=0; i<length; ++i) {
// range will sanitize its value to 50 (the default) if it isn't a valid
// number. We need to handle that specially.
if (testData[j][0] == 'range' || testData[i][0] == 'range') {
if (testData[j][0] == 'date' || testData[j][0] == 'time') {
if (testData[j][0] == 'date' || testData[j][0] == 'time' ||
testData[j][0] == 'month') {
expectedValue = '';
} else if (testData[j][0] == 'color') {
expectedValue = '#000000';
@ -69,7 +70,7 @@ for (var i=0; i<length; ++i) {
}
} else if (testData[i][0] == 'color' || testData[j][0] == 'color') {
if (testData[j][0] == 'number' || testData[j][0] == 'date' ||
testData[j][0] == 'time') {
testData[j][0] == 'time' || testData[j][0] == 'month') {
expectedValue = ''
} else {
expectedValue = '#000000';

View File

@ -28,8 +28,6 @@ ContentBridgeChild::ContentBridgeChild(Transport* aTransport)
ContentBridgeChild::~ContentBridgeChild()
{
RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTransport);
XRE_GetIOMessageLoop()->PostTask(task.forget());
}
void

View File

@ -27,8 +27,6 @@ ContentBridgeParent::ContentBridgeParent(Transport* aTransport)
ContentBridgeParent::~ContentBridgeParent()
{
RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTransport);
XRE_GetIOMessageLoop()->PostTask(task.forget());
}
void

View File

@ -2271,8 +2271,6 @@ ContentParent::ContentParent(mozIApplication* aApp,
? base::PRIVILEGES_INHERIT
: base::PRIVILEGES_DEFAULT;
mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content, privs);
IToplevelProtocol::SetTransport(mSubprocess->GetChannel());
}
#ifdef MOZ_NUWA_PROCESS
@ -2477,6 +2475,14 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
#endif
MaybeFileDesc brokerFd = void_t();
#ifdef XP_LINUX
// XXX: Checking the pref here makes it possible to enable/disable sandboxing
// during an active session. Currently the pref is only used for testing
// purpose. If the decision is made to permanently rely on the pref, this
// should be changed so that it is required to restart firefox for the change
// of value to take effect.
shouldSandbox = (Preferences::GetInt("security.sandbox.content.level") > 0) &&
!PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX");
if (shouldSandbox) {
MOZ_ASSERT(!mSandboxBroker);
UniquePtr<SandboxBroker::Policy> policy =

View File

@ -162,20 +162,17 @@ public:
mActor = nullptr;
}
/** Sets the information associated with this hang: this includes the ID of
* the plugin which caused the hang as well as the content PID.
/**
* Sets the information associated with this hang: this includes the ID of
* the plugin which caused the hang as well as the content PID. The ID of
* a minidump taken during the hang can also be provided.
*
* @param aHangData The hang information
* @param aDumpId The ID of a minidump taken when the hang occurred
*/
void SetHangData(const HangData& aHangData) { mHangData = aHangData; }
/** Sets the ID of the crash dump associated with this hang. When the ID has
* been set then the corresponding crash dump will be used for reporting
* instead of generating a new one.
*
* @param aId The ID of the crash dump taken when the hang was detected. */
void SetDumpId(nsString& aId) {
mDumpId = aId;
void SetHangData(const HangData& aHangData, const nsAString& aDumpId) {
mHangData = aHangData;
mDumpId = aDumpId;
}
void ClearHang() {
@ -216,9 +213,17 @@ public:
void EndStartingDebugger();
void CleanupPluginHang(uint32_t aPluginId, bool aRemoveFiles);
/**
* Update the dump for the specified plugin. This method is thread-safe and
* is used to replace a browser minidump with a full minidump. If aDumpId is
* empty this is a no-op.
*/
void UpdateMinidump(uint32_t aPluginId, const nsString& aDumpId);
MessageLoop* MonitorLoop() { return mHangMonitor->MonitorLoop(); }
private:
private:
bool TakeBrowserMinidump(const PluginHangData& aPhd, nsString& aCrashId);
void ShutdownOnThread();
const RefPtr<ProcessHangMonitor> mHangMonitor;
@ -258,11 +263,6 @@ HangMonitorChild::HangMonitorChild(ProcessHangMonitor* aMonitor)
HangMonitorChild::~HangMonitorChild()
{
// For some reason IPDL doesn't automatically delete the channel for a
// bridged protocol (bug 1090570). So we have to do it ourselves.
RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
XRE_GetIOMessageLoop()->PostTask(task.forget());
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_ASSERT(sInstance == this);
sInstance = nullptr;
@ -475,11 +475,6 @@ HangMonitorParent::HangMonitorParent(ProcessHangMonitor* aMonitor)
HangMonitorParent::~HangMonitorParent()
{
// For some reason IPDL doesn't automatically delete the channel for a
// bridged protocol (bug 1090570). So we have to do it ourselves.
RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
XRE_GetIOMessageLoop()->PostTask(task.forget());
#ifdef MOZ_CRASHREPORTER
MutexAutoLock lock(mBrowserCrashDumpHashLock);
@ -550,11 +545,15 @@ class HangObserverNotifier final : public Runnable
{
public:
HangObserverNotifier(HangMonitoredProcess* aProcess,
HangMonitorParent *aParent,
const HangData& aHangData,
const nsString& aBrowserDumpId)
const nsString& aBrowserDumpId,
bool aTakeMinidump)
: mProcess(aProcess),
mParent(aParent),
mHangData(aHangData),
mBrowserDumpId(aBrowserDumpId)
mBrowserDumpId(aBrowserDumpId),
mTakeMinidump(aTakeMinidump)
{}
NS_IMETHOD
@ -564,14 +563,19 @@ public:
MOZ_RELEASE_ASSERT(NS_IsMainThread());
nsString dumpId;
if (mHangData.type() == HangData::TPluginHangData) {
if ((mHangData.type() == HangData::TPluginHangData) && mTakeMinidump) {
// We've been handed a partial minidump; complete it with plugin and
// content process dumps.
const PluginHangData& phd = mHangData.get_PluginHangData();
plugins::TakeFullMinidump(phd.pluginId(), phd.contentProcessId(),
mBrowserDumpId, dumpId);
mParent->UpdateMinidump(phd.pluginId(), dumpId);
} else {
// We already have a full minidump; go ahead and use it.
dumpId = mBrowserDumpId;
}
mProcess->SetHangData(mHangData);
mProcess->SetDumpId(dumpId);
mProcess->SetHangData(mHangData, dumpId);
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
@ -581,10 +585,40 @@ public:
private:
RefPtr<HangMonitoredProcess> mProcess;
HangMonitorParent* mParent;
HangData mHangData;
nsAutoString mBrowserDumpId;
bool mTakeMinidump;
};
// Take a minidump of the browser process if one wasn't already taken for the
// plugin that caused the hang. Return false if a dump was already available or
// true if new one has been taken.
bool
HangMonitorParent::TakeBrowserMinidump(const PluginHangData& aPhd,
nsString& aCrashId)
{
#ifdef MOZ_CRASHREPORTER
MutexAutoLock lock(mBrowserCrashDumpHashLock);
if (!mBrowserCrashDumpIds.Get(aPhd.pluginId(), &aCrashId)) {
nsCOMPtr<nsIFile> browserDump;
if (CrashReporter::TakeMinidump(getter_AddRefs(browserDump), true)) {
if (!CrashReporter::GetIDFromMinidump(browserDump, aCrashId)
|| aCrashId.IsEmpty()) {
browserDump->Remove(false);
NS_WARNING("Failed to generate timely browser stack, "
"this is bad for plugin hang analysis!");
} else {
mBrowserCrashDumpIds.Put(aPhd.pluginId(), aCrashId);
return true;
}
}
}
#endif // MOZ_CRASHREPORTER
return false;
}
bool
HangMonitorParent::RecvHangEvidence(const HangData& aHangData)
{
@ -606,30 +640,17 @@ HangMonitorParent::RecvHangEvidence(const HangData& aHangData)
// Before we wake up the browser main thread we want to take a
// browser minidump.
nsAutoString crashId;
#ifdef MOZ_CRASHREPORTER
bool takeMinidump = false;
if (aHangData.type() == HangData::TPluginHangData) {
MutexAutoLock lock(mBrowserCrashDumpHashLock);
const PluginHangData& phd = aHangData.get_PluginHangData();
if (!mBrowserCrashDumpIds.Get(phd.pluginId(), &crashId)) {
nsCOMPtr<nsIFile> browserDump;
if (CrashReporter::TakeMinidump(getter_AddRefs(browserDump), true)) {
if (!CrashReporter::GetIDFromMinidump(browserDump, crashId) || crashId.IsEmpty()) {
browserDump->Remove(false);
NS_WARNING("Failed to generate timely browser stack, this is bad for plugin hang analysis!");
} else {
mBrowserCrashDumpIds.Put(phd.pluginId(), crashId);
}
}
}
takeMinidump = TakeBrowserMinidump(aHangData.get_PluginHangData(), crashId);
}
#endif
mHangMonitor->InitiateCPOWTimeout();
MonitorAutoLock lock(mMonitor);
nsCOMPtr<nsIRunnable> notifier =
new HangObserverNotifier(mProcess, aHangData, crashId);
new HangObserverNotifier(mProcess, this, aHangData, crashId, takeMinidump);
NS_DispatchToMainThread(notifier);
return true;
@ -726,6 +747,17 @@ HangMonitorParent::CleanupPluginHang(uint32_t aPluginId, bool aRemoveFiles)
#endif
}
void
HangMonitorParent::UpdateMinidump(uint32_t aPluginId, const nsString& aDumpId)
{
if (aDumpId.IsEmpty()) {
return;
}
MutexAutoLock lock(mBrowserCrashDumpHashLock);
mBrowserCrashDumpIds.Put(aPluginId, aDumpId);
}
/* HangMonitoredProcess implementation */
NS_IMPL_ISUPPORTS(HangMonitoredProcess, nsIHangReport)

View File

@ -4,6 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MediaStreamGraphImpl.h"
#include "MediaStreamListener.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/unused.h"
@ -78,7 +79,7 @@ AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo,
MediaStreamListener* l = mListeners[i];
AudioSegment tmp;
l->NotifyQueuedTrackChanges(
Graph(), mTrackId, 0, MediaStreamListener::TRACK_EVENT_CREATED, tmp);
Graph(), mTrackId, 0, TrackEventCommand::TRACK_EVENT_CREATED, tmp);
l->NotifyFinishedTrackCreation(Graph());
}
mTrackCreated = true;

View File

@ -186,18 +186,18 @@ public:
}
void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset, uint32_t aTrackEvents,
StreamTime aTrackOffset, TrackEventCommand aTrackEvents,
const MediaSegment& aQueuedMedia,
MediaStream* aInputStream,
TrackID aInputTrackID) override
{
if (aTrackEvents & TRACK_EVENT_CREATED) {
if (aTrackEvents & TrackEventCommand::TRACK_EVENT_CREATED) {
nsCOMPtr<nsIRunnable> runnable =
NewRunnableMethod<TrackID, MediaSegment::Type, MediaStream*, TrackID>(
this, &OwnedStreamListener::DoNotifyTrackCreated,
aID, aQueuedMedia.GetType(), aInputStream, aInputTrackID);
aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget());
} else if (aTrackEvents & TRACK_EVENT_ENDED) {
} else if (aTrackEvents & TrackEventCommand::TRACK_EVENT_ENDED) {
nsCOMPtr<nsIRunnable> runnable =
NewRunnableMethod<MediaStream*, TrackID, TrackID>(
this, &OwnedStreamListener::DoNotifyTrackEnded,
@ -276,12 +276,12 @@ public:
// The methods below are called on the MediaStreamGraph thread.
void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset, uint32_t aTrackEvents,
StreamTime aTrackOffset, TrackEventCommand aTrackEvents,
const MediaSegment& aQueuedMedia,
MediaStream* aInputStream,
TrackID aInputTrackID) override
{
if (aTrackEvents & TRACK_EVENT_ENDED) {
if (aTrackEvents & TrackEventCommand::TRACK_EVENT_ENDED) {
nsCOMPtr<nsIRunnable> runnable =
NewRunnableMethod<StorensRefPtrPassByPtr<MediaStream>, TrackID>(
this, &PlaybackStreamListener::DoNotifyTrackEnded, aInputStream, aInputTrackID);
@ -757,7 +757,7 @@ DOMMediaStream::OwnsTrack(const MediaStreamTrack& aTrack) const
}
bool
DOMMediaStream::AddDirectListener(MediaStreamDirectListener* aListener)
DOMMediaStream::AddDirectListener(DirectMediaStreamListener* aListener)
{
if (GetInputStream() && GetInputStream()->AsSourceStream()) {
GetInputStream()->AsSourceStream()->AddDirectListener(aListener);
@ -767,7 +767,7 @@ DOMMediaStream::AddDirectListener(MediaStreamDirectListener* aListener)
}
void
DOMMediaStream::RemoveDirectListener(MediaStreamDirectListener* aListener)
DOMMediaStream::RemoveDirectListener(DirectMediaStreamListener* aListener)
{
if (GetInputStream() && GetInputStream()->AsSourceStream()) {
GetInputStream()->AsSourceStream()->RemoveDirectListener(aListener);

View File

@ -30,7 +30,7 @@ class DOMLocalMediaStream;
class DOMMediaStream;
class MediaStream;
class MediaInputPort;
class MediaStreamDirectListener;
class DirectMediaStreamListener;
class MediaStreamGraph;
class ProcessedMediaStream;
@ -439,8 +439,8 @@ public:
* Allows users to get access to media data without going through graph
* queuing. Returns a bool to let us know if direct data will be delivered.
*/
bool AddDirectListener(MediaStreamDirectListener *aListener);
void RemoveDirectListener(MediaStreamDirectListener *aListener);
bool AddDirectListener(DirectMediaStreamListener *aListener);
void RemoveDirectListener(DirectMediaStreamListener *aListener);
virtual DOMLocalMediaStream* AsDOMLocalMediaStream() { return nullptr; }
virtual DOMHwMediaStream* AsDOMHwMediaStream() { return nullptr; }

View File

@ -9,6 +9,7 @@
#include "MediaStreamGraph.h"
#include "mozilla/dom/MediaStreamTrack.h"
#include "GetUserMediaRequest.h"
#include "MediaStreamListener.h"
#include "nsContentUtils.h"
#include "nsHashPropertyBag.h"
#ifdef MOZ_WIDGET_GONK
@ -243,6 +244,253 @@ HostHasPermission(nsIURI &docURI)
return false;
}
/**
* This class is an implementation of MediaStreamListener. This is used
* to Start() and Stop() the underlying MediaEngineSource when MediaStreams
* are assigned and deassigned in content.
*/
class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener
{
public:
// Create in an inactive state
GetUserMediaCallbackMediaStreamListener(base::Thread *aThread,
uint64_t aWindowID,
const PrincipalHandle& aPrincipalHandle)
: mMediaThread(aThread)
, mMainThreadCheck(nullptr)
, mWindowID(aWindowID)
, mPrincipalHandle(aPrincipalHandle)
, mStopped(false)
, mFinished(false)
, mRemoved(false)
, mAudioStopped(false)
, mVideoStopped(false) {}
~GetUserMediaCallbackMediaStreamListener()
{
Unused << mMediaThread;
// It's OK to release mStream on any thread; they have thread-safe
// refcounts.
}
void Activate(already_AddRefed<SourceMediaStream> aStream,
AudioDevice* aAudioDevice,
VideoDevice* aVideoDevice)
{
MOZ_ASSERT(NS_IsMainThread());
mMainThreadCheck = PR_GetCurrentThread();
mStream = aStream;
mAudioDevice = aAudioDevice;
mVideoDevice = aVideoDevice;
mStream->AddListener(this);
}
MediaStream *Stream() // Can be used to test if Activate was called
{
return mStream;
}
SourceMediaStream *GetSourceStream()
{
NS_ASSERTION(mStream,"Getting stream from never-activated GUMCMSListener");
if (!mStream) {
return nullptr;
}
return mStream->AsSourceStream();
}
void StopSharing();
void StopTrack(TrackID aID);
typedef media::Pledge<bool, dom::MediaStreamError*> PledgeVoid;
already_AddRefed<PledgeVoid>
ApplyConstraintsToTrack(nsPIDOMWindowInner* aWindow,
TrackID aID,
const dom::MediaTrackConstraints& aConstraints);
// mVideo/AudioDevice are set by Activate(), so we assume they're capturing
// if set and represent a real capture device.
bool CapturingVideo()
{
MOZ_ASSERT(NS_IsMainThread());
return mVideoDevice && !mStopped &&
!mVideoDevice->GetSource()->IsAvailable() &&
mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Camera &&
(!mVideoDevice->GetSource()->IsFake() ||
Preferences::GetBool("media.navigator.permission.fake"));
}
bool CapturingAudio()
{
MOZ_ASSERT(NS_IsMainThread());
return mAudioDevice && !mStopped &&
!mAudioDevice->GetSource()->IsAvailable() &&
(!mAudioDevice->GetSource()->IsFake() ||
Preferences::GetBool("media.navigator.permission.fake"));
}
bool CapturingScreen()
{
MOZ_ASSERT(NS_IsMainThread());
return mVideoDevice && !mStopped &&
!mVideoDevice->GetSource()->IsAvailable() &&
mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Screen;
}
bool CapturingWindow()
{
MOZ_ASSERT(NS_IsMainThread());
return mVideoDevice && !mStopped &&
!mVideoDevice->GetSource()->IsAvailable() &&
mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Window;
}
bool CapturingApplication()
{
MOZ_ASSERT(NS_IsMainThread());
return mVideoDevice && !mStopped &&
!mVideoDevice->GetSource()->IsAvailable() &&
mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Application;
}
bool CapturingBrowser()
{
MOZ_ASSERT(NS_IsMainThread());
return mVideoDevice && !mStopped &&
mVideoDevice->GetSource()->IsAvailable() &&
mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Browser;
}
// implement in .cpp to avoid circular dependency with MediaOperationTask
// Can be invoked from EITHER MainThread or MSG thread
void Stop();
void
AudioConfig(bool aEchoOn, uint32_t aEcho,
bool aAgcOn, uint32_t aAGC,
bool aNoiseOn, uint32_t aNoise,
int32_t aPlayoutDelay);
void
Remove()
{
MOZ_ASSERT(NS_IsMainThread());
// allow calling even if inactive (!mStream) for easier cleanup
// Caller holds strong reference to us, so no death grip required
if (mStream && !mRemoved) {
MM_LOG(("Listener removed on purpose, mFinished = %d", (int) mFinished));
mRemoved = true; // RemoveListener is async, avoid races
// If it's destroyed, don't call - listener will be removed and we'll be notified!
if (!mStream->IsDestroyed()) {
mStream->RemoveListener(this);
}
}
}
// Proxy NotifyPull() to sources
void
NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) override
{
// Currently audio sources ignore NotifyPull, but they could
// watch it especially for fake audio.
if (mAudioDevice) {
mAudioDevice->GetSource()->NotifyPull(aGraph, mStream, kAudioTrack,
aDesiredTime, mPrincipalHandle);
}
if (mVideoDevice) {
mVideoDevice->GetSource()->NotifyPull(aGraph, mStream, kVideoTrack,
aDesiredTime, mPrincipalHandle);
}
}
void
NotifyEvent(MediaStreamGraph* aGraph,
MediaStreamGraphEvent aEvent) override
{
nsresult rv;
nsCOMPtr<nsIThread> thread;
switch (aEvent) {
case MediaStreamGraphEvent::EVENT_FINISHED:
rv = NS_GetMainThread(getter_AddRefs(thread));
if (NS_WARN_IF(NS_FAILED(rv))) {
NS_ASSERTION(false, "Mainthread not available; running on current thread");
// Ensure this really *was* MainThread (NS_GetCurrentThread won't work)
MOZ_RELEASE_ASSERT(mMainThreadCheck == PR_GetCurrentThread());
NotifyFinished();
return;
}
thread->Dispatch(NewRunnableMethod(this, &GetUserMediaCallbackMediaStreamListener::NotifyFinished),
NS_DISPATCH_NORMAL);
break;
case MediaStreamGraphEvent::EVENT_REMOVED:
rv = NS_GetMainThread(getter_AddRefs(thread));
if (NS_WARN_IF(NS_FAILED(rv))) {
NS_ASSERTION(false, "Mainthread not available; running on current thread");
// Ensure this really *was* MainThread (NS_GetCurrentThread won't work)
MOZ_RELEASE_ASSERT(mMainThreadCheck == PR_GetCurrentThread());
NotifyRemoved();
return;
}
thread->Dispatch(NewRunnableMethod(this, &GetUserMediaCallbackMediaStreamListener::NotifyRemoved),
NS_DISPATCH_NORMAL);
break;
case MediaStreamGraphEvent::EVENT_HAS_DIRECT_LISTENERS:
NotifyDirectListeners(aGraph, true);
break;
case MediaStreamGraphEvent::EVENT_HAS_NO_DIRECT_LISTENERS:
NotifyDirectListeners(aGraph, false);
break;
default:
break;
}
}
void
NotifyFinished();
void
NotifyRemoved();
void
NotifyDirectListeners(MediaStreamGraph* aGraph, bool aHasListeners);
PrincipalHandle GetPrincipalHandle() const { return mPrincipalHandle; }
private:
// Set at construction
base::Thread* mMediaThread;
// never ever indirect off this; just for assertions
PRThread* mMainThreadCheck;
uint64_t mWindowID;
const PrincipalHandle mPrincipalHandle;
// true after this listener has sent MEDIA_STOP. MainThread only.
bool mStopped;
// true after the stream this listener is listening to has finished in the
// MediaStreamGraph. MainThread only.
bool mFinished;
// true after this listener has been removed from its MediaStream.
// MainThread only.
bool mRemoved;
// true if we have sent MEDIA_STOP or MEDIA_STOP_TRACK for mAudioDevice.
// MainThread only.
bool mAudioStopped;
// true if we have sent MEDIA_STOP or MEDIA_STOP_TRACK for mVideoDevice.
// MainThread only.
bool mVideoStopped;
// Set at Activate on MainThread
// Accessed from MediaStreamGraph thread, MediaManager thread, and MainThread
// No locking needed as they're only addrefed except on the MediaManager thread
RefPtr<AudioDevice> mAudioDevice; // threadsafe refcnt
RefPtr<VideoDevice> mVideoDevice; // threadsafe refcnt
RefPtr<SourceMediaStream> mStream; // threadsafe refcnt
};
// Generic class for running long media operations like Start off the main
// thread, and then (because nsDOMMediaStreams aren't threadsafe),
// ProxyReleases mStream since it's cycle collected.
@ -3144,14 +3392,14 @@ GetUserMediaCallbackMediaStreamListener::StopSharing()
// ApplyConstraints for track
already_AddRefed<GetUserMediaCallbackMediaStreamListener::PledgeVoid>
already_AddRefed<media::Pledge<bool, dom::MediaStreamError*>>
GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack(
nsPIDOMWindowInner* aWindow,
TrackID aTrackID,
const MediaTrackConstraints& aConstraints)
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<PledgeVoid> p = new PledgeVoid();
RefPtr<media::Pledge<bool, dom::MediaStreamError*>> p = new media::Pledge<bool, dom::MediaStreamError*>();
// XXX to support multiple tracks of a type in a stream, this should key off
// the TrackID and not just the type
@ -3204,7 +3452,7 @@ GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack(
if (!mgr) {
return NS_OK;
}
RefPtr<PledgeVoid> p = mgr->mOutstandingVoidPledges.Remove(id);
RefPtr<media::Pledge<bool, dom::MediaStreamError*>> p = mgr->mOutstandingVoidPledges.Remove(id);
if (p) {
if (NS_SUCCEEDED(rv)) {
p->Resolve(false);
@ -3320,6 +3568,26 @@ GetUserMediaCallbackMediaStreamListener::NotifyRemoved()
}
}
GetUserMediaNotificationEvent::GetUserMediaNotificationEvent(
GetUserMediaCallbackMediaStreamListener* aListener,
GetUserMediaStatus aStatus,
bool aIsAudio, bool aIsVideo, uint64_t aWindowID)
: mListener(aListener) , mStatus(aStatus) , mIsAudio(aIsAudio)
, mIsVideo(aIsVideo), mWindowID(aWindowID) {}
GetUserMediaNotificationEvent::GetUserMediaNotificationEvent(
GetUserMediaStatus aStatus,
already_AddRefed<DOMMediaStream> aStream,
OnTracksAvailableCallback* aOnTracksAvailableCallback,
bool aIsAudio, bool aIsVideo, uint64_t aWindowID,
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError)
: mStream(aStream), mOnTracksAvailableCallback(aOnTracksAvailableCallback),
mStatus(aStatus), mIsAudio(aIsAudio), mIsVideo(aIsVideo), mWindowID(aWindowID),
mOnFailure(aError) {}
GetUserMediaNotificationEvent::~GetUserMediaNotificationEvent()
{
}
NS_IMETHODIMP
GetUserMediaNotificationEvent::Run()
{

View File

@ -53,6 +53,10 @@ struct MediaTrackConstraints;
struct MediaTrackConstraintSet;
} // namespace dom
class MediaManager;
class GetUserMediaCallbackMediaStreamListener;
class GetUserMediaTask;
extern LogModule* GetMediaManagerLog();
#define MM_LOG(msg) MOZ_LOG(GetMediaManagerLog(), mozilla::LogLevel::Debug, msg)
@ -117,253 +121,6 @@ public:
const MediaEnginePrefs &aPrefs);
};
/**
* This class is an implementation of MediaStreamListener. This is used
* to Start() and Stop() the underlying MediaEngineSource when MediaStreams
* are assigned and deassigned in content.
*/
class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener
{
public:
// Create in an inactive state
GetUserMediaCallbackMediaStreamListener(base::Thread *aThread,
uint64_t aWindowID,
const PrincipalHandle& aPrincipalHandle)
: mMediaThread(aThread)
, mMainThreadCheck(nullptr)
, mWindowID(aWindowID)
, mPrincipalHandle(aPrincipalHandle)
, mStopped(false)
, mFinished(false)
, mRemoved(false)
, mAudioStopped(false)
, mVideoStopped(false) {}
~GetUserMediaCallbackMediaStreamListener()
{
Unused << mMediaThread;
// It's OK to release mStream on any thread; they have thread-safe
// refcounts.
}
void Activate(already_AddRefed<SourceMediaStream> aStream,
AudioDevice* aAudioDevice,
VideoDevice* aVideoDevice)
{
MOZ_ASSERT(NS_IsMainThread());
mMainThreadCheck = PR_GetCurrentThread();
mStream = aStream;
mAudioDevice = aAudioDevice;
mVideoDevice = aVideoDevice;
mStream->AddListener(this);
}
MediaStream *Stream() // Can be used to test if Activate was called
{
return mStream;
}
SourceMediaStream *GetSourceStream()
{
NS_ASSERTION(mStream,"Getting stream from never-activated GUMCMSListener");
if (!mStream) {
return nullptr;
}
return mStream->AsSourceStream();
}
void StopSharing();
void StopTrack(TrackID aID);
typedef media::Pledge<bool, dom::MediaStreamError*> PledgeVoid;
already_AddRefed<PledgeVoid>
ApplyConstraintsToTrack(nsPIDOMWindowInner* aWindow,
TrackID aID,
const dom::MediaTrackConstraints& aConstraints);
// mVideo/AudioDevice are set by Activate(), so we assume they're capturing
// if set and represent a real capture device.
bool CapturingVideo()
{
MOZ_ASSERT(NS_IsMainThread());
return mVideoDevice && !mStopped &&
!mVideoDevice->GetSource()->IsAvailable() &&
mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Camera &&
(!mVideoDevice->GetSource()->IsFake() ||
Preferences::GetBool("media.navigator.permission.fake"));
}
bool CapturingAudio()
{
MOZ_ASSERT(NS_IsMainThread());
return mAudioDevice && !mStopped &&
!mAudioDevice->GetSource()->IsAvailable() &&
(!mAudioDevice->GetSource()->IsFake() ||
Preferences::GetBool("media.navigator.permission.fake"));
}
bool CapturingScreen()
{
MOZ_ASSERT(NS_IsMainThread());
return mVideoDevice && !mStopped &&
!mVideoDevice->GetSource()->IsAvailable() &&
mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Screen;
}
bool CapturingWindow()
{
MOZ_ASSERT(NS_IsMainThread());
return mVideoDevice && !mStopped &&
!mVideoDevice->GetSource()->IsAvailable() &&
mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Window;
}
bool CapturingApplication()
{
MOZ_ASSERT(NS_IsMainThread());
return mVideoDevice && !mStopped &&
!mVideoDevice->GetSource()->IsAvailable() &&
mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Application;
}
bool CapturingBrowser()
{
MOZ_ASSERT(NS_IsMainThread());
return mVideoDevice && !mStopped &&
mVideoDevice->GetSource()->IsAvailable() &&
mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Browser;
}
// implement in .cpp to avoid circular dependency with MediaOperationTask
// Can be invoked from EITHER MainThread or MSG thread
void Stop();
void
AudioConfig(bool aEchoOn, uint32_t aEcho,
bool aAgcOn, uint32_t aAGC,
bool aNoiseOn, uint32_t aNoise,
int32_t aPlayoutDelay);
void
Remove()
{
MOZ_ASSERT(NS_IsMainThread());
// allow calling even if inactive (!mStream) for easier cleanup
// Caller holds strong reference to us, so no death grip required
if (mStream && !mRemoved) {
MM_LOG(("Listener removed on purpose, mFinished = %d", (int) mFinished));
mRemoved = true; // RemoveListener is async, avoid races
// If it's destroyed, don't call - listener will be removed and we'll be notified!
if (!mStream->IsDestroyed()) {
mStream->RemoveListener(this);
}
}
}
// Proxy NotifyPull() to sources
void
NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) override
{
// Currently audio sources ignore NotifyPull, but they could
// watch it especially for fake audio.
if (mAudioDevice) {
mAudioDevice->GetSource()->NotifyPull(aGraph, mStream, kAudioTrack,
aDesiredTime, mPrincipalHandle);
}
if (mVideoDevice) {
mVideoDevice->GetSource()->NotifyPull(aGraph, mStream, kVideoTrack,
aDesiredTime, mPrincipalHandle);
}
}
void
NotifyEvent(MediaStreamGraph* aGraph,
MediaStreamListener::MediaStreamGraphEvent aEvent) override
{
nsresult rv;
nsCOMPtr<nsIThread> thread;
switch (aEvent) {
case EVENT_FINISHED:
rv = NS_GetMainThread(getter_AddRefs(thread));
if (NS_WARN_IF(NS_FAILED(rv))) {
NS_ASSERTION(false, "Mainthread not available; running on current thread");
// Ensure this really *was* MainThread (NS_GetCurrentThread won't work)
MOZ_RELEASE_ASSERT(mMainThreadCheck == PR_GetCurrentThread());
NotifyFinished();
return;
}
thread->Dispatch(NewRunnableMethod(this, &GetUserMediaCallbackMediaStreamListener::NotifyFinished),
NS_DISPATCH_NORMAL);
break;
case EVENT_REMOVED:
rv = NS_GetMainThread(getter_AddRefs(thread));
if (NS_WARN_IF(NS_FAILED(rv))) {
NS_ASSERTION(false, "Mainthread not available; running on current thread");
// Ensure this really *was* MainThread (NS_GetCurrentThread won't work)
MOZ_RELEASE_ASSERT(mMainThreadCheck == PR_GetCurrentThread());
NotifyRemoved();
return;
}
thread->Dispatch(NewRunnableMethod(this, &GetUserMediaCallbackMediaStreamListener::NotifyRemoved),
NS_DISPATCH_NORMAL);
break;
case EVENT_HAS_DIRECT_LISTENERS:
NotifyDirectListeners(aGraph, true);
break;
case EVENT_HAS_NO_DIRECT_LISTENERS:
NotifyDirectListeners(aGraph, false);
break;
default:
break;
}
}
void
NotifyFinished();
void
NotifyRemoved();
void
NotifyDirectListeners(MediaStreamGraph* aGraph, bool aHasListeners);
PrincipalHandle GetPrincipalHandle() const { return mPrincipalHandle; }
private:
// Set at construction
base::Thread* mMediaThread;
// never ever indirect off this; just for assertions
PRThread* mMainThreadCheck;
uint64_t mWindowID;
const PrincipalHandle mPrincipalHandle;
// true after this listener has sent MEDIA_STOP. MainThread only.
bool mStopped;
// true after the stream this listener is listening to has finished in the
// MediaStreamGraph. MainThread only.
bool mFinished;
// true after this listener has been removed from its MediaStream.
// MainThread only.
bool mRemoved;
// true if we have sent MEDIA_STOP or MEDIA_STOP_TRACK for mAudioDevice.
// MainThread only.
bool mAudioStopped;
// true if we have sent MEDIA_STOP or MEDIA_STOP_TRACK for mVideoDevice.
// MainThread only.
bool mVideoStopped;
// Set at Activate on MainThread
// Accessed from MediaStreamGraph thread, MediaManager thread, and MainThread
// No locking needed as they're only addrefed except on the MediaManager thread
RefPtr<AudioDevice> mAudioDevice; // threadsafe refcnt
RefPtr<VideoDevice> mVideoDevice; // threadsafe refcnt
RefPtr<SourceMediaStream> mStream; // threadsafe refcnt
};
class GetUserMediaNotificationEvent: public Runnable
{
public:
@ -374,22 +131,14 @@ class GetUserMediaNotificationEvent: public Runnable
};
GetUserMediaNotificationEvent(GetUserMediaCallbackMediaStreamListener* aListener,
GetUserMediaStatus aStatus,
bool aIsAudio, bool aIsVideo, uint64_t aWindowID)
: mListener(aListener) , mStatus(aStatus) , mIsAudio(aIsAudio)
, mIsVideo(aIsVideo), mWindowID(aWindowID) {}
bool aIsAudio, bool aIsVideo, uint64_t aWindowID);
GetUserMediaNotificationEvent(GetUserMediaStatus aStatus,
already_AddRefed<DOMMediaStream> aStream,
OnTracksAvailableCallback* aOnTracksAvailableCallback,
bool aIsAudio, bool aIsVideo, uint64_t aWindowID,
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError)
: mStream(aStream), mOnTracksAvailableCallback(aOnTracksAvailableCallback),
mStatus(aStatus), mIsAudio(aIsAudio), mIsVideo(aIsVideo), mWindowID(aWindowID),
mOnFailure(aError) {}
virtual ~GetUserMediaNotificationEvent()
{
}
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError);
virtual ~GetUserMediaNotificationEvent();
NS_IMETHOD Run() override;
@ -411,9 +160,6 @@ typedef enum {
MEDIA_DIRECT_LISTENERS,
} MediaOperation;
class MediaManager;
class GetUserMediaTask;
class ReleaseMediaOperationResource : public Runnable
{
public:
@ -575,7 +321,7 @@ private:
media::CoatCheck<PledgeSourceSet> mOutstandingPledges;
media::CoatCheck<PledgeChar> mOutstandingCharPledges;
media::CoatCheck<GetUserMediaCallbackMediaStreamListener::PledgeVoid> mOutstandingVoidPledges;
media::CoatCheck<media::Pledge<bool, dom::MediaStreamError*>> mOutstandingVoidPledges;
#if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
RefPtr<nsDOMCameraManager> mCameraManager;
#endif

View File

@ -22,6 +22,7 @@
#include "AudioChannelService.h"
#include "AudioNodeStream.h"
#include "AudioNodeExternalInputStream.h"
#include "MediaStreamListener.h"
#include "mozilla/dom/AudioContextBinding.h"
#include "mozilla/media/MediaUtils.h"
#include <algorithm>
@ -60,6 +61,12 @@ LazyLogModule gMediaStreamGraphLog("MediaStreamGraph");
# define LIFECYCLE_LOG(...)
#endif
enum SourceMediaStream::TrackCommands : uint32_t {
TRACK_CREATE = TrackEventCommand::TRACK_EVENT_CREATED,
TRACK_END = TrackEventCommand::TRACK_EVENT_ENDED,
TRACK_UNUSED = TrackEventCommand::TRACK_EVENT_UNUSED,
};
/**
* A hash table containing the graph instances, one per AudioChannel.
*/
@ -201,7 +208,7 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
offset, *(static_cast<AudioSegment*>(data->mData.get())));
}
l->NotifyQueuedTrackChanges(this, data->mID,
offset, data->mCommands, *data->mData);
offset, static_cast<TrackEventCommand>(data->mCommands), *data->mData);
if (data->mCommands & SourceMediaStream::TRACK_CREATE) {
l->NotifyQueuedAudioData(this, data->mID,
offset, *(static_cast<AudioSegment*>(data->mData.get())));
@ -221,7 +228,7 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
MOZ_ASSERT(!(data->mCommands & SourceMediaStream::TRACK_UNUSED));
for (MediaStreamListener* l : aStream->mListeners) {
l->NotifyQueuedTrackChanges(this, data->mID,
offset, data->mCommands, *data->mData);
offset, static_cast<TrackEventCommand>(data->mCommands), *data->mData);
}
} else {
// Fixme: This part will be removed in the bug 1201363. It will be
@ -231,7 +238,7 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
// Dealing with video and not TRACK_CREATE and TRACK_END case.
for (MediaStreamListener* l : aStream->mListeners) {
l->NotifyQueuedTrackChanges(this, data->mID,
offset, data->mCommands, *data->mData);
offset, static_cast<TrackEventCommand>(data->mCommands), *data->mData);
}
}
}
@ -356,7 +363,7 @@ MediaStreamGraphImpl::UpdateCurrentTimeForStreams(GraphTime aPrevCurrentTime)
SetStreamOrderDirty();
for (uint32_t j = 0; j < stream->mListeners.Length(); ++j) {
MediaStreamListener* l = stream->mListeners[j];
l->NotifyEvent(this, MediaStreamListener::EVENT_FINISHED);
l->NotifyEvent(this, MediaStreamGraphEvent::EVENT_FINISHED);
}
}
}
@ -2001,6 +2008,14 @@ MediaStream::MediaStream()
MOZ_COUNT_CTOR(MediaStream);
}
MediaStream::~MediaStream()
{
MOZ_COUNT_DTOR(MediaStream);
NS_ASSERTION(mMainThreadDestroyed, "Should have been destroyed already");
NS_ASSERTION(mMainThreadListeners.IsEmpty(),
"All main thread listeners should have been removed");
}
size_t
MediaStream::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
@ -2105,7 +2120,7 @@ MediaStream::EnsureTrack(TrackID aTrackId)
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
MediaStreamListener* l = mListeners[j];
l->NotifyQueuedTrackChanges(Graph(), aTrackId, 0,
MediaStreamListener::TRACK_EVENT_CREATED,
TrackEventCommand::TRACK_EVENT_CREATED,
*segment);
// TODO If we ever need to ensure several tracks at once, we will have to
// change this.
@ -2121,7 +2136,7 @@ MediaStream::RemoveAllListenersImpl()
{
for (int32_t i = mListeners.Length() - 1; i >= 0; --i) {
RefPtr<MediaStreamListener> listener = mListeners[i].forget();
listener->NotifyEvent(GraphImpl(), MediaStreamListener::EVENT_REMOVED);
listener->NotifyEvent(GraphImpl(), MediaStreamGraphEvent::EVENT_REMOVED);
}
mListeners.Clear();
}
@ -2381,17 +2396,17 @@ MediaStream::AddListenerImpl(already_AddRefed<MediaStreamListener> aListener)
MOZ_ASSERT(IsTrackIDExplicit(inputTrackID));
}
uint32_t flags = MediaStreamListener::TRACK_EVENT_CREATED;
uint32_t flags = TrackEventCommand::TRACK_EVENT_CREATED;
if (it->IsEnded()) {
flags |= MediaStreamListener::TRACK_EVENT_ENDED;
flags |= TrackEventCommand::TRACK_EVENT_ENDED;
}
nsAutoPtr<MediaSegment> segment(it->GetSegment()->CreateEmptyClone());
listener->NotifyQueuedTrackChanges(Graph(), it->GetID(), it->GetEnd(),
flags, *segment,
static_cast<TrackEventCommand>(flags), *segment,
inputStream, inputTrackID);
}
if (mNotifiedFinished) {
listener->NotifyEvent(GraphImpl(), MediaStreamListener::EVENT_FINISHED);
listener->NotifyEvent(GraphImpl(), MediaStreamGraphEvent::EVENT_FINISHED);
}
if (mNotifiedHasCurrentData) {
listener->NotifyHasCurrentData(GraphImpl());
@ -2420,7 +2435,7 @@ MediaStream::RemoveListenerImpl(MediaStreamListener* aListener)
// wouldn't need this if we could do it in the opposite order
RefPtr<MediaStreamListener> listener(aListener);
mListeners.RemoveElement(aListener);
listener->NotifyEvent(GraphImpl(), MediaStreamListener::EVENT_REMOVED);
listener->NotifyEvent(GraphImpl(), MediaStreamGraphEvent::EVENT_REMOVED);
}
void
@ -2513,56 +2528,56 @@ MediaStream::RemoveTrackListener(MediaStreamTrackListener* aListener,
}
void
MediaStream::AddDirectTrackListenerImpl(already_AddRefed<MediaStreamTrackDirectListener> aListener,
MediaStream::AddDirectTrackListenerImpl(already_AddRefed<DirectMediaStreamTrackListener> aListener,
TrackID aTrackID)
{
// Base implementation, for streams that don't support direct track listeners.
RefPtr<MediaStreamTrackDirectListener> listener = aListener;
RefPtr<DirectMediaStreamTrackListener> listener = aListener;
listener->NotifyDirectListenerInstalled(
MediaStreamTrackDirectListener::InstallationResult::STREAM_NOT_SUPPORTED);
DirectMediaStreamTrackListener::InstallationResult::STREAM_NOT_SUPPORTED);
}
void
MediaStream::AddDirectTrackListener(MediaStreamTrackDirectListener* aListener,
MediaStream::AddDirectTrackListener(DirectMediaStreamTrackListener* aListener,
TrackID aTrackID)
{
class Message : public ControlMessage {
public:
Message(MediaStream* aStream, MediaStreamTrackDirectListener* aListener,
Message(MediaStream* aStream, DirectMediaStreamTrackListener* aListener,
TrackID aTrackID) :
ControlMessage(aStream), mListener(aListener), mTrackID(aTrackID) {}
virtual void Run()
{
mStream->AddDirectTrackListenerImpl(mListener.forget(), mTrackID);
}
RefPtr<MediaStreamTrackDirectListener> mListener;
RefPtr<DirectMediaStreamTrackListener> mListener;
TrackID mTrackID;
};
GraphImpl()->AppendMessage(MakeUnique<Message>(this, aListener, aTrackID));
}
void
MediaStream::RemoveDirectTrackListenerImpl(MediaStreamTrackDirectListener* aListener,
MediaStream::RemoveDirectTrackListenerImpl(DirectMediaStreamTrackListener* aListener,
TrackID aTrackID)
{
// Base implementation, the listener was never added so nothing to do.
RefPtr<MediaStreamTrackDirectListener> listener = aListener;
RefPtr<DirectMediaStreamTrackListener> listener = aListener;
}
void
MediaStream::RemoveDirectTrackListener(MediaStreamTrackDirectListener* aListener,
MediaStream::RemoveDirectTrackListener(DirectMediaStreamTrackListener* aListener,
TrackID aTrackID)
{
class Message : public ControlMessage {
public:
Message(MediaStream* aStream, MediaStreamTrackDirectListener* aListener,
Message(MediaStream* aStream, DirectMediaStreamTrackListener* aListener,
TrackID aTrackID) :
ControlMessage(aStream), mListener(aListener), mTrackID(aTrackID) {}
virtual void Run()
{
mStream->RemoveDirectTrackListenerImpl(mListener, mTrackID);
}
RefPtr<MediaStreamTrackDirectListener> mListener;
RefPtr<DirectMediaStreamTrackListener> mListener;
TrackID mTrackID;
};
GraphImpl()->AppendMessage(MakeUnique<Message>(this, aListener, aTrackID));
@ -2686,6 +2701,16 @@ MediaStream::AddMainThreadListener(MainThreadMediaStreamListener* aListener)
NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(runnable.forget())));
}
SourceMediaStream::SourceMediaStream() :
MediaStream(),
mMutex("mozilla::media::SourceMediaStream"),
mUpdateKnownTracksTime(0),
mPullEnabled(false),
mUpdateFinished(false),
mNeedsMixing(false)
{
}
nsresult
SourceMediaStream::OpenAudioInput(int aID,
AudioDataListener *aListener)
@ -2750,6 +2775,13 @@ SourceMediaStream::AddTrackInternal(TrackID aID, TrackRate aRate, StreamTime aSt
}
}
void
SourceMediaStream::AddAudioTrack(TrackID aID, TrackRate aRate, StreamTime aStart,
AudioSegment* aSegment, uint32_t aFlags)
{
AddTrackInternal(aID, aRate, aStart, aSegment, aFlags);
}
void
SourceMediaStream::FinishAddTracks()
{
@ -2830,13 +2862,13 @@ SourceMediaStream::NotifyDirectConsumers(TrackData *aTrack,
MOZ_ASSERT(aTrack);
for (uint32_t j = 0; j < mDirectListeners.Length(); ++j) {
MediaStreamDirectListener* l = mDirectListeners[j];
DirectMediaStreamListener* l = mDirectListeners[j];
StreamTime offset = 0; // FIX! need a separate StreamTime.... or the end of the internal buffer
l->NotifyRealtimeData(static_cast<MediaStreamGraph*>(GraphImpl()), aTrack->mID,
offset, aTrack->mCommands, *aSegment);
}
for (const TrackBound<MediaStreamTrackDirectListener>& source
for (const TrackBound<DirectMediaStreamTrackListener>& source
: mDirectTrackListeners) {
if (aTrack->mID != source.mTrackID) {
continue;
@ -2848,7 +2880,7 @@ SourceMediaStream::NotifyDirectConsumers(TrackData *aTrack,
// These handle notifying all the listeners of an event
void
SourceMediaStream::NotifyListenersEventImpl(MediaStreamListener::MediaStreamGraphEvent aEvent)
SourceMediaStream::NotifyListenersEventImpl(MediaStreamGraphEvent aEvent)
{
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
MediaStreamListener* l = mListeners[j];
@ -2857,23 +2889,23 @@ SourceMediaStream::NotifyListenersEventImpl(MediaStreamListener::MediaStreamGrap
}
void
SourceMediaStream::NotifyListenersEvent(MediaStreamListener::MediaStreamGraphEvent aNewEvent)
SourceMediaStream::NotifyListenersEvent(MediaStreamGraphEvent aNewEvent)
{
class Message : public ControlMessage {
public:
Message(SourceMediaStream* aStream, MediaStreamListener::MediaStreamGraphEvent aEvent) :
Message(SourceMediaStream* aStream, MediaStreamGraphEvent aEvent) :
ControlMessage(aStream), mEvent(aEvent) {}
void Run() override
{
mStream->AsSourceStream()->NotifyListenersEventImpl(mEvent);
}
MediaStreamListener::MediaStreamGraphEvent mEvent;
MediaStreamGraphEvent mEvent;
};
GraphImpl()->AppendMessage(MakeUnique<Message>(this, aNewEvent));
}
void
SourceMediaStream::AddDirectListener(MediaStreamDirectListener* aListener)
SourceMediaStream::AddDirectListener(DirectMediaStreamListener* aListener)
{
bool wasEmpty;
{
@ -2884,12 +2916,12 @@ SourceMediaStream::AddDirectListener(MediaStreamDirectListener* aListener)
if (wasEmpty) {
// Async
NotifyListenersEvent(MediaStreamListener::EVENT_HAS_DIRECT_LISTENERS);
NotifyListenersEvent(MediaStreamGraphEvent::EVENT_HAS_DIRECT_LISTENERS);
}
}
void
SourceMediaStream::RemoveDirectListener(MediaStreamDirectListener* aListener)
SourceMediaStream::RemoveDirectListener(DirectMediaStreamListener* aListener)
{
bool isEmpty;
{
@ -2900,28 +2932,33 @@ SourceMediaStream::RemoveDirectListener(MediaStreamDirectListener* aListener)
if (isEmpty) {
// Async
NotifyListenersEvent(MediaStreamListener::EVENT_HAS_NO_DIRECT_LISTENERS);
NotifyListenersEvent(MediaStreamGraphEvent::EVENT_HAS_NO_DIRECT_LISTENERS);
}
}
void
SourceMediaStream::AddDirectTrackListenerImpl(already_AddRefed<MediaStreamTrackDirectListener> aListener,
SourceMediaStream::AddDirectTrackListenerImpl(already_AddRefed<DirectMediaStreamTrackListener> aListener,
TrackID aTrackID)
{
MOZ_ASSERT(IsTrackIDExplicit(aTrackID));
TrackData* data;
bool found;
bool isAudio;
RefPtr<MediaStreamTrackDirectListener> listener = aListener;
bool isVideo;
RefPtr<DirectMediaStreamTrackListener> listener = aListener;
STREAM_LOG(LogLevel::Debug, ("Adding direct track listener %p bound to track %d to source stream %p",
listener.get(), aTrackID, this));
{
MutexAutoLock lock(mMutex);
data = FindDataForTrack(aTrackID);
found = !!data;
isAudio = found && data->mData->GetType() == MediaSegment::AUDIO;
if (found && isAudio) {
TrackBound<MediaStreamTrackDirectListener>* sourceListener =
if (found) {
isAudio = data->mData->GetType() == MediaSegment::AUDIO;
isVideo = data->mData->GetType() == MediaSegment::VIDEO;
}
if (found && (isAudio || isVideo)) {
TrackBound<DirectMediaStreamTrackListener>* sourceListener =
mDirectTrackListeners.AppendElement();
sourceListener->mListener = listener;
sourceListener->mTrackID = aTrackID;
@ -2931,28 +2968,28 @@ SourceMediaStream::AddDirectTrackListenerImpl(already_AddRefed<MediaStreamTrackD
STREAM_LOG(LogLevel::Warning, ("Couldn't find source track for direct track listener %p",
listener.get()));
listener->NotifyDirectListenerInstalled(
MediaStreamTrackDirectListener::InstallationResult::TRACK_NOT_FOUND_AT_SOURCE);
DirectMediaStreamTrackListener::InstallationResult::TRACK_NOT_FOUND_AT_SOURCE);
return;
}
if (!isAudio) {
STREAM_LOG(LogLevel::Warning, ("Source track for direct track listener %p is not audio",
if (!isAudio && !isVideo) {
STREAM_LOG(LogLevel::Warning, ("Source track for direct track listener %p is unknown",
listener.get()));
listener->NotifyDirectListenerInstalled(
MediaStreamTrackDirectListener::InstallationResult::TRACK_TYPE_NOT_SUPPORTED);
// It is not a video or audio track.
MOZ_ASSERT(true);
return;
}
STREAM_LOG(LogLevel::Debug, ("Added direct track listener %p", listener.get()));
listener->NotifyDirectListenerInstalled(
MediaStreamTrackDirectListener::InstallationResult::SUCCESS);
DirectMediaStreamTrackListener::InstallationResult::SUCCESS);
}
void
SourceMediaStream::RemoveDirectTrackListenerImpl(MediaStreamTrackDirectListener* aListener,
SourceMediaStream::RemoveDirectTrackListenerImpl(DirectMediaStreamTrackListener* aListener,
TrackID aTrackID)
{
MutexAutoLock lock(mMutex);
for (int32_t i = mDirectTrackListeners.Length() - 1; i >= 0; --i) {
const TrackBound<MediaStreamTrackDirectListener>& source =
const TrackBound<DirectMediaStreamTrackListener>& source =
mDirectTrackListeners[i];
if (source.mListener == aListener && source.mTrackID == aTrackID) {
aListener->NotifyDirectListenerUninstalled();
@ -2979,7 +3016,7 @@ SourceMediaStream::EndTrack(TrackID aID)
MutexAutoLock lock(mMutex);
TrackData *track = FindDataForTrack(aID);
if (track) {
track->mCommands |= TRACK_END;
track->mCommands |= TrackEventCommand::TRACK_EVENT_ENDED;
}
if (auto graph = GraphImpl()) {
graph->EnsureNextIteration();
@ -3012,7 +3049,7 @@ SourceMediaStream::SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled)
{
{
MutexAutoLock lock(mMutex);
for (TrackBound<MediaStreamTrackDirectListener>& l: mDirectTrackListeners) {
for (TrackBound<DirectMediaStreamTrackListener>& l: mDirectTrackListeners) {
if (l.mTrackID == aTrackID) {
bool oldEnabled = !mDisabledTrackIDs.Contains(aTrackID);
if (!oldEnabled && aEnabled) {
@ -3038,13 +3075,17 @@ SourceMediaStream::EndAllTrackAndFinish()
MutexAutoLock lock(mMutex);
for (uint32_t i = 0; i < mUpdateTracks.Length(); ++i) {
SourceMediaStream::TrackData* data = &mUpdateTracks[i];
data->mCommands |= TRACK_END;
data->mCommands |= TrackEventCommand::TRACK_EVENT_ENDED;
}
mPendingTracks.Clear();
FinishWithLockHeld();
// we will call NotifyEvent() to let GetUserMedia know
}
SourceMediaStream::~SourceMediaStream()
{
}
void
SourceMediaStream::RegisterForAudioMixing()
{

View File

@ -12,14 +12,13 @@
#include "mozilla/dom/AudioChannelBinding.h"
#include "AudioSegment.h"
#include "AudioStream.h"
#include "nsTArray.h"
#include "nsIRunnable.h"
#include "StreamTracks.h"
#include "VideoFrameContainer.h"
#include "VideoSegment.h"
#include "MainThreadUtils.h"
#include "StreamTracks.h"
#include "nsAutoPtr.h"
#include "nsAutoRef.h"
#include <speex/speex_resampler.h>
@ -89,125 +88,6 @@ class MediaStreamGraphImpl;
class ProcessedMediaStream;
class SourceMediaStream;
/**
* This is a base class for media graph thread listener callbacks.
* Override methods to be notified of audio or video data or changes in stream
* state.
*
* This can be used by stream recorders or network connections that receive
* stream input. It could also be used for debugging.
*
* All notification methods are called from the media graph thread. Overriders
* of these methods are responsible for all synchronization. Beware!
* These methods are called without the media graph monitor held, so
* reentry into media graph methods is possible, although very much discouraged!
* You should do something non-blocking and non-reentrant (e.g. dispatch an
* event to some thread) and return.
* The listener is not allowed to add/remove any listeners from the stream.
*
* When a listener is first attached, we guarantee to send a NotifyBlockingChanged
* callback to notify of the initial blocking state. Also, if a listener is
* attached to a stream that has already finished, we'll call NotifyFinished.
*/
class MediaStreamListener {
protected:
// Protected destructor, to discourage deletion outside of Release():
virtual ~MediaStreamListener() {}
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStreamListener)
/**
* When a SourceMediaStream has pulling enabled, and the MediaStreamGraph
* control loop is ready to pull, this gets called. A NotifyPull implementation
* is allowed to call the SourceMediaStream methods that alter track
* data. It is not allowed to make other MediaStream API calls, including
* calls to add or remove MediaStreamListeners. It is not allowed to block
* for any length of time.
* aDesiredTime is the stream time we would like to get data up to. Data
* beyond this point will not be played until NotifyPull runs again, so there's
* not much point in providing it. Note that if the stream is blocked for
* some reason, then data before aDesiredTime may not be played immediately.
*/
virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) {}
enum Blocking {
BLOCKED,
UNBLOCKED
};
/**
* Notify that the blocking status of the stream changed. The initial state
* is assumed to be BLOCKED.
*/
virtual void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked) {}
/**
* Notify that the stream has data in each track
* for the stream's current time. Once this state becomes true, it will
* always be true since we block stream time from progressing to times where
* there isn't data in each track.
*/
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph) {}
/**
* Notify that the stream output is advancing. aCurrentTime is the graph's
* current time. MediaStream::GraphTimeToStreamTime can be used to get the
* stream time.
*/
virtual void NotifyOutput(MediaStreamGraph* aGraph, GraphTime aCurrentTime) {}
enum MediaStreamGraphEvent {
EVENT_FINISHED,
EVENT_REMOVED,
EVENT_HAS_DIRECT_LISTENERS, // transition from no direct listeners
EVENT_HAS_NO_DIRECT_LISTENERS, // transition to no direct listeners
};
/**
* Notify that an event has occurred on the Stream
*/
virtual void NotifyEvent(MediaStreamGraph* aGraph, MediaStreamGraphEvent aEvent) {}
// maskable flags, not a simple enumerated value
enum {
TRACK_EVENT_CREATED = 0x01,
TRACK_EVENT_ENDED = 0x02,
TRACK_EVENT_UNUSED = ~(TRACK_EVENT_ENDED | TRACK_EVENT_CREATED),
};
/**
* Notify that changes to one of the stream tracks have been queued.
* aTrackEvents can be any combination of TRACK_EVENT_CREATED and
* TRACK_EVENT_ENDED. aQueuedMedia is the data being added to the track
* at aTrackOffset (relative to the start of the stream).
* aInputStream and aInputTrackID will be set if the changes originated
* from an input stream's track. In practice they will only be used for
* ProcessedMediaStreams.
*/
virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset,
uint32_t aTrackEvents,
const MediaSegment& aQueuedMedia,
MediaStream* aInputStream = nullptr,
TrackID aInputTrackID = TRACK_INVALID) {}
/**
* Notify queued audio data. Only audio data need to be queued. The video data
* will be notified by MediaStreamVideoSink::SetCurrentFrame.
*/
virtual void NotifyQueuedAudioData(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset,
const AudioSegment& aQueuedMedia,
MediaStream* aInputStream = nullptr,
TrackID aInputTrackID = TRACK_INVALID) {}
/**
* Notify that all new tracks this iteration have been created.
* This is to ensure that tracks added atomically to MediaStreamGraph
* are also notified of atomically to MediaStreamListeners.
*/
virtual void NotifyFinishedTrackCreation(MediaStreamGraph* aGraph) {}
};
class AudioDataListenerInterface {
protected:
// Protected destructor, to discourage deletion outside of Release():
@ -246,177 +126,6 @@ public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioDataListener)
};
/**
* This is a base class for media graph thread listener callbacks locked to
* specific tracks. Override methods to be notified of audio or video data or
* changes in track state.
*
* All notification methods are called from the media graph thread. Overriders
* of these methods are responsible for all synchronization. Beware!
* These methods are called without the media graph monitor held, so
* reentry into media graph methods is possible, although very much discouraged!
* You should do something non-blocking and non-reentrant (e.g. dispatch an
* event to some thread) and return.
* The listener is not allowed to add/remove any listeners from the parent
* stream.
*
* If a listener is attached to a track that has already ended, we guarantee
* to call NotifyEnded.
*/
class MediaStreamTrackListener
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStreamTrackListener)
public:
virtual void NotifyQueuedChanges(MediaStreamGraph* aGraph,
StreamTime aTrackOffset,
const MediaSegment& aQueuedMedia) {}
virtual void NotifyPrincipalHandleChanged(MediaStreamGraph* aGraph,
const PrincipalHandle& aNewPrincipalHandle) {}
virtual void NotifyEnded() {}
virtual void NotifyRemoved() {}
protected:
virtual ~MediaStreamTrackListener() {}
};
/**
* This is a base class for media graph thread listener direct callbacks
* from within AppendToTrack(). Note that your regular listener will
* still get NotifyQueuedTrackChanges() callbacks from the MSG thread, so
* you must be careful to ignore them if AddDirectListener was successful.
*/
class MediaStreamDirectListener : public MediaStreamListener
{
public:
virtual ~MediaStreamDirectListener() {}
/*
* This will be called on any MediaStreamDirectListener added to a
* a SourceMediaStream when AppendToTrack() is called. The MediaSegment
* will be the RawSegment (unresampled) if available in AppendToTrack().
* Note that NotifyQueuedTrackChanges() calls will also still occur.
*/
virtual void NotifyRealtimeData(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset,
uint32_t aTrackEvents,
const MediaSegment& aMedia) {}
};
/**
* This is a base class for media graph thread listener direct callbacks from
* within AppendToTrack(). It is bound to a certain track and can only be
* installed on audio tracks. Once added to a track on any stream in the graph,
* the graph will try to install it at that track's source of media data.
*
* This works for TrackUnionStreams, which will forward the listener to the
* track's input track if it exists, or wait for it to be created before
* forwarding if it doesn't.
* Once it reaches a SourceMediaStream, it can be successfully installed.
* Other types of streams will fail installation since they are not supported.
*
* Note that this listener and others for the same track will still get
* NotifyQueuedChanges() callbacks from the MSG tread, so you must be careful
* to ignore them if this listener was successfully installed.
*/
class MediaStreamTrackDirectListener : public MediaStreamTrackListener
{
friend class SourceMediaStream;
friend class TrackUnionStream;
public:
/*
* This will be called on any MediaStreamTrackDirectListener added to a
* SourceMediaStream when AppendToTrack() is called for the listener's bound
* track, using the thread of the AppendToTrack() caller. The MediaSegment
* will be the RawSegment (unresampled) if available in AppendToTrack().
* If the track is enabled at the source but has been disabled in one of the
* streams in between the source and where it was originally added, aMedia
* will be a disabled version of the one passed to AppendToTrack() as well.
* Note that NotifyQueuedTrackChanges() calls will also still occur.
*/
virtual void NotifyRealtimeTrackData(MediaStreamGraph* aGraph,
StreamTime aTrackOffset,
const MediaSegment& aMedia) {}
/**
* When a direct listener is processed for installation by the
* MediaStreamGraph it will be notified with whether the installation was
* successful or not. The results of this installation are the following:
* TRACK_NOT_FOUND_AT_SOURCE
* We found the source stream of media data for this track, but the track
* didn't exist. This should only happen if you try to install the listener
* directly to a SourceMediaStream that doesn't contain the given TrackID.
* TRACK_TYPE_NOT_SUPPORTED
* This is the failure when you install the listener to a non-audio track.
* STREAM_NOT_SUPPORTED
* While looking for the data source of this track, we found a MediaStream
* that is not a SourceMediaStream or a TrackUnionStream.
* SUCCESS
* Installation was successful and this listener will start receiving
* NotifyRealtimeData on the next AppendToTrack().
*/
enum class InstallationResult {
TRACK_NOT_FOUND_AT_SOURCE,
TRACK_TYPE_NOT_SUPPORTED,
STREAM_NOT_SUPPORTED,
SUCCESS
};
virtual void NotifyDirectListenerInstalled(InstallationResult aResult) {}
virtual void NotifyDirectListenerUninstalled() {}
protected:
virtual ~MediaStreamTrackDirectListener() {}
void MirrorAndDisableSegment(AudioSegment& aFrom, AudioSegment& aTo)
{
aTo.Clear();
aTo.AppendNullData(aFrom.GetDuration());
}
void NotifyRealtimeTrackDataAndApplyTrackDisabling(MediaStreamGraph* aGraph,
StreamTime aTrackOffset,
MediaSegment& aMedia)
{
if (mDisabledCount == 0) {
NotifyRealtimeTrackData(aGraph, aTrackOffset, aMedia);
return;
}
if (!mMedia) {
mMedia = aMedia.CreateEmptyClone();
}
if (aMedia.GetType() == MediaSegment::AUDIO) {
MirrorAndDisableSegment(static_cast<AudioSegment&>(aMedia),
static_cast<AudioSegment&>(*mMedia));
} else {
MOZ_CRASH("Unsupported media type");
}
NotifyRealtimeTrackData(aGraph, aTrackOffset, *mMedia);
}
void IncreaseDisabled()
{
++mDisabledCount;
}
void DecreaseDisabled()
{
--mDisabledCount;
MOZ_ASSERT(mDisabledCount >= 0, "Double decrease");
}
// Matches the number of disabled streams to which this listener is attached.
// The number of streams are those between the stream the listener was added
// and the SourceMediaStream that is the input of the data.
Atomic<int32_t> mDisabledCount;
nsAutoPtr<MediaSegment> mMedia;
};
/**
* This is a base class for main-thread listener callbacks.
* This callback is invoked on the main thread when the main-thread-visible
@ -447,6 +156,23 @@ struct AudioNodeSizes
nsCString mNodeType;
};
class AudioNodeEngine;
class AudioNodeExternalInputStream;
class AudioNodeStream;
class AudioSegment;
class CameraPreviewMediaStream;
class DirectMediaStreamListener;
class DirectMediaStreamTrackListener;
class MediaInputPort;
class MediaStreamGraphImpl;
class MediaStreamListener;
class MediaStreamTrackListener;
class ProcessedMediaStream;
class SourceMediaStream;
enum MediaStreamGraphEvent : uint32_t;
enum TrackEventCommand : uint32_t;
/**
* Helper struct for binding a track listener to a specific TrackID.
*/
@ -536,13 +262,7 @@ public:
protected:
// Protected destructor, to discourage deletion outside of Release():
virtual ~MediaStream()
{
MOZ_COUNT_DTOR(MediaStream);
NS_ASSERTION(mMainThreadDestroyed, "Should have been destroyed already");
NS_ASSERTION(mMainThreadListeners.IsEmpty(),
"All main thread listeners should have been removed");
}
virtual ~MediaStream();
public:
/**
@ -599,7 +319,7 @@ public:
* Note that the listener will be notified on the MediaStreamGraph thread
* with whether the installation of it at the source was successful or not.
*/
virtual void AddDirectTrackListener(MediaStreamTrackDirectListener* aListener,
virtual void AddDirectTrackListener(DirectMediaStreamTrackListener* aListener,
TrackID aTrackID);
/**
@ -610,7 +330,7 @@ public:
* the source cannot be found, or when the listener had already been removed
* does nothing.
*/
virtual void RemoveDirectTrackListener(MediaStreamTrackDirectListener* aListener,
virtual void RemoveDirectTrackListener(DirectMediaStreamTrackListener* aListener,
TrackID aTrackID);
// A disabled track has video replaced by black, and audio replaced by
@ -713,9 +433,9 @@ public:
TrackID aTrackID);
virtual void RemoveTrackListenerImpl(MediaStreamTrackListener* aListener,
TrackID aTrackID);
virtual void AddDirectTrackListenerImpl(already_AddRefed<MediaStreamTrackDirectListener> aListener,
virtual void AddDirectTrackListenerImpl(already_AddRefed<DirectMediaStreamTrackListener> aListener,
TrackID aTrackID);
virtual void RemoveDirectTrackListenerImpl(MediaStreamTrackDirectListener* aListener,
virtual void RemoveDirectTrackListenerImpl(DirectMediaStreamTrackListener* aListener,
TrackID aTrackID);
virtual void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled);
@ -864,7 +584,7 @@ protected:
float mVolume;
};
nsTArray<AudioOutput> mAudioOutputs;
nsTArray<RefPtr<VideoFrameContainer> > mVideoOutputs;
nsTArray<RefPtr<VideoFrameContainer>> mVideoOutputs;
// We record the last played video frame to avoid playing the frame again
// with a different frame id.
VideoFrame mLastPlayedVideoFrame;
@ -953,14 +673,7 @@ protected:
class SourceMediaStream : public MediaStream
{
public:
explicit SourceMediaStream() :
MediaStream(),
mMutex("mozilla::media::SourceMediaStream"),
mUpdateKnownTracksTime(0),
mPullEnabled(false),
mUpdateFinished(false),
mNeedsMixing(false)
{}
explicit SourceMediaStream();
SourceMediaStream* AsSourceStream() override { return this; }
@ -992,10 +705,10 @@ public:
* synchronization delays for e.g. PeerConnection, which wants the data ASAP
* and lets the far-end handle sync and playout timing.
*/
void NotifyListenersEventImpl(MediaStreamListener::MediaStreamGraphEvent aEvent);
void NotifyListenersEvent(MediaStreamListener::MediaStreamGraphEvent aEvent);
void AddDirectListener(MediaStreamDirectListener* aListener);
void RemoveDirectListener(MediaStreamDirectListener* aListener);
void NotifyListenersEventImpl(MediaStreamGraphEvent aEvent);
void NotifyListenersEvent(MediaStreamGraphEvent aEvent);
void AddDirectListener(DirectMediaStreamListener* aListener);
void RemoveDirectListener(DirectMediaStreamListener* aListener);
enum {
ADDTRACK_QUEUED = 0x01 // Queue track add until FinishAddTracks()
@ -1016,10 +729,7 @@ public:
* Like AddTrack, but resamples audio from aRate to the graph rate.
*/
void AddAudioTrack(TrackID aID, TrackRate aRate, StreamTime aStart,
AudioSegment* aSegment, uint32_t aFlags = 0)
{
AddTrackInternal(aID, aRate, aStart, aSegment, aFlags);
}
AudioSegment* aSegment, uint32_t aFlags = 0);
/**
* Call after a series of AddTrack or AddAudioTrack calls to implement
@ -1095,11 +805,10 @@ public:
friend class MediaStreamGraphImpl;
protected:
enum TrackCommands {
TRACK_CREATE = MediaStreamListener::TRACK_EVENT_CREATED,
TRACK_END = MediaStreamListener::TRACK_EVENT_ENDED,
TRACK_UNUSED = MediaStreamListener::TRACK_EVENT_UNUSED,
};
enum TrackCommands : uint32_t;
virtual ~SourceMediaStream();
/**
* Data for each track that hasn't ended.
*/
@ -1126,9 +835,9 @@ protected:
void ResampleAudioToGraphSampleRate(TrackData* aTrackData, MediaSegment* aSegment);
void AddDirectTrackListenerImpl(already_AddRefed<MediaStreamTrackDirectListener> aListener,
void AddDirectTrackListenerImpl(already_AddRefed<DirectMediaStreamTrackListener> aListener,
TrackID aTrackID) override;
void RemoveDirectTrackListenerImpl(MediaStreamTrackDirectListener* aListener,
void RemoveDirectTrackListenerImpl(DirectMediaStreamTrackListener* aListener,
TrackID aTrackID) override;
void AddTrackInternal(TrackID aID, TrackRate aRate,
@ -1168,8 +877,8 @@ protected:
StreamTime mUpdateKnownTracksTime;
nsTArray<TrackData> mUpdateTracks;
nsTArray<TrackData> mPendingTracks;
nsTArray<RefPtr<MediaStreamDirectListener> > mDirectListeners;
nsTArray<TrackBound<MediaStreamTrackDirectListener>> mDirectTrackListeners;
nsTArray<RefPtr<DirectMediaStreamListener>> mDirectListeners;
nsTArray<TrackBound<DirectMediaStreamTrackListener>> mDirectTrackListeners;
bool mPullEnabled;
bool mUpdateFinished;
bool mNeedsMixing;

View File

@ -0,0 +1,58 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MediaStreamListener.h"
#include "AudioSegment.h"
#include "VideoSegment.h"
#include "StreamTracks.h"
namespace mozilla {
void
DirectMediaStreamTrackListener::MirrorAndDisableSegment(AudioSegment& aFrom,
AudioSegment& aTo)
{
aTo.Clear();
aTo.AppendNullData(aFrom.GetDuration());
}
void
DirectMediaStreamTrackListener::MirrorAndDisableSegment(VideoSegment& aFrom,
VideoSegment& aTo)
{
aTo.Clear();
for (VideoSegment::ChunkIterator it(aFrom); !it.IsEnded(); it.Next()) {
aTo.AppendFrame(do_AddRef(it->mFrame.GetImage()), it->GetDuration(),
it->mFrame.GetIntrinsicSize(), it->GetPrincipalHandle(), true);
}
}
void
DirectMediaStreamTrackListener::NotifyRealtimeTrackDataAndApplyTrackDisabling(MediaStreamGraph* aGraph,
StreamTime aTrackOffset,
MediaSegment& aMedia)
{
if (mDisabledCount == 0) {
NotifyRealtimeTrackData(aGraph, aTrackOffset, aMedia);
return;
}
if (!mMedia) {
mMedia = aMedia.CreateEmptyClone();
}
if (aMedia.GetType() == MediaSegment::AUDIO) {
MirrorAndDisableSegment(static_cast<AudioSegment&>(aMedia),
static_cast<AudioSegment&>(*mMedia));
} else if (aMedia.GetType() == MediaSegment::VIDEO) {
MirrorAndDisableSegment(static_cast<VideoSegment&>(aMedia),
static_cast<VideoSegment&>(*mMedia));
} else {
MOZ_CRASH("Unsupported media type");
}
NotifyRealtimeTrackData(aGraph, aTrackOffset, *mMedia);
}
} // namespace mozilla

View File

@ -0,0 +1,286 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_MEDIASTREAMLISTENER_h_
#define MOZILLA_MEDIASTREAMLISTENER_h_
namespace mozilla {
class MediaStream;
class MediaStreamGraph;
enum MediaStreamGraphEvent : uint32_t {
EVENT_FINISHED,
EVENT_REMOVED,
EVENT_HAS_DIRECT_LISTENERS, // transition from no direct listeners
EVENT_HAS_NO_DIRECT_LISTENERS, // transition to no direct listeners
};
// maskable flags, not a simple enumerated value
enum TrackEventCommand : uint32_t {
TRACK_EVENT_NONE = 0x00,
TRACK_EVENT_CREATED = 0x01,
TRACK_EVENT_ENDED = 0x02,
TRACK_EVENT_UNUSED = ~(TRACK_EVENT_ENDED | TRACK_EVENT_CREATED),
};
/**
* This is a base class for media graph thread listener callbacks.
* Override methods to be notified of audio or video data or changes in stream
* state.
*
* This can be used by stream recorders or network connections that receive
* stream input. It could also be used for debugging.
*
* All notification methods are called from the media graph thread. Overriders
* of these methods are responsible for all synchronization. Beware!
* These methods are called without the media graph monitor held, so
* reentry into media graph methods is possible, although very much discouraged!
* You should do something non-blocking and non-reentrant (e.g. dispatch an
* event to some thread) and return.
* The listener is not allowed to add/remove any listeners from the stream.
*
* When a listener is first attached, we guarantee to send a NotifyBlockingChanged
* callback to notify of the initial blocking state. Also, if a listener is
* attached to a stream that has already finished, we'll call NotifyFinished.
*/
class MediaStreamListener {
protected:
// Protected destructor, to discourage deletion outside of Release():
virtual ~MediaStreamListener() {}
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStreamListener)
/**
* When a SourceMediaStream has pulling enabled, and the MediaStreamGraph
* control loop is ready to pull, this gets called. A NotifyPull implementation
* is allowed to call the SourceMediaStream methods that alter track
* data. It is not allowed to make other MediaStream API calls, including
* calls to add or remove MediaStreamListeners. It is not allowed to block
* for any length of time.
* aDesiredTime is the stream time we would like to get data up to. Data
* beyond this point will not be played until NotifyPull runs again, so there's
* not much point in providing it. Note that if the stream is blocked for
* some reason, then data before aDesiredTime may not be played immediately.
*/
virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) {}
enum Blocking {
BLOCKED,
UNBLOCKED
};
/**
* Notify that the blocking status of the stream changed. The initial state
* is assumed to be BLOCKED.
*/
virtual void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked) {}
/**
* Notify that the stream has data in each track
* for the stream's current time. Once this state becomes true, it will
* always be true since we block stream time from progressing to times where
* there isn't data in each track.
*/
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph) {}
/**
* Notify that the stream output is advancing. aCurrentTime is the graph's
* current time. MediaStream::GraphTimeToStreamTime can be used to get the
* stream time.
*/
virtual void NotifyOutput(MediaStreamGraph* aGraph, GraphTime aCurrentTime) {}
/**
* Notify that an event has occurred on the Stream
*/
virtual void NotifyEvent(MediaStreamGraph* aGraph, MediaStreamGraphEvent aEvent) {}
/**
* Notify that changes to one of the stream tracks have been queued.
* aTrackEvents can be any combination of TRACK_EVENT_CREATED and
* TRACK_EVENT_ENDED. aQueuedMedia is the data being added to the track
* at aTrackOffset (relative to the start of the stream).
* aInputStream and aInputTrackID will be set if the changes originated
* from an input stream's track. In practice they will only be used for
* ProcessedMediaStreams.
*/
virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset,
TrackEventCommand aTrackEvents,
const MediaSegment& aQueuedMedia,
MediaStream* aInputStream = nullptr,
TrackID aInputTrackID = TRACK_INVALID) {}
/**
* Notify queued audio data. Only audio data need to be queued. The video data
* will be notified by MediaStreamVideoSink::SetCurrentFrame.
*/
virtual void NotifyQueuedAudioData(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset,
const AudioSegment& aQueuedMedia,
MediaStream* aInputStream = nullptr,
TrackID aInputTrackID = TRACK_INVALID) {}
/**
* Notify that all new tracks this iteration have been created.
* This is to ensure that tracks added atomically to MediaStreamGraph
* are also notified of atomically to MediaStreamListeners.
*/
virtual void NotifyFinishedTrackCreation(MediaStreamGraph* aGraph) {}
};
/**
* This is a base class for media graph thread listener callbacks locked to
* specific tracks. Override methods to be notified of audio or video data or
* changes in track state.
*
* All notification methods are called from the media graph thread. Overriders
* of these methods are responsible for all synchronization. Beware!
* These methods are called without the media graph monitor held, so
* reentry into media graph methods is possible, although very much discouraged!
* You should do something non-blocking and non-reentrant (e.g. dispatch an
* event to some thread) and return.
* The listener is not allowed to add/remove any listeners from the parent
* stream.
*
* If a listener is attached to a track that has already ended, we guarantee
* to call NotifyEnded.
*/
class MediaStreamTrackListener
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaStreamTrackListener)
public:
virtual void NotifyQueuedChanges(MediaStreamGraph* aGraph,
StreamTime aTrackOffset,
const MediaSegment& aQueuedMedia) {}
virtual void NotifyPrincipalHandleChanged(MediaStreamGraph* aGraph,
const PrincipalHandle& aNewPrincipalHandle) {}
virtual void NotifyEnded() {}
virtual void NotifyRemoved() {}
protected:
virtual ~MediaStreamTrackListener() {}
};
/**
* This is a base class for media graph thread listener direct callbacks
* from within AppendToTrack(). Note that your regular listener will
* still get NotifyQueuedTrackChanges() callbacks from the MSG thread, so
* you must be careful to ignore them if AddDirectListener was successful.
*/
class DirectMediaStreamListener : public MediaStreamListener
{
public:
virtual ~DirectMediaStreamListener() {}
/*
* This will be called on any DirectMediaStreamListener added to a
* a SourceMediaStream when AppendToTrack() is called. The MediaSegment
* will be the RawSegment (unresampled) if available in AppendToTrack().
* Note that NotifyQueuedTrackChanges() calls will also still occur.
*/
virtual void NotifyRealtimeData(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset,
uint32_t aTrackEvents,
const MediaSegment& aMedia) {}
};
/**
* This is a base class for media graph thread listener direct callbacks from
* within AppendToTrack(). It is bound to a certain track and can only be
* installed on audio tracks. Once added to a track on any stream in the graph,
* the graph will try to install it at that track's source of media data.
*
* This works for TrackUnionStreams, which will forward the listener to the
* track's input track if it exists, or wait for it to be created before
* forwarding if it doesn't.
* Once it reaches a SourceMediaStream, it can be successfully installed.
* Other types of streams will fail installation since they are not supported.
*
* Note that this listener and others for the same track will still get
* NotifyQueuedChanges() callbacks from the MSG tread, so you must be careful
* to ignore them if this listener was successfully installed.
*/
class DirectMediaStreamTrackListener : public MediaStreamTrackListener
{
friend class SourceMediaStream;
friend class TrackUnionStream;
public:
/*
* This will be called on any DirectMediaStreamTrackListener added to a
* SourceMediaStream when AppendToTrack() is called for the listener's bound
* track, using the thread of the AppendToTrack() caller. The MediaSegment
* will be the RawSegment (unresampled) if available in AppendToTrack().
* If the track is enabled at the source but has been disabled in one of the
* streams in between the source and where it was originally added, aMedia
* will be a disabled version of the one passed to AppendToTrack() as well.
* Note that NotifyQueuedTrackChanges() calls will also still occur.
*/
virtual void NotifyRealtimeTrackData(MediaStreamGraph* aGraph,
StreamTime aTrackOffset,
const MediaSegment& aMedia) {}
/**
* When a direct listener is processed for installation by the
* MediaStreamGraph it will be notified with whether the installation was
* successful or not. The results of this installation are the following:
* TRACK_NOT_FOUND_AT_SOURCE
* We found the source stream of media data for this track, but the track
* didn't exist. This should only happen if you try to install the listener
* directly to a SourceMediaStream that doesn't contain the given TrackID.
* STREAM_NOT_SUPPORTED
* While looking for the data source of this track, we found a MediaStream
* that is not a SourceMediaStream or a TrackUnionStream.
* SUCCESS
* Installation was successful and this listener will start receiving
* NotifyRealtimeData on the next AppendToTrack().
*/
enum class InstallationResult {
TRACK_NOT_FOUND_AT_SOURCE,
TRACK_TYPE_NOT_SUPPORTED,
STREAM_NOT_SUPPORTED,
SUCCESS
};
virtual void NotifyDirectListenerInstalled(InstallationResult aResult) {}
virtual void NotifyDirectListenerUninstalled() {}
protected:
virtual ~DirectMediaStreamTrackListener() {}
void MirrorAndDisableSegment(AudioSegment& aFrom, AudioSegment& aTo);
void MirrorAndDisableSegment(VideoSegment& aFrom, VideoSegment& aTo);
void NotifyRealtimeTrackDataAndApplyTrackDisabling(MediaStreamGraph* aGraph,
StreamTime aTrackOffset,
MediaSegment& aMedia);
void IncreaseDisabled()
{
++mDisabledCount;
}
void DecreaseDisabled()
{
--mDisabledCount;
MOZ_ASSERT(mDisabledCount >= 0, "Double decrease");
}
// Matches the number of disabled streams to which this listener is attached.
// The number of streams are those between the stream the listener was added
// and the SourceMediaStream that is the input of the data.
Atomic<int32_t> mDisabledCount;
nsAutoPtr<MediaSegment> mMedia;
};
} // namespace mozilla
#endif // MOZILLA_MEDIASTREAMLISTENER_h_

View File

@ -9,6 +9,7 @@
#include "MediaStreamGraph.h"
#include "nsIUUIDGenerator.h"
#include "nsServiceManagerUtils.h"
#include "MediaStreamListener.h"
#ifdef LOG
#undef LOG
@ -161,6 +162,12 @@ MediaStreamTrack::Destroy()
mPrincipalHandleListener->Forget();
mPrincipalHandleListener = nullptr;
}
for (auto l : mTrackListeners) {
RemoveListener(l);
}
for (auto l : mDirectTrackListeners) {
RemoveDirectListener(l);
}
}
NS_IMPL_CYCLE_COLLECTION_CLASS(MediaStreamTrack)
@ -387,6 +394,11 @@ MediaStreamTrack::GetInputStream()
ProcessedMediaStream*
MediaStreamTrack::GetOwnedStream()
{
if (!mOwningStream)
{
return nullptr;
}
return mOwningStream->GetOwnedStream();
}
@ -395,8 +407,10 @@ MediaStreamTrack::AddListener(MediaStreamTrackListener* aListener)
{
LOG(LogLevel::Debug, ("MediaStreamTrack %p adding listener %p",
this, aListener));
MOZ_ASSERT(GetOwnedStream());
GetOwnedStream()->AddTrackListener(aListener, mTrackID);
mTrackListeners.AppendElement(aListener);
}
void
@ -405,27 +419,35 @@ MediaStreamTrack::RemoveListener(MediaStreamTrackListener* aListener)
LOG(LogLevel::Debug, ("MediaStreamTrack %p removing listener %p",
this, aListener));
GetOwnedStream()->RemoveTrackListener(aListener, mTrackID);
if (GetOwnedStream()) {
GetOwnedStream()->RemoveTrackListener(aListener, mTrackID);
mTrackListeners.RemoveElement(aListener);
}
}
void
MediaStreamTrack::AddDirectListener(MediaStreamTrackDirectListener *aListener)
MediaStreamTrack::AddDirectListener(DirectMediaStreamTrackListener *aListener)
{
LOG(LogLevel::Debug, ("MediaStreamTrack %p (%s) adding direct listener %p to "
"stream %p, track %d",
this, AsAudioStreamTrack() ? "audio" : "video",
aListener, GetOwnedStream(), mTrackID));
MOZ_ASSERT(GetOwnedStream());
GetOwnedStream()->AddDirectTrackListener(aListener, mTrackID);
mDirectTrackListeners.AppendElement(aListener);
}
void
MediaStreamTrack::RemoveDirectListener(MediaStreamTrackDirectListener *aListener)
MediaStreamTrack::RemoveDirectListener(DirectMediaStreamTrackListener *aListener)
{
LOG(LogLevel::Debug, ("MediaStreamTrack %p removing direct listener %p from stream %p",
this, aListener, GetOwnedStream()));
GetOwnedStream()->RemoveDirectTrackListener(aListener, mTrackID);
if (GetOwnedStream()) {
GetOwnedStream()->RemoveDirectTrackListener(aListener, mTrackID);
mDirectTrackListeners.RemoveElement(aListener);
}
}
already_AddRefed<MediaInputPort>

View File

@ -24,7 +24,7 @@ class MediaStream;
class MediaStreamGraph;
class MediaStreamGraphImpl;
class MediaStreamTrackListener;
class MediaStreamTrackDirectListener;
class DirectMediaStreamTrackListener;
class PeerConnectionImpl;
class PeerConnectionMedia;
class PeerIdentity;
@ -363,8 +363,8 @@ public:
* the listener succeeded (tracks originating from SourceMediaStreams) or
* failed (e.g., WebAudio originated tracks).
*/
void AddDirectListener(MediaStreamTrackDirectListener *aListener);
void RemoveDirectListener(MediaStreamTrackDirectListener *aListener);
void AddDirectListener(DirectMediaStreamTrackListener *aListener);
void RemoveDirectListener(DirectMediaStreamTrackListener *aListener);
/**
* Sets up a MediaInputPort from the underlying track that this
@ -378,6 +378,8 @@ public:
*/
bool IsForwardedThrough(MediaInputPort* aPort);
void SetMediaStreamSizeListener(DirectMediaStreamTrackListener* aListener);
protected:
virtual ~MediaStreamTrack();
@ -416,6 +418,10 @@ protected:
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIPrincipal> mPendingPrincipal;
RefPtr<PrincipalHandleListener> mPrincipalHandleListener;
// Keep tracking MediaStreamTrackListener and DirectMediaStreamTrackListener,
// so we can remove them in |Destory|.
nsTArray<RefPtr<MediaStreamTrackListener>> mTrackListeners;
nsTArray<RefPtr<DirectMediaStreamTrackListener>> mDirectTrackListeners;
nsString mID;
MediaStreamTrackState mReadyState;
bool mEnabled;

View File

@ -9,6 +9,7 @@
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/AudioTrack.h"
#include "mozilla/dom/VideoStreamTrack.h"
#include "mozilla/dom/VideoTrack.h"
#include "mozilla/dom/TrackEvent.h"
#include "nsThreadUtils.h"
@ -106,9 +107,10 @@ already_AddRefed<VideoTrack>
MediaTrackList::CreateVideoTrack(const nsAString& aId,
const nsAString& aKind,
const nsAString& aLabel,
const nsAString& aLanguage)
const nsAString& aLanguage,
VideoStreamTrack* aVideoTrack)
{
RefPtr<VideoTrack> track = new VideoTrack(aId, aKind, aLabel, aLanguage);
RefPtr<VideoTrack> track = new VideoTrack(aId, aKind, aLabel, aLanguage, aVideoTrack);
return track.forget();
}

View File

@ -20,6 +20,7 @@ class AudioTrackList;
class VideoTrackList;
class AudioTrack;
class VideoTrack;
class VideoStreamTrack;
/**
* Base class of AudioTrackList and VideoTrackList. The AudioTrackList and
@ -58,11 +59,14 @@ public:
const nsAString& aLanguage,
bool aEnabled);
// For the case of src of HTMLMediaElement is non-MediaStream, leave the
// aVideoTrack as default(nullptr).
static already_AddRefed<VideoTrack>
CreateVideoTrack(const nsAString& aId,
const nsAString& aKind,
const nsAString& aLabel,
const nsAString& aLanguage);
const nsAString& aLanguage,
VideoStreamTrack* aVideoTrack = nullptr);
virtual void EmptyTracks();

View File

@ -4,6 +4,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MediaStreamGraphImpl.h"
#include "MediaStreamListener.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/unused.h"
@ -200,7 +201,7 @@ TrackUnionStream::TrackUnionStream() :
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
MediaStreamListener* l = mListeners[j];
l->NotifyQueuedTrackChanges(Graph(), id, outputStart,
MediaStreamListener::TRACK_EVENT_CREATED,
TrackEventCommand::TRACK_EVENT_CREATED,
*segment,
aPort->GetSource(), aTrack->GetID());
}
@ -221,7 +222,7 @@ TrackUnionStream::TrackUnionStream() :
map->mSegment = aTrack->GetSegment()->CreateEmptyClone();
for (int32_t i = mPendingDirectTrackListeners.Length() - 1; i >= 0; --i) {
TrackBound<MediaStreamTrackDirectListener>& bound =
TrackBound<DirectMediaStreamTrackListener>& bound =
mPendingDirectTrackListeners[i];
if (bound.mTrackID != map->mOutputTrackID) {
continue;
@ -256,7 +257,7 @@ TrackUnionStream::TrackUnionStream() :
nsAutoPtr<MediaSegment> segment;
segment = outputTrack->GetSegment()->CreateEmptyClone();
l->NotifyQueuedTrackChanges(Graph(), outputTrack->GetID(), offset,
MediaStreamListener::TRACK_EVENT_ENDED,
TrackEventCommand::TRACK_EVENT_ENDED,
*segment,
mTrackMap[aIndex].mInputPort->GetSource(),
mTrackMap[aIndex].mInputTrackID);
@ -334,7 +335,7 @@ TrackUnionStream::TrackUnionStream() :
} else {
// This part will be removed in bug 1201363.
l->NotifyQueuedTrackChanges(Graph(), outputTrack->GetID(),
outputStart, 0, *segment,
outputStart, TrackEventCommand::TRACK_EVENT_NONE, *segment,
map->mInputPort->GetSource(),
map->mInputTrackID);
}
@ -355,7 +356,7 @@ TrackUnionStream::SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled) {
if (entry.mOutputTrackID == aTrackID) {
STREAM_LOG(LogLevel::Info, ("TrackUnionStream %p track %d was explicitly %s",
this, aTrackID, aEnabled ? "enabled" : "disabled"));
for (MediaStreamTrackDirectListener* listener : entry.mOwnedDirectListeners) {
for (DirectMediaStreamTrackListener* listener : entry.mOwnedDirectListeners) {
bool oldEnabled = !mDisabledTrackIDs.Contains(aTrackID);
if (!oldEnabled && aEnabled) {
STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p track %d setting "
@ -399,10 +400,10 @@ TrackUnionStream::GetInputTrackIDFor(TrackID aTrackID)
}
void
TrackUnionStream::AddDirectTrackListenerImpl(already_AddRefed<MediaStreamTrackDirectListener> aListener,
TrackUnionStream::AddDirectTrackListenerImpl(already_AddRefed<DirectMediaStreamTrackListener> aListener,
TrackID aTrackID)
{
RefPtr<MediaStreamTrackDirectListener> listener = aListener;
RefPtr<DirectMediaStreamTrackListener> listener = aListener;
for (TrackMapEntry& entry : mTrackMap) {
if (entry.mOutputTrackID == aTrackID) {
@ -422,14 +423,14 @@ TrackUnionStream::AddDirectTrackListenerImpl(already_AddRefed<MediaStreamTrackDi
}
}
TrackBound<MediaStreamTrackDirectListener>* bound =
TrackBound<DirectMediaStreamTrackListener>* bound =
mPendingDirectTrackListeners.AppendElement();
bound->mListener = listener.forget();
bound->mTrackID = aTrackID;
}
void
TrackUnionStream::RemoveDirectTrackListenerImpl(MediaStreamTrackDirectListener* aListener,
TrackUnionStream::RemoveDirectTrackListenerImpl(DirectMediaStreamTrackListener* aListener,
TrackID aTrackID)
{
for (TrackMapEntry& entry : mTrackMap) {
@ -460,7 +461,7 @@ TrackUnionStream::RemoveDirectTrackListenerImpl(MediaStreamTrackDirectListener*
}
for (size_t i = 0; i < mPendingDirectTrackListeners.Length(); ++i) {
TrackBound<MediaStreamTrackDirectListener>& bound =
TrackBound<DirectMediaStreamTrackListener>& bound =
mPendingDirectTrackListeners[i];
if (bound.mListener == aListener && bound.mTrackID == aTrackID) {
mPendingDirectTrackListeners.RemoveElementAt(i);

View File

@ -53,7 +53,7 @@ protected:
// These are direct track listeners that have been added to this
// TrackUnionStream-track and forwarded to the input track. We will update
// these when this track's disabled status changes.
nsTArray<RefPtr<MediaStreamTrackDirectListener>> mOwnedDirectListeners;
nsTArray<RefPtr<DirectMediaStreamTrackListener>> mOwnedDirectListeners;
};
// Add the track to this stream, retaining its TrackID if it has never
@ -65,9 +65,9 @@ protected:
uint32_t aMapIndex, GraphTime aFrom, GraphTime aTo,
bool* aOutputTrackFinished);
void AddDirectTrackListenerImpl(already_AddRefed<MediaStreamTrackDirectListener> aListener,
void AddDirectTrackListenerImpl(already_AddRefed<DirectMediaStreamTrackListener> aListener,
TrackID aTrackID) override;
void RemoveDirectTrackListenerImpl(MediaStreamTrackDirectListener* aListener,
void RemoveDirectTrackListenerImpl(DirectMediaStreamTrackListener* aListener,
TrackID aTrackID) override;
nsTArray<TrackMapEntry> mTrackMap;
@ -81,7 +81,7 @@ protected:
// Direct track listeners that have not been forwarded to their input stream
// yet. We'll forward these as their inputs become available.
nsTArray<TrackBound<MediaStreamTrackDirectListener>> mPendingDirectTrackListeners;
nsTArray<TrackBound<DirectMediaStreamTrackListener>> mPendingDirectTrackListeners;
};
} // namespace mozilla

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/VideoStreamTrack.h"
#include "mozilla/dom/VideoTrack.h"
#include "mozilla/dom/VideoTrackBinding.h"
#include "mozilla/dom/VideoTrackList.h"
@ -15,12 +16,25 @@ namespace dom {
VideoTrack::VideoTrack(const nsAString& aId,
const nsAString& aKind,
const nsAString& aLabel,
const nsAString& aLanguage)
const nsAString& aLanguage,
VideoStreamTrack* aStreamTarck)
: MediaTrack(aId, aKind, aLabel, aLanguage)
, mSelected(false)
, mVideoStreamTrack(aStreamTarck)
{
}
VideoTrack::~VideoTrack()
{
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(VideoTrack, MediaTrack, mVideoStreamTrack)
NS_IMPL_ADDREF_INHERITED(VideoTrack, MediaTrack)
NS_IMPL_RELEASE_INHERITED(VideoTrack, MediaTrack)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(VideoTrack)
NS_INTERFACE_MAP_END_INHERITING(MediaTrack)
JSObject*
VideoTrack::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{

View File

@ -13,6 +13,7 @@ namespace mozilla {
namespace dom {
class VideoTrackList;
class VideoStreamTrack;
class VideoTrack : public MediaTrack
{
@ -20,7 +21,11 @@ public:
VideoTrack(const nsAString& aId,
const nsAString& aKind,
const nsAString& aLabel,
const nsAString& aLanguage);
const nsAString& aLanguage,
VideoStreamTrack* aStreamTarck = nullptr);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(VideoTrack, MediaTrack)
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@ -36,6 +41,11 @@ public:
// aFlags contains FIRE_NO_EVENTS because no events are fired in such cases.
void SetEnabledInternal(bool aEnabled, int aFlags) override;
// Get associated video stream track when the video track comes from
// MediaStream. This might be nullptr when the src of owning HTMLMediaElement
// is not MediaStream.
VideoStreamTrack* GetVideoStreamTrack() { return mVideoStreamTrack; }
// WebIDL
bool Selected() const
{
@ -48,7 +58,10 @@ public:
void SetSelected(bool aSelected);
private:
virtual ~VideoTrack();
bool mSelected;
RefPtr<VideoStreamTrack> mVideoStreamTrack;
};
} // namespace dom

View File

@ -31,18 +31,18 @@ VideoTrackList::RemoveTrack(const RefPtr<MediaTrack>& aTrack)
// need to be done after RemoveTrack. Also the call of
// |MediaTrackList::RemoveTrack| is necessary even when mSelectedIndex = -1.
bool found;
VideoTrack* videoTrack = IndexedGetter(mSelectedIndex, found);
VideoTrack* selectedVideoTrack = IndexedGetter(mSelectedIndex, found);
MediaTrackList::RemoveTrack(aTrack);
if (mSelectedIndex == -1) {
// There was no selected track and we don't select another track on removal.
return;
}
MOZ_ASSERT(found, "When mSelectedIndex is set it should point to a track");
MOZ_ASSERT(videoTrack, "The mSelectedIndex should be set to video track only");
MOZ_ASSERT(selectedVideoTrack, "The mSelectedIndex should be set to video track only");
// Let the caller of RemoveTrack deal with choosing the new selected track if
// it removes the currently-selected track.
if (aTrack == videoTrack) {
if (aTrack == selectedVideoTrack) {
mSelectedIndex = -1;
return;
}
@ -51,7 +51,7 @@ VideoTrackList::RemoveTrack(const RefPtr<MediaTrack>& aTrack)
// currently-selected video track. We need to find the new location of the
// selected track.
for (size_t ix = 0; ix < mTracks.Length(); ix++) {
if (mTracks[ix] == videoTrack) {
if (mTracks[ix] == selectedVideoTrack) {
mSelectedIndex = ix;
return;
}

View File

@ -21,9 +21,6 @@
#if defined(_MSC_VER)
#define strtoll _strtoi64
#if _MSC_VER < 1900
#define snprintf _snprintf_s
#endif
#endif
using namespace mozilla;

View File

@ -66,7 +66,7 @@ void
MediaEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
TrackID aID,
StreamTime aTrackOffset,
uint32_t aTrackEvents,
TrackEventCommand aTrackEvents,
const MediaSegment& aQueuedMedia,
MediaStream* aInputStream,
TrackID aInputTrackID)
@ -74,7 +74,7 @@ MediaEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
if (!mDirectConnected) {
NotifyRealtimeData(aGraph, aID, aTrackOffset, aTrackEvents, aQueuedMedia);
} else {
if (aTrackEvents != 0) {
if (aTrackEvents != TrackEventCommand::TRACK_EVENT_NONE) {
// forward events (TRACK_EVENT_ENDED) but not the media
if (aQueuedMedia.GetType() == MediaSegment::VIDEO) {
VideoSegment segment;
@ -125,7 +125,7 @@ MediaEncoder::NotifyQueuedAudioData(MediaStreamGraph* aGraph, TrackID aID,
void
MediaEncoder::NotifyEvent(MediaStreamGraph* aGraph,
MediaStreamListener::MediaStreamGraphEvent event)
MediaStreamGraphEvent event)
{
// In case that MediaEncoder does not receive a TRACK_EVENT_ENDED event.
LOG(LogLevel::Debug, ("NotifyRemoved in [MediaEncoder]."));

View File

@ -10,6 +10,7 @@
#include "TrackEncoder.h"
#include "ContainerWriter.h"
#include "MediaStreamGraph.h"
#include "MediaStreamListener.h"
#include "nsAutoPtr.h"
#include "nsIMemoryReporter.h"
#include "mozilla/MemoryReporting.h"
@ -51,7 +52,7 @@ namespace mozilla {
* 4) To stop encoding, remove this component from its source stream.
* => sourceStream->RemoveListener(encoder);
*/
class MediaEncoder : public MediaStreamDirectListener
class MediaEncoder : public DirectMediaStreamListener
{
public :
enum {
@ -125,7 +126,7 @@ public :
*/
void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset,
uint32_t aTrackEvents,
TrackEventCommand aTrackEvents,
const MediaSegment& aQueuedMedia,
MediaStream* aInputStream,
TrackID aInputTrackID) override;
@ -144,7 +145,7 @@ public :
* * Notified the stream is being removed.
*/
void NotifyEvent(MediaStreamGraph* aGraph,
MediaStreamListener::MediaStreamGraphEvent event) override;
MediaStreamGraphEvent event) override;
/**
* Creates an encoder with a given MIME type. Returns null if we are unable

View File

@ -5,6 +5,7 @@
#include "TrackEncoder.h"
#include "AudioChannelFormat.h"
#include "MediaStreamGraph.h"
#include "MediaStreamListener.h"
#include "mozilla/Logging.h"
#include "VideoUtils.h"
@ -41,6 +42,14 @@ TrackEncoder::TrackEncoder()
{
}
void TrackEncoder::NotifyEvent(MediaStreamGraph* aGraph,
MediaStreamGraphEvent event)
{
if (event == MediaStreamGraphEvent::EVENT_REMOVED) {
NotifyEndOfStream();
}
}
void
AudioTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
TrackID aID,
@ -91,7 +100,7 @@ AudioTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
// The stream has stopped and reached the end of track.
if (aTrackEvents == MediaStreamListener::TRACK_EVENT_ENDED) {
if (aTrackEvents == TrackEventCommand::TRACK_EVENT_ENDED) {
LOG("[AudioTrackEncoder]: Receive TRACK_EVENT_ENDED .");
NotifyEndOfStream();
}
@ -232,7 +241,7 @@ VideoTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
AppendVideoSegment(video);
// The stream has stopped and reached the end of track.
if (aTrackEvents == MediaStreamListener::TRACK_EVENT_ENDED) {
if (aTrackEvents == TrackEventCommand::TRACK_EVENT_ENDED) {
LOG("[VideoTrackEncoder]: Receive TRACK_EVENT_ENDED .");
NotifyEndOfStream();
}

View File

@ -48,12 +48,7 @@ public:
* MediaStreamGraph. Called on the MediaStreamGraph thread.
*/
void NotifyEvent(MediaStreamGraph* aGraph,
MediaStreamListener::MediaStreamGraphEvent event)
{
if (event == MediaStreamListener::MediaStreamGraphEvent::EVENT_REMOVED) {
NotifyEndOfStream();
}
}
MediaStreamGraphEvent event);
/**
* Creates and sets up meta data for a specific codec, called on the worker

View File

@ -23,8 +23,6 @@ GMPContentChild::GMPContentChild(GMPChild* aChild)
GMPContentChild::~GMPContentChild()
{
MOZ_COUNT_DTOR(GMPContentChild);
RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
XRE_GetIOMessageLoop()->PostTask(task.forget());
}
MessageLoop*

View File

@ -44,8 +44,6 @@ GMPContentParent::GMPContentParent(GMPParent* aParent)
GMPContentParent::~GMPContentParent()
{
RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
XRE_GetIOMessageLoop()->PostTask(task.forget());
}
class ReleaseGMPContentParent : public Runnable

View File

@ -266,8 +266,6 @@ GMPServiceChild::GMPServiceChild()
GMPServiceChild::~GMPServiceChild()
{
RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
XRE_GetIOMessageLoop()->PostTask(task.forget());
}
PGMPContentParent*

View File

@ -1835,8 +1835,6 @@ GeckoMediaPluginServiceParent::GetById(uint32_t aPluginId)
GMPServiceParent::~GMPServiceParent()
{
RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
XRE_GetIOMessageLoop()->PostTask(task.forget());
}
bool

View File

@ -9,6 +9,7 @@
#include "VP8TrackEncoder.h"
#include "ImageContainer.h"
#include "MediaStreamGraph.h"
#include "MediaStreamListener.h"
#include "WebMWriter.h" // TODO: it's weird to include muxer header to get the class definition of VP8 METADATA
using ::testing::TestWithParam;
@ -296,7 +297,7 @@ TEST(VP8VideoTrackEncoder, EncodeComplete)
// track end notification.
VideoSegment segment;
encoder.NotifyQueuedTrackChanges(nullptr, 0, 0, MediaStreamListener::TRACK_EVENT_ENDED, segment);
encoder.NotifyQueuedTrackChanges(nullptr, 0, 0, TrackEventCommand::TRACK_EVENT_ENDED, segment);
// Pull Encoded Data back from encoder. Since we have sent
// EOS to encoder, encoder.GetEncodedTrack should return

View File

@ -8,6 +8,7 @@
#define CAPTURETASK_H
#include "MediaStreamGraph.h"
#include "MediaStreamListener.h"
#include "PrincipalChangeObserver.h"
namespace mozilla {

View File

@ -13,6 +13,7 @@
#include "MediaData.h"
#include "MediaQueue.h"
#include "MediaStreamGraph.h"
#include "MediaStreamListener.h"
#include "OutputStreamManager.h"
#include "SharedBuffer.h"
#include "VideoSegment.h"
@ -30,7 +31,6 @@ struct PlaybackInfoInit {
};
class DecodedStreamGraphListener : public MediaStreamListener {
typedef MediaStreamListener::MediaStreamGraphEvent MediaStreamGraphEvent;
public:
DecodedStreamGraphListener(MediaStream* aStream,
MozPromiseHolder<GenericPromise>&& aPromise)
@ -52,7 +52,7 @@ public:
void NotifyEvent(MediaStreamGraph* aGraph, MediaStreamGraphEvent event) override
{
if (event == EVENT_FINISHED) {
if (event == MediaStreamGraphEvent::EVENT_FINISHED) {
nsCOMPtr<nsIRunnable> event =
NewRunnableMethod(this, &DecodedStreamGraphListener::DoNotifyFinished);
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());

View File

@ -127,6 +127,7 @@ EXPORTS += [
'MediaSegment.h',
'MediaStatistics.h',
'MediaStreamGraph.h',
'MediaStreamListener.h',
'MediaTimer.h',
'MediaTrack.h',
'MediaTrackList.h',
@ -238,6 +239,7 @@ UNIFIED_SOURCES += [
'MediaShutdownManager.cpp',
'MediaStreamError.cpp',
'MediaStreamGraph.cpp',
'MediaStreamListener.cpp',
'MediaStreamTrack.cpp',
'MediaTimer.cpp',
'MediaTrack.cpp',

View File

@ -6,6 +6,7 @@
#include "AudioNodeStream.h"
#include "MediaStreamGraphImpl.h"
#include "MediaStreamListener.h"
#include "AudioNodeEngine.h"
#include "ThreeDPoint.h"
#include "AudioChannelFormat.h"
@ -647,7 +648,7 @@ AudioNodeStream::AdvanceOutputSegment()
AudioSegment tmpSegment;
tmpSegment.AppendAndConsumeChunk(&copyChunk);
l->NotifyQueuedTrackChanges(Graph(), AUDIO_TRACK,
segment->GetDuration(), 0, tmpSegment);
segment->GetDuration(), TrackEventCommand::TRACK_EVENT_NONE, tmpSegment);
}
}
@ -662,7 +663,7 @@ AudioNodeStream::FinishOutput()
AudioSegment emptySegment;
l->NotifyQueuedTrackChanges(Graph(), AUDIO_TRACK,
track->GetSegment()->GetDuration(),
MediaStreamListener::TRACK_EVENT_ENDED, emptySegment);
TrackEventCommand::TRACK_EVENT_ENDED, emptySegment);
}
}

View File

@ -85,7 +85,7 @@ SpeechStreamListener::ConvertAndDispatchAudioChunk(int aDuration, float aVolume,
void
SpeechStreamListener::NotifyEvent(MediaStreamGraph* aGraph,
MediaStreamListener::MediaStreamGraphEvent event)
MediaStreamGraphEvent event)
{
// TODO dispatch SpeechEnd event so services can be informed
}

View File

@ -8,6 +8,7 @@
#define mozilla_dom_SpeechStreamListener_h
#include "MediaStreamGraph.h"
#include "MediaStreamListener.h"
#include "AudioSegment.h"
namespace mozilla {
@ -31,7 +32,7 @@ public:
TrackID aInputTrackID) override;
void NotifyEvent(MediaStreamGraph* aGraph,
MediaStreamListener::MediaStreamGraphEvent event) override;
MediaStreamGraphEvent event) override;
private:
template<typename SampleFormatType>

View File

@ -7,8 +7,10 @@
#include "AudioChannelAgent.h"
#include "AudioChannelService.h"
#include "AudioSegment.h"
#include "MediaStreamListener.h"
#include "nsSpeechTask.h"
#include "nsSynthVoiceRegistry.h"
#include "SharedBuffer.h"
#include "SpeechSynthesis.h"
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
@ -53,10 +55,10 @@ public:
}
void NotifyEvent(MediaStreamGraph* aGraph,
MediaStreamListener::MediaStreamGraphEvent event) override
MediaStreamGraphEvent event) override
{
switch (event) {
case EVENT_FINISHED:
case MediaStreamGraphEvent::EVENT_FINISHED:
{
if (!mStarted) {
mStarted = true;
@ -70,7 +72,7 @@ public:
aGraph->DispatchToMainThreadAfterStreamStateUpdate(endRunnable.forget());
}
break;
case EVENT_REMOVED:
case MediaStreamGraphEvent::EVENT_REMOVED:
mSpeechTask = nullptr;
// Dereference MediaStream to destroy safety
mStream = nullptr;

View File

@ -13,6 +13,9 @@
#include "nsISpeechService.h"
namespace mozilla {
class SharedBuffer;
namespace dom {
class SpeechSynthesisUtterance;

View File

@ -62,6 +62,7 @@ DIRS += [
'fmradio',
'gamepad',
'geolocation',
'grid',
'html',
'icc',
'inputport',

View File

@ -108,7 +108,6 @@ static const TCHAR kPluginIgnoreSubclassProperty[] = TEXT("PluginIgnoreSubclassP
#elif defined(XP_MACOSX)
#include <ApplicationServices/ApplicationServices.h>
#include "nsCocoaFeatures.h"
#include "PluginUtilsOSX.h"
#endif // defined(XP_MACOSX)
@ -3534,10 +3533,8 @@ PluginInstanceChild::EnsureCurrentBuffer(void)
void *caLayer = nullptr;
if (mDrawingModel == NPDrawingModelCoreGraphics) {
if (!mCGLayer) {
bool avoidCGCrashes = !nsCocoaFeatures::OnMountainLionOrLater() &&
(GetQuirks() & QUIRK_FLASH_AVOID_CGMODE_CRASHES);
caLayer = mozilla::plugins::PluginUtilsOSX::GetCGLayer(CallCGDraw, this,
avoidCGCrashes,
caLayer = mozilla::plugins::PluginUtilsOSX::GetCGLayer(CallCGDraw,
this, false,
mContentsScaleFactor);
if (!caLayer) {

View File

@ -154,15 +154,6 @@ PluginModuleChild::PluginModuleChild(bool aIsChrome)
PluginModuleChild::~PluginModuleChild()
{
if (mTransport) {
// For some reason IPDL doesn't automatically delete the channel for a
// bridged protocol (bug 1090570). So we have to do it ourselves. This
// code is only invoked for PluginModuleChild instances created via
// bridging; otherwise mTransport is null.
RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTransport);
XRE_GetIOMessageLoop()->PostTask(task.forget());
}
if (mIsChrome) {
MOZ_ASSERT(gChromeInstance == this);

View File

@ -723,10 +723,6 @@ PluginModuleContentParent::PluginModuleContentParent(bool aAllowAsyncInit)
PluginModuleContentParent::~PluginModuleContentParent()
{
RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
XRE_GetIOMessageLoop()->PostTask(task.forget());
Preferences::UnregisterCallback(TimeoutChanged, kContentTimeoutPref, this);
}

View File

@ -36,10 +36,6 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT
[test_manyWindows.html]
skip-if = buildapp == 'b2g'
[test_mozsettings.html]
skip-if = buildapp == 'b2g' || toolkit == 'android'
[test_mozsettingsWatch.html]
skip-if = buildapp == 'b2g' || toolkit == 'android'
[test_optional_api_params.html]
skip-if = buildapp == 'b2g'
[test_shutdown.html]

View File

@ -1,92 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=478911
-->
<head>
<title>Test for getCurrentPosition </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="geolocation_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=777594">Mozilla Bug 777594</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");
var timeToWaitMs = 1000;
resume_geolocationProvider(function() {
force_prompt(true, test1);
});
SpecialPowers.importInMainProcess("resource://gre/modules/SettingsRequestManager.jsm");
function test1() {
//This pushPermissions call is after pushPrefEnv call and pushPrefEnv calls follow after this
SpecialPowers.pushPermissions([{'type': 'settings-read', 'allow': true, 'context': document},
{'type': 'settings-write', 'allow': true, 'context': document},
{'type': 'settings-api-write', 'allow': true, 'context': document},
{'type': 'settings-api-read', 'allow': true, 'context': document}
], test2);
}
function test2() {
ok(navigator.geolocation, "get geolocation object");
toggleGeolocationSetting(false, function() {
ok(true, "turned off geolocation via mozSettings");
setTimeout(function() {
navigator.geolocation.getCurrentPosition(successCallbackAfterMozsettingOff,
failureCallbackAfterMozsettingOff);
}, timeToWaitMs); // need to wait a bit for all of these async callbacks to finish
});
}
function successCallbackAfterMozsettingOff(position) {
ok(false, "Success callback should not have been called after setting geolocation.enabled to false.");
toggleGeolocationSetting(true, function() {
ok(true, "turned on geolocation via mozSettings");
setTimeout(function() {
navigator.geolocation.getCurrentPosition(successCallbackAfterMozsettingOn,
failureCallbackAfterMozsettingOn);
}, timeToWaitMs); // need to wait a bit for all of these async callbacks to finish
});
}
function failureCallbackAfterMozsettingOff(error) {
ok(true, "Geolocation didn't work after setting geolocation.enabled to false.");
toggleGeolocationSetting(true, function() {
ok(true, "turned on geolocation via mozSettings");
setTimeout(function() {
navigator.geolocation.getCurrentPosition(successCallbackAfterMozsettingOn,
failureCallbackAfterMozsettingOn);
}, timeToWaitMs); // need to wait a bit for all of these async callbacks to finish
});
}
function successCallbackAfterMozsettingOn(position) {
ok(true, "Geolocation worked after setting geolocation.enabled to true.");
SimpleTest.finish();
}
function failureCallbackAfterMozsettingOn(error) {
ok(false, "Geolocation didn't work after setting geolocation.enabled to true.");
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -1,97 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=478911
-->
<head>
<title>Test for getCurrentPosition </title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="geolocation_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=777594">Mozilla Bug 777594</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("untriaged");
resume_geolocationProvider(function() {
force_prompt(true, test1);
});
SpecialPowers.importInMainProcess("resource://gre/modules/SettingsRequestManager.jsm");
function test1() {
//This pushPermissions call is after pushPrefEnv call and pushPrefEnv calls follow after this
SpecialPowers.pushPermissions([{'type': 'settings-read', 'allow': true, 'context': document},
{'type': 'settings-write', 'allow': true, 'context': document},
{'type': 'settings-api-write', 'allow': true, 'context': document},
{'type': 'settings-api-read', 'allow': true, 'context': document}
], test2);
}
var watchId;
function test2() {
ok(navigator.geolocation, "get geolocation object");
toggleGeolocationSetting(false, function() {
ok(true, "turned off geolocation via mozSettings");
setTimeout(function() {
watchId = navigator.geolocation.watchPosition(successCallbackAfterMozsettingOff,
failureCallbackAfterMozsettingOff);
}, 500); // need to wait a bit for all of these async callbacks to finish
});
}
function successCallbackAfterMozsettingOff(position) {
ok(false, "Success callback should not have been called after setting geolocation.enabled to false.");
navigator.geolocation.clearWatch(watchId);
toggleGeolocationSetting(true, function() {
ok(true, "turned on geolocation via mozSettings");
setTimeout(function() {
watchId = navigator.geolocation.watchPosition(successCallbackAfterMozsettingOn,
failureCallbackAfterMozsettingOn);
}, 500); // need to wait a bit for all of these async callbacks to finish
});
}
function failureCallbackAfterMozsettingOff(error) {
ok(true, "Geolocation didn't work after setting geolocation.enabled to false.");
navigator.geolocation.clearWatch(watchId);
toggleGeolocationSetting(true, function() {
ok(true, "turned on geolocation via mozSettings");
setTimeout(function() {
watchId = navigator.geolocation.watchPosition(successCallbackAfterMozsettingOn,
failureCallbackAfterMozsettingOn);
}, 500); // need to wait a bit for all of these async callbacks to finish
});
}
function successCallbackAfterMozsettingOn(position) {
ok(true, "Geolocation worked after setting geolocation.enabled to true.");
navigator.geolocation.clearWatch(watchId);
SimpleTest.finish();
}
function failureCallbackAfterMozsettingOn(error) {
ok(false, "Geolocation didn't work after setting geolocation.enabled to true.");
navigator.geolocation.clearWatch(watchId);
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -25,6 +25,9 @@ interface WindowClient : Client {
[Throws, NewObject]
Promise<WindowClient> focus();
[Throws, NewObject]
Promise<WindowClient> navigate(USVString url);
};
enum FrameType {

Some files were not shown because too many files have changed in this diff Show More