mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 03:45:46 +00:00
Merge inbound to central, a=merge
MozReview-Commit-ID: JIAGB82GtAS
This commit is contained in:
commit
f20e8d0047
@ -226,7 +226,11 @@ pref("lightweightThemes.update.enabled", true);
|
||||
pref("lightweightThemes.getMoreURL", "https://addons.mozilla.org/%LOCALE%/firefox/themes");
|
||||
pref("lightweightThemes.recommendedThemes", "[{\"id\":\"recommended-1\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/a-web-browser-renaissance/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.header.jpg\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.footer.jpg\",\"textcolor\":\"#000000\",\"accentcolor\":\"#f2d9b1\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.preview.jpg\",\"author\":\"Sean.Martell\",\"version\":\"0\"},{\"id\":\"recommended-2\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/space-fantasy/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.header.jpg\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.footer.jpg\",\"textcolor\":\"#ffffff\",\"accentcolor\":\"#d9d9d9\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.preview.jpg\",\"author\":\"fx5800p\",\"version\":\"1.0\"},{\"id\":\"recommended-3\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/linen-light/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.footer.png\",\"accentcolor\":\"#ada8a8\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.icon.png\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.preview.png\",\"author\":\"DVemer\",\"version\":\"1.0\"},{\"id\":\"recommended-4\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/pastel-gradient/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.footer.png\",\"textcolor\":\"#000000\",\"accentcolor\":\"#000000\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.icon.png\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.preview.png\",\"author\":\"darrinhenein\",\"version\":\"1.0\"},{\"id\":\"recommended-5\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/carbon-light/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.footer.png\",\"textcolor\":\"#3b3b3b\",\"accentcolor\":\"#2e2e2e\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.preview.jpg\",\"author\":\"Jaxivo\",\"version\":\"1.0\"}]");
|
||||
|
||||
#if defined(MOZ_ADOBE_EME) || defined(MOZ_WIDEVINE_EME)
|
||||
pref("browser.eme.ui.enabled", true);
|
||||
#else
|
||||
pref("browser.eme.ui.enabled", false);
|
||||
#endif
|
||||
|
||||
// UI tour experience.
|
||||
pref("browser.uitour.enabled", true);
|
||||
@ -1378,10 +1382,6 @@ pref("media.gmp.decoder.h264", 2);
|
||||
// decode H.264.
|
||||
pref("media.gmp.trial-create.enabled", true);
|
||||
|
||||
#if defined(MOZ_ADOBE_EME) || defined(MOZ_WIDEVINE_EME)
|
||||
pref("browser.eme.ui.enabled", true);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_ADOBE_EME
|
||||
pref("media.gmp-eme-adobe.enabled", true);
|
||||
#endif
|
||||
|
@ -18,7 +18,7 @@
|
||||
let meNode, msNode, mdNode;
|
||||
navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia;
|
||||
|
||||
navigator.getUserMedia({ audio: true }, stream => {
|
||||
navigator.getUserMedia({ audio: true, fake: true }, stream => {
|
||||
meNode = ctx.createMediaElementSource(audio);
|
||||
msNode = ctx.createMediaStreamSource(stream);
|
||||
mdNode = ctx.createMediaStreamDestination();
|
||||
|
@ -13232,7 +13232,7 @@ nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer* aContentViewer)
|
||||
if (baseURI) {
|
||||
nsIDocument* document = aContentViewer->GetDocument();
|
||||
if (document) {
|
||||
rv = document->SetBaseURI(baseURI);
|
||||
document->SetBaseURI(baseURI);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
|
@ -3574,11 +3574,11 @@ nsIDocument::GetBaseURI(bool aTryUseXHRDocBaseURI) const
|
||||
return uri.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
void
|
||||
nsDocument::SetBaseURI(nsIURI* aURI)
|
||||
{
|
||||
if (!aURI && !mDocumentBaseURI) {
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't do anything if the URI wasn't actually changed.
|
||||
@ -3586,25 +3586,7 @@ nsDocument::SetBaseURI(nsIURI* aURI)
|
||||
bool equalBases = false;
|
||||
mDocumentBaseURI->Equals(aURI, &equalBases);
|
||||
if (equalBases) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if CSP allows this base-uri
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
nsresult rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (csp && aURI) {
|
||||
bool permitsBaseURI = false;
|
||||
|
||||
// base-uri is only enforced if explicitly defined in the
|
||||
// policy - do *not* consult default-src, see:
|
||||
// http://www.w3.org/TR/CSP2/#directive-default-src
|
||||
rv = csp->Permits(aURI, nsIContentSecurityPolicy::BASE_URI_DIRECTIVE,
|
||||
true, &permitsBaseURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!permitsBaseURI) {
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3614,8 +3596,6 @@ nsDocument::SetBaseURI(nsIURI* aURI)
|
||||
mDocumentBaseURI = nullptr;
|
||||
}
|
||||
RefreshLinkHrefs();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -735,7 +735,7 @@ public:
|
||||
*/
|
||||
virtual void SetContentType(const nsAString& aContentType) override;
|
||||
|
||||
virtual nsresult SetBaseURI(nsIURI* aURI) override;
|
||||
virtual void SetBaseURI(nsIURI* aURI) override;
|
||||
|
||||
/**
|
||||
* Get/Set the base target of a link in a document.
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "nsBindingManager.h"
|
||||
#include "nsCCUncollectableMarker.h"
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "nsTextNode.h"
|
||||
|
||||
#include "PLDHashTable.h"
|
||||
#include "mozilla/Snprintf.h"
|
||||
|
@ -9356,7 +9356,7 @@ nsGlobalWindow::AddEventListener(const nsAString& aType,
|
||||
void
|
||||
nsGlobalWindow::AddEventListener(const nsAString& aType,
|
||||
EventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const AddEventListenerOptionsOrBoolean& aOptions,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
@ -9378,7 +9378,8 @@ nsGlobalWindow::AddEventListener(const nsAString& aType,
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
manager->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
|
||||
|
||||
manager->AddEventListener(aType, aListener, aOptions, wantsUntrusted);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -402,7 +402,7 @@ public:
|
||||
using mozilla::dom::EventTarget::RemoveEventListener;
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
mozilla::dom::EventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const mozilla::dom::AddEventListenerOptionsOrBoolean& aOptions,
|
||||
const mozilla::dom::Nullable<bool>& aWantsUntrusted,
|
||||
mozilla::ErrorResult& aRv) override;
|
||||
virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindings() override;
|
||||
|
@ -388,7 +388,7 @@ public:
|
||||
}
|
||||
virtual already_AddRefed<nsIURI> GetBaseURI(bool aTryUseXHRDocBaseURI = false) const override;
|
||||
|
||||
virtual nsresult SetBaseURI(nsIURI* aURI) = 0;
|
||||
virtual void SetBaseURI(nsIURI* aURI) = 0;
|
||||
|
||||
/**
|
||||
* Get/Set the base target of a link in a document.
|
||||
|
@ -1178,7 +1178,7 @@ nsINode::AddEventListener(const nsAString& aType,
|
||||
void
|
||||
nsINode::AddEventListener(const nsAString& aType,
|
||||
EventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const AddEventListenerOptionsOrBoolean& aOptions,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
@ -1194,7 +1194,8 @@ nsINode::AddEventListener(const nsAString& aType,
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
listener_manager->AddEventListener(aType, aListener, aUseCapture,
|
||||
|
||||
listener_manager->AddEventListener(aType, aListener, aOptions,
|
||||
wantsUntrusted);
|
||||
}
|
||||
|
||||
|
@ -938,7 +938,7 @@ public:
|
||||
using nsIDOMEventTarget::AddEventListener;
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
mozilla::dom::EventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const mozilla::dom::AddEventListenerOptionsOrBoolean& aOptions,
|
||||
const mozilla::dom::Nullable<bool>& aWantsUntrusted,
|
||||
mozilla::ErrorResult& aRv) override;
|
||||
using nsIDOMEventTarget::AddSystemEventListener;
|
||||
|
@ -117,7 +117,7 @@ nsWindowRoot::AddEventListener(const nsAString& aType,
|
||||
void
|
||||
nsWindowRoot::AddEventListener(const nsAString& aType,
|
||||
EventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const AddEventListenerOptionsOrBoolean& aOptions,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
@ -127,7 +127,7 @@ nsWindowRoot::AddEventListener(const nsAString& aType,
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
elm->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
|
||||
elm->AddEventListener(aType, aListener, aOptions, wantsUntrusted);
|
||||
}
|
||||
|
||||
|
||||
@ -287,7 +287,7 @@ nsWindowRoot::GetControllerForCommand(const char * aCommand,
|
||||
nsGlobalWindow *win = nsGlobalWindow::Cast(focusedWindow);
|
||||
focusedWindow = win->GetPrivateParent();
|
||||
}
|
||||
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
using mozilla::dom::EventTarget::RemoveEventListener;
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
mozilla::dom::EventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const mozilla::dom::AddEventListenerOptionsOrBoolean& aOptions,
|
||||
const mozilla::dom::Nullable<bool>& aWantsUntrusted,
|
||||
mozilla::ErrorResult& aRv) override;
|
||||
|
||||
|
@ -593,11 +593,11 @@ BroadcastChannel::SetOnmessage(EventHandlerNonNull* aCallback)
|
||||
void
|
||||
BroadcastChannel::AddEventListener(const nsAString& aType,
|
||||
EventListener* aCallback,
|
||||
bool aCapture,
|
||||
const AddEventListenerOptionsOrBoolean& aOptions,
|
||||
const dom::Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
DOMEventTargetHelper::AddEventListener(aType, aCallback, aCapture,
|
||||
DOMEventTargetHelper::AddEventListener(aType, aCallback, aOptions,
|
||||
aWantsUntrusted, aRv);
|
||||
|
||||
if (aRv.Failed()) {
|
||||
@ -610,10 +610,10 @@ BroadcastChannel::AddEventListener(const nsAString& aType,
|
||||
void
|
||||
BroadcastChannel::RemoveEventListener(const nsAString& aType,
|
||||
EventListener* aCallback,
|
||||
bool aCapture,
|
||||
const EventListenerOptionsOrBoolean& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
DOMEventTargetHelper::RemoveEventListener(aType, aCallback, aCapture, aRv);
|
||||
DOMEventTargetHelper::RemoveEventListener(aType, aCallback, aOptions, aRv);
|
||||
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
|
@ -74,12 +74,12 @@ public:
|
||||
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
EventListener* aCallback,
|
||||
bool aCapture,
|
||||
const AddEventListenerOptionsOrBoolean& aOptions,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv) override;
|
||||
virtual void RemoveEventListener(const nsAString& aType,
|
||||
EventListener* aCallback,
|
||||
bool aCapture,
|
||||
const EventListenerOptionsOrBoolean& aOptions,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
void Shutdown();
|
||||
|
@ -1616,18 +1616,16 @@ CanvasRenderingContext2D::ReturnTarget()
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CanvasRenderingContext2D::InitializeWithSurface(nsIDocShell* aShell,
|
||||
gfxASurface* aSurface,
|
||||
int32_t aWidth,
|
||||
int32_t aHeight)
|
||||
CanvasRenderingContext2D::InitializeWithDrawTarget(nsIDocShell* aShell,
|
||||
gfx::DrawTarget* aTarget)
|
||||
{
|
||||
RemovePostRefreshObserver();
|
||||
mDocShell = aShell;
|
||||
AddPostRefreshObserverIfNecessary();
|
||||
|
||||
SetDimensions(aWidth, aHeight);
|
||||
mTarget = gfxPlatform::GetPlatform()->
|
||||
CreateDrawTargetForSurface(aSurface, IntSize(aWidth, aHeight));
|
||||
IntSize size = aTarget->GetSize();
|
||||
SetDimensions(size.width, size.height);
|
||||
mTarget = aTarget;
|
||||
|
||||
if (!mTarget) {
|
||||
EnsureErrorTarget();
|
||||
|
@ -443,7 +443,8 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
NS_IMETHOD SetDimensions(int32_t aWidth, int32_t aHeight) override;
|
||||
NS_IMETHOD InitializeWithSurface(nsIDocShell* aShell, gfxASurface* aSurface, int32_t aWidth, int32_t aHeight) override;
|
||||
NS_IMETHOD InitializeWithDrawTarget(nsIDocShell* aShell,
|
||||
gfx::DrawTarget* aTarget) override;
|
||||
|
||||
NS_IMETHOD GetInputStream(const char* aMimeType,
|
||||
const char16_t* aEncoderOptions,
|
||||
|
@ -82,10 +82,8 @@ ImageBitmapRenderingContext::SetDimensions(int32_t aWidth, int32_t aHeight)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImageBitmapRenderingContext::InitializeWithSurface(nsIDocShell* aDocShell,
|
||||
gfxASurface* aSurface,
|
||||
int32_t aWidth,
|
||||
int32_t aHeight)
|
||||
ImageBitmapRenderingContext::InitializeWithDrawTarget(nsIDocShell* aDocShell,
|
||||
gfx::DrawTarget* aTarget)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ namespace mozilla {
|
||||
|
||||
namespace gfx {
|
||||
class DataSourceSurface;
|
||||
class DrawTarget;
|
||||
class SourceSurface;
|
||||
}
|
||||
|
||||
@ -53,10 +54,8 @@ public:
|
||||
|
||||
NS_IMETHOD SetDimensions(int32_t aWidth, int32_t aHeight) override;
|
||||
|
||||
NS_IMETHOD InitializeWithSurface(nsIDocShell* aDocShell,
|
||||
gfxASurface* aSurface,
|
||||
int32_t aWidth,
|
||||
int32_t aHeight) override;
|
||||
NS_IMETHOD InitializeWithDrawTarget(nsIDocShell* aDocShell,
|
||||
gfx::DrawTarget* aTarget) override;
|
||||
|
||||
virtual mozilla::UniquePtr<uint8_t[]> GetImageBuffer(int32_t* aFormat) override;
|
||||
NS_IMETHOD GetInputStream(const char* aMimeType,
|
||||
|
@ -240,8 +240,7 @@ public:
|
||||
virtual int32_t GetHeight() const override;
|
||||
|
||||
NS_IMETHOD SetDimensions(int32_t width, int32_t height) override;
|
||||
NS_IMETHOD InitializeWithSurface(nsIDocShell*, gfxASurface*, int32_t,
|
||||
int32_t) override
|
||||
NS_IMETHOD InitializeWithDrawTarget(nsIDocShell*, gfx::DrawTarget*) override
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -96,7 +96,10 @@ public:
|
||||
// whenever the size of the element changes.
|
||||
NS_IMETHOD SetDimensions(int32_t width, int32_t height) = 0;
|
||||
|
||||
NS_IMETHOD InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, int32_t width, int32_t height) = 0;
|
||||
// Initializes with an nsIDocShell and DrawTarget. The size is taken from the
|
||||
// DrawTarget.
|
||||
NS_IMETHOD InitializeWithDrawTarget(nsIDocShell *aDocShell,
|
||||
mozilla::gfx::DrawTarget* aTarget) = 0;
|
||||
|
||||
// Creates an image buffer. Returns null on failure.
|
||||
virtual mozilla::UniquePtr<uint8_t[]> GetImageBuffer(int32_t* format) = 0;
|
||||
|
@ -222,7 +222,7 @@ DOMEventTargetHelper::AddEventListener(const nsAString& aType,
|
||||
void
|
||||
DOMEventTargetHelper::AddEventListener(const nsAString& aType,
|
||||
EventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const AddEventListenerOptionsOrBoolean& aOptions,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
@ -242,7 +242,8 @@ DOMEventTargetHelper::AddEventListener(const nsAString& aType,
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
elm->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
|
||||
|
||||
elm->AddEventListener(aType, aListener, aOptions, wantsUntrusted);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -72,7 +72,7 @@ public:
|
||||
using dom::EventTarget::RemoveEventListener;
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
dom::EventListener* aListener,
|
||||
bool aCapture,
|
||||
const dom::AddEventListenerOptionsOrBoolean& aOptions,
|
||||
const dom::Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/EventTargetBinding.h"
|
||||
#include "mozilla/TimelineConsumers.h"
|
||||
#include "mozilla/EventTimelineMarker.h"
|
||||
|
||||
@ -1332,6 +1333,21 @@ EventListenerManager::AddEventListener(
|
||||
return AddEventListenerByType(aListenerHolder, aType, flags);
|
||||
}
|
||||
|
||||
void
|
||||
EventListenerManager::AddEventListener(
|
||||
const nsAString& aType,
|
||||
const EventListenerHolder& aListenerHolder,
|
||||
const dom::AddEventListenerOptionsOrBoolean& aOptions,
|
||||
bool aWantsUntrusted)
|
||||
{
|
||||
EventListenerFlags flags;
|
||||
flags.mCapture =
|
||||
aOptions.IsBoolean() ? aOptions.GetAsBoolean()
|
||||
: aOptions.GetAsAddEventListenerOptions().mCapture;
|
||||
flags.mAllowUntrustedEvents = aWantsUntrusted;
|
||||
return AddEventListenerByType(aListenerHolder, aType, flags);
|
||||
}
|
||||
|
||||
void
|
||||
EventListenerManager::RemoveEventListener(
|
||||
const nsAString& aType,
|
||||
@ -1343,6 +1359,19 @@ EventListenerManager::RemoveEventListener(
|
||||
RemoveEventListenerByType(aListenerHolder, aType, flags);
|
||||
}
|
||||
|
||||
void
|
||||
EventListenerManager::RemoveEventListener(
|
||||
const nsAString& aType,
|
||||
const EventListenerHolder& aListenerHolder,
|
||||
const dom::EventListenerOptionsOrBoolean& aOptions)
|
||||
{
|
||||
EventListenerFlags flags;
|
||||
flags.mCapture =
|
||||
aOptions.IsBoolean() ? aOptions.GetAsBoolean()
|
||||
: aOptions.GetAsEventListenerOptions().mCapture;
|
||||
RemoveEventListenerByType(aListenerHolder, aType, flags);
|
||||
}
|
||||
|
||||
void
|
||||
EventListenerManager::AddListenerForAllEvents(nsIDOMEventListener* aDOMListener,
|
||||
bool aUseCapture,
|
||||
|
@ -248,11 +248,11 @@ public:
|
||||
}
|
||||
void AddEventListener(const nsAString& aType,
|
||||
dom::EventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const dom::AddEventListenerOptionsOrBoolean& aOptions,
|
||||
bool aWantsUntrusted)
|
||||
{
|
||||
EventListenerHolder holder(aListener);
|
||||
AddEventListener(aType, holder, aUseCapture, aWantsUntrusted);
|
||||
AddEventListener(aType, holder, aOptions, aWantsUntrusted);
|
||||
}
|
||||
void RemoveEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
@ -263,10 +263,10 @@ public:
|
||||
}
|
||||
void RemoveEventListener(const nsAString& aType,
|
||||
dom::EventListener* aListener,
|
||||
bool aUseCapture)
|
||||
const dom::EventListenerOptionsOrBoolean& aOptions)
|
||||
{
|
||||
EventListenerHolder holder(aListener);
|
||||
RemoveEventListener(aType, holder, aUseCapture);
|
||||
RemoveEventListener(aType, holder, aOptions);
|
||||
}
|
||||
|
||||
void AddListenerForAllEvents(nsIDOMEventListener* aListener,
|
||||
@ -553,10 +553,17 @@ protected:
|
||||
const TypedEventHandler* GetTypedEventHandler(nsIAtom* aEventName,
|
||||
const nsAString& aTypeString);
|
||||
|
||||
void AddEventListener(const nsAString& aType,
|
||||
const EventListenerHolder& aListener,
|
||||
const dom::AddEventListenerOptionsOrBoolean& aOptions,
|
||||
bool aWantsUntrusted);
|
||||
void AddEventListener(const nsAString& aType,
|
||||
const EventListenerHolder& aListener,
|
||||
bool aUseCapture,
|
||||
bool aWantsUntrusted);
|
||||
void RemoveEventListener(const nsAString& aType,
|
||||
const EventListenerHolder& aListener,
|
||||
const dom::EventListenerOptionsOrBoolean& aOptions);
|
||||
void RemoveEventListener(const nsAString& aType,
|
||||
const EventListenerHolder& aListener,
|
||||
bool aUseCapture);
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "mozilla/EventListenerManager.h"
|
||||
#include "mozilla/dom/EventTarget.h"
|
||||
#include "mozilla/dom/EventTargetBinding.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -14,12 +15,12 @@ namespace dom {
|
||||
void
|
||||
EventTarget::RemoveEventListener(const nsAString& aType,
|
||||
EventListener* aListener,
|
||||
bool aUseCapture,
|
||||
const EventListenerOptionsOrBoolean& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
EventListenerManager* elm = GetExistingListenerManager();
|
||||
if (elm) {
|
||||
elm->RemoveEventListener(aType, aListener, aUseCapture);
|
||||
elm->RemoveEventListener(aType, aListener, aOptions);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,9 +21,12 @@ class EventListenerManager;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class AddEventListenerOptionsOrBoolean;
|
||||
class Event;
|
||||
class EventListener;
|
||||
class EventListenerOptionsOrBoolean;
|
||||
class EventHandlerNonNull;
|
||||
|
||||
template <class T> struct Nullable;
|
||||
|
||||
// IID for the dom::EventTarget interface
|
||||
@ -43,12 +46,12 @@ public:
|
||||
using nsIDOMEventTarget::DispatchEvent;
|
||||
virtual void AddEventListener(const nsAString& aType,
|
||||
EventListener* aCallback,
|
||||
bool aCapture,
|
||||
const AddEventListenerOptionsOrBoolean& aOptions,
|
||||
const Nullable<bool>& aWantsUntrusted,
|
||||
ErrorResult& aRv) = 0;
|
||||
virtual void RemoveEventListener(const nsAString& aType,
|
||||
EventListener* aCallback,
|
||||
bool aCapture,
|
||||
const EventListenerOptionsOrBoolean& aOptions,
|
||||
ErrorResult& aRv);
|
||||
bool DispatchEvent(JSContext* aCx, Event& aEvent, ErrorResult& aRv);
|
||||
|
||||
|
@ -2039,7 +2039,7 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
|
||||
|
||||
OutputMediaStream* out = mOutputStreams.AppendElement();
|
||||
MediaStreamTrackSourceGetter* getter = new CaptureStreamTrackSourceGetter(this);
|
||||
out->mStream = DOMMediaStream::CreateTrackUnionStream(window, aGraph, getter);
|
||||
out->mStream = DOMMediaStream::CreateTrackUnionStreamAsInput(window, aGraph, getter);
|
||||
out->mFinishWhenEnded = aFinishWhenEnded;
|
||||
|
||||
mAudioCaptured = true;
|
||||
@ -3933,16 +3933,16 @@ HTMLMediaElement::UpdateReadyStateInternal()
|
||||
}
|
||||
|
||||
if (mSrcStream && mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
|
||||
bool hasAudio = !AudioTracks()->IsEmpty();
|
||||
bool hasVideo = !VideoTracks()->IsEmpty();
|
||||
bool hasAudioTracks = !AudioTracks()->IsEmpty();
|
||||
bool hasVideoTracks = !VideoTracks()->IsEmpty();
|
||||
|
||||
if (!hasAudio && !hasVideo) {
|
||||
if (!hasAudioTracks && !hasVideoTracks) {
|
||||
LOG(LogLevel::Debug, ("MediaElement %p UpdateReadyStateInternal() "
|
||||
"Stream with no tracks", this));
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsVideo() && hasVideo && !HasVideo()) {
|
||||
if (IsVideo() && hasVideoTracks && !HasVideo()) {
|
||||
LOG(LogLevel::Debug, ("MediaElement %p UpdateReadyStateInternal() "
|
||||
"Stream waiting for video", this));
|
||||
return;
|
||||
@ -3956,10 +3956,10 @@ HTMLMediaElement::UpdateReadyStateInternal()
|
||||
// We are playing a stream that has video and a video frame is now set.
|
||||
// This means we have all metadata needed to change ready state.
|
||||
MediaInfo mediaInfo = mMediaInfo;
|
||||
if (hasAudio) {
|
||||
if (hasAudioTracks) {
|
||||
mediaInfo.EnableAudio();
|
||||
}
|
||||
if (hasVideo) {
|
||||
if (hasVideoTracks) {
|
||||
mediaInfo.EnableVideo();
|
||||
}
|
||||
MetadataLoaded(&mediaInfo, nsAutoPtr<const MetadataTags>(nullptr));
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "nsRuleData.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
NS_IMPL_NS_NEW_HTML_ELEMENT(Shared)
|
||||
@ -176,12 +177,28 @@ SetBaseURIUsingFirstBaseWithHref(nsIDocument* aDocument, nsIContent* aMustMatch)
|
||||
getter_AddRefs(newBaseURI), href, aDocument,
|
||||
aDocument->GetFallbackBaseURI());
|
||||
|
||||
// Try to set our base URI. If that fails, try to set base URI to null
|
||||
nsresult rv = aDocument->SetBaseURI(newBaseURI);
|
||||
aDocument->SetChromeXHRDocBaseURI(nullptr);
|
||||
// Check if CSP allows this base-uri
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
nsresult rv = aDocument->NodePrincipal()->GetCsp(getter_AddRefs(csp));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Getting CSP Failed");
|
||||
// For all the different error cases we assign a nullptr to
|
||||
// newBaseURI, so we basically call aDocument->SetBaseURI(nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
aDocument->SetBaseURI(nullptr);
|
||||
newBaseURI = nullptr;
|
||||
}
|
||||
if (csp && newBaseURI) {
|
||||
// base-uri is only enforced if explicitly defined in the
|
||||
// policy - do *not* consult default-src, see:
|
||||
// http://www.w3.org/TR/CSP2/#directive-default-src
|
||||
bool cspPermitsBaseURI = true;
|
||||
rv = csp->Permits(newBaseURI, nsIContentSecurityPolicy::BASE_URI_DIRECTIVE,
|
||||
true, &cspPermitsBaseURI);
|
||||
if (NS_FAILED(rv) || !cspPermitsBaseURI) {
|
||||
newBaseURI = nullptr;
|
||||
}
|
||||
}
|
||||
aDocument->SetBaseURI(newBaseURI);
|
||||
aDocument->SetChromeXHRDocBaseURI(nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ InputPort::Init(nsIInputPortData* aData, nsIInputPortListener* aListener, ErrorR
|
||||
MediaStreamGraph* graph =
|
||||
MediaStreamGraph::GetInstance(MediaStreamGraph::SYSTEM_THREAD_DRIVER,
|
||||
AudioChannel::Normal);
|
||||
mStream = DOMMediaStream::CreateSourceStream(GetOwner(), graph);
|
||||
mStream = DOMMediaStream::CreateSourceStreamAsInput(GetOwner(), graph);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -71,7 +71,7 @@ AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo,
|
||||
}
|
||||
|
||||
uint32_t inputCount = mInputs.Length();
|
||||
StreamBuffer::Track* track = EnsureTrack(mTrackId);
|
||||
StreamTracks::Track* track = EnsureTrack(mTrackId);
|
||||
// Notify the DOM everything is in order.
|
||||
if (!mTrackCreated) {
|
||||
for (uint32_t i = 0; i < mListeners.Length(); i++) {
|
||||
@ -101,7 +101,7 @@ AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo,
|
||||
AudioSegment output;
|
||||
for (uint32_t i = 0; i < inputCount; i++) {
|
||||
MediaStream* s = mInputs[i]->GetSource();
|
||||
StreamBuffer::TrackIter tracks(s->GetStreamBuffer(), MediaSegment::AUDIO);
|
||||
StreamTracks::TrackIter tracks(s->GetStreamTracks(), MediaSegment::AUDIO);
|
||||
while (!tracks.IsEnded()) {
|
||||
AudioSegment* inputSegment = tracks->Get<AudioSegment>();
|
||||
StreamTime inputStart = s->GraphTimeToStreamTimeWithBlocking(aFrom);
|
||||
@ -121,7 +121,7 @@ AudioCaptureStream::ProcessInput(GraphTime aFrom, GraphTime aTo,
|
||||
}
|
||||
|
||||
// Regardless of the status of the input tracks, we go foward.
|
||||
mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTimeWithBlocking((aTo)));
|
||||
mTracks.AdvanceKnownTracksTime(GraphTimeToStreamTimeWithBlocking((aTo)));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "AudioMixer.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "StreamTracks.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include "DOMMediaStream.h"
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "StreamTracks.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
|
||||
|
@ -71,9 +71,8 @@ DOMMediaStream::TrackPort::~TrackPort()
|
||||
{
|
||||
MOZ_COUNT_DTOR(TrackPort);
|
||||
|
||||
if (mOwnership == InputPortOwnership::OWNED && mInputPort) {
|
||||
mInputPort->Destroy();
|
||||
mInputPort = nullptr;
|
||||
if (mOwnership == InputPortOwnership::OWNED) {
|
||||
DestroyInputPort();
|
||||
}
|
||||
}
|
||||
|
||||
@ -853,9 +852,9 @@ DOMMediaStream::InitPlaybackStreamCommon(MediaStreamGraph* aGraph)
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMediaStream>
|
||||
DOMMediaStream::CreateSourceStream(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter)
|
||||
DOMMediaStream::CreateSourceStreamAsInput(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter)
|
||||
{
|
||||
RefPtr<DOMMediaStream> stream = new DOMMediaStream(aWindow, aTrackSourceGetter);
|
||||
stream->InitSourceStream(aGraph);
|
||||
@ -863,9 +862,9 @@ DOMMediaStream::CreateSourceStream(nsPIDOMWindowInner* aWindow,
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMediaStream>
|
||||
DOMMediaStream::CreateTrackUnionStream(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter)
|
||||
DOMMediaStream::CreateTrackUnionStreamAsInput(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter)
|
||||
{
|
||||
RefPtr<DOMMediaStream> stream = new DOMMediaStream(aWindow, aTrackSourceGetter);
|
||||
stream->InitTrackUnionStream(aGraph);
|
||||
@ -873,9 +872,9 @@ DOMMediaStream::CreateTrackUnionStream(nsPIDOMWindowInner* aWindow,
|
||||
}
|
||||
|
||||
already_AddRefed<DOMMediaStream>
|
||||
DOMMediaStream::CreateAudioCaptureStream(nsPIDOMWindowInner* aWindow,
|
||||
nsIPrincipal* aPrincipal,
|
||||
MediaStreamGraph* aGraph)
|
||||
DOMMediaStream::CreateAudioCaptureStreamAsInput(nsPIDOMWindowInner* aWindow,
|
||||
nsIPrincipal* aPrincipal,
|
||||
MediaStreamGraph* aGraph)
|
||||
{
|
||||
// Audio capture doesn't create tracks dynamically
|
||||
MediaStreamTrackSourceGetter* getter = nullptr;
|
||||
@ -1300,9 +1299,9 @@ DOMLocalMediaStream::StopImpl()
|
||||
}
|
||||
|
||||
already_AddRefed<DOMLocalMediaStream>
|
||||
DOMLocalMediaStream::CreateSourceStream(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter)
|
||||
DOMLocalMediaStream::CreateSourceStreamAsInput(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter)
|
||||
{
|
||||
RefPtr<DOMLocalMediaStream> stream =
|
||||
new DOMLocalMediaStream(aWindow, aTrackSourceGetter);
|
||||
@ -1311,9 +1310,9 @@ DOMLocalMediaStream::CreateSourceStream(nsPIDOMWindowInner* aWindow,
|
||||
}
|
||||
|
||||
already_AddRefed<DOMLocalMediaStream>
|
||||
DOMLocalMediaStream::CreateTrackUnionStream(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter)
|
||||
DOMLocalMediaStream::CreateTrackUnionStreamAsInput(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter)
|
||||
{
|
||||
RefPtr<DOMLocalMediaStream> stream =
|
||||
new DOMLocalMediaStream(aWindow, aTrackSourceGetter);
|
||||
@ -1332,9 +1331,9 @@ DOMAudioNodeMediaStream::~DOMAudioNodeMediaStream()
|
||||
}
|
||||
|
||||
already_AddRefed<DOMAudioNodeMediaStream>
|
||||
DOMAudioNodeMediaStream::CreateTrackUnionStream(nsPIDOMWindowInner* aWindow,
|
||||
AudioNode* aNode,
|
||||
MediaStreamGraph* aGraph)
|
||||
DOMAudioNodeMediaStream::CreateTrackUnionStreamAsInput(nsPIDOMWindowInner* aWindow,
|
||||
AudioNode* aNode,
|
||||
MediaStreamGraph* aGraph)
|
||||
{
|
||||
RefPtr<DOMAudioNodeMediaStream> stream = new DOMAudioNodeMediaStream(aWindow, aNode);
|
||||
stream->InitTrackUnionStream(aGraph);
|
||||
@ -1443,7 +1442,7 @@ DOMHwMediaStream::SetImageSize(uint32_t width, uint32_t height)
|
||||
#endif
|
||||
|
||||
SourceMediaStream* srcStream = GetInputStream()->AsSourceStream();
|
||||
StreamBuffer::Track* track = srcStream->FindTrack(TRACK_VIDEO_PRIMARY);
|
||||
StreamTracks::Track* track = srcStream->FindTrack(TRACK_VIDEO_PRIMARY);
|
||||
|
||||
if (!track || !track->GetSegment()) {
|
||||
return;
|
||||
@ -1479,7 +1478,7 @@ DOMHwMediaStream::SetOverlayImage(OverlayImage* aImage)
|
||||
#endif
|
||||
|
||||
SourceMediaStream* srcStream = GetInputStream()->AsSourceStream();
|
||||
StreamBuffer::Track* track = srcStream->FindTrack(TRACK_VIDEO_PRIMARY);
|
||||
StreamTracks::Track* track = srcStream->FindTrack(TRACK_VIDEO_PRIMARY);
|
||||
|
||||
if (!track || !track->GetSegment()) {
|
||||
return;
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "StreamTracks.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
@ -484,25 +484,25 @@ public:
|
||||
/**
|
||||
* Create a DOMMediaStream whose underlying input stream is a SourceMediaStream.
|
||||
*/
|
||||
static already_AddRefed<DOMMediaStream> CreateSourceStream(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
|
||||
static already_AddRefed<DOMMediaStream> CreateSourceStreamAsInput(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
|
||||
|
||||
/**
|
||||
* Create a DOMMediaStream whose underlying input stream is a TrackUnionStream.
|
||||
*/
|
||||
static already_AddRefed<DOMMediaStream> CreateTrackUnionStream(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
|
||||
static already_AddRefed<DOMMediaStream> CreateTrackUnionStreamAsInput(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
|
||||
|
||||
/**
|
||||
* Create an DOMMediaStream whose underlying input stream is an
|
||||
* AudioCaptureStream.
|
||||
*/
|
||||
static already_AddRefed<DOMMediaStream>
|
||||
CreateAudioCaptureStream(nsPIDOMWindowInner* aWindow,
|
||||
nsIPrincipal* aPrincipal,
|
||||
MediaStreamGraph* aGraph);
|
||||
CreateAudioCaptureStreamAsInput(nsPIDOMWindowInner* aWindow,
|
||||
nsIPrincipal* aPrincipal,
|
||||
MediaStreamGraph* aGraph);
|
||||
|
||||
void SetLogicalStreamStartTime(StreamTime aTime)
|
||||
{
|
||||
@ -719,17 +719,17 @@ public:
|
||||
* Create an nsDOMLocalMediaStream whose underlying stream is a SourceMediaStream.
|
||||
*/
|
||||
static already_AddRefed<DOMLocalMediaStream>
|
||||
CreateSourceStream(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
|
||||
CreateSourceStreamAsInput(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
|
||||
|
||||
/**
|
||||
* Create an nsDOMLocalMediaStream whose underlying stream is a TrackUnionStream.
|
||||
*/
|
||||
static already_AddRefed<DOMLocalMediaStream>
|
||||
CreateTrackUnionStream(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
|
||||
CreateTrackUnionStreamAsInput(nsPIDOMWindowInner* aWindow,
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
|
||||
|
||||
protected:
|
||||
virtual ~DOMLocalMediaStream();
|
||||
@ -753,9 +753,9 @@ public:
|
||||
* Create a DOMAudioNodeMediaStream whose underlying stream is a TrackUnionStream.
|
||||
*/
|
||||
static already_AddRefed<DOMAudioNodeMediaStream>
|
||||
CreateTrackUnionStream(nsPIDOMWindowInner* aWindow,
|
||||
AudioNode* aNode,
|
||||
MediaStreamGraph* aGraph);
|
||||
CreateTrackUnionStreamAsInput(nsPIDOMWindowInner* aWindow,
|
||||
AudioNode* aNode,
|
||||
MediaStreamGraph* aGraph);
|
||||
|
||||
protected:
|
||||
~DOMAudioNodeMediaStream();
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "nsTArray.h"
|
||||
#include "ImageTypes.h"
|
||||
#include "MediaData.h"
|
||||
#include "StreamBuffer.h" // for TrackID
|
||||
#include "StreamTracks.h" // for TrackID
|
||||
#include "TimeUnits.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -833,7 +833,7 @@ public:
|
||||
// not a problem here, we got explicit user content.
|
||||
nsCOMPtr<nsIPrincipal> principal = window->GetExtantDoc()->NodePrincipal();
|
||||
domStream =
|
||||
DOMMediaStream::CreateAudioCaptureStream(window, principal, msg);
|
||||
DOMMediaStream::CreateAudioCaptureStreamAsInput(window, principal, msg);
|
||||
|
||||
stream = msg->CreateSourceStream(nullptr); // Placeholder
|
||||
msg->RegisterCaptureStreamForWindow(
|
||||
@ -919,8 +919,8 @@ public:
|
||||
// avoid us blocking. Pass a simple TrackSourceGetter for potential
|
||||
// fake tracks. Apart from them gUM never adds tracks dynamically.
|
||||
domStream =
|
||||
DOMLocalMediaStream::CreateSourceStream(window, msg,
|
||||
new FakeTrackSourceGetter(principal));
|
||||
DOMLocalMediaStream::CreateSourceStreamAsInput(window, msg,
|
||||
new FakeTrackSourceGetter(principal));
|
||||
|
||||
if (mAudioDevice) {
|
||||
nsString audioDeviceName;
|
||||
|
@ -45,7 +45,7 @@ typedef int64_t MediaTime;
|
||||
const int64_t MEDIA_TIME_MAX = TRACK_TICKS_MAX;
|
||||
|
||||
/**
|
||||
* Media time relative to the start of a StreamBuffer.
|
||||
* Media time relative to the start of a StreamTracks.
|
||||
*/
|
||||
typedef MediaTime StreamTime;
|
||||
const StreamTime STREAM_TIME_MAX = MEDIA_TIME_MAX;
|
||||
|
@ -81,7 +81,7 @@ MediaStreamGraphImpl::FinishStream(MediaStream* aStream)
|
||||
return;
|
||||
STREAM_LOG(LogLevel::Debug, ("MediaStream %p will finish", aStream));
|
||||
#ifdef DEBUG
|
||||
for (StreamBuffer::TrackIter track(aStream->mBuffer);
|
||||
for (StreamTracks::TrackIter track(aStream->mTracks);
|
||||
!track.IsEnded(); track.Next()) {
|
||||
if (!track->IsEnded()) {
|
||||
STREAM_LOG(LogLevel::Error,
|
||||
@ -92,7 +92,7 @@ MediaStreamGraphImpl::FinishStream(MediaStream* aStream)
|
||||
}
|
||||
#endif
|
||||
aStream->mFinished = true;
|
||||
aStream->mBuffer.AdvanceKnownTracksTime(STREAM_TIME_MAX);
|
||||
aStream->mTracks.AdvanceKnownTracksTime(STREAM_TIME_MAX);
|
||||
|
||||
SetStreamOrderDirty();
|
||||
}
|
||||
@ -100,7 +100,7 @@ MediaStreamGraphImpl::FinishStream(MediaStream* aStream)
|
||||
void
|
||||
MediaStreamGraphImpl::AddStreamGraphThread(MediaStream* aStream)
|
||||
{
|
||||
aStream->mBufferStartTime = mProcessedTime;
|
||||
aStream->mTracksStartTime = mProcessedTime;
|
||||
if (aStream->IsSuspended()) {
|
||||
mSuspendedStreams.AppendElement(aStream);
|
||||
STREAM_LOG(LogLevel::Debug, ("Adding media stream %p to the graph, in the suspended stream array", aStream));
|
||||
@ -160,14 +160,14 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
|
||||
StreamTime t = aStream->GraphTimeToStreamTime(aDesiredUpToTime);
|
||||
STREAM_LOG(LogLevel::Verbose, ("Calling NotifyPull aStream=%p t=%f current end=%f", aStream,
|
||||
MediaTimeToSeconds(t),
|
||||
MediaTimeToSeconds(aStream->mBuffer.GetEnd())));
|
||||
if (t > aStream->mBuffer.GetEnd()) {
|
||||
MediaTimeToSeconds(aStream->mTracks.GetEnd())));
|
||||
if (t > aStream->mTracks.GetEnd()) {
|
||||
*aEnsureNextIteration = true;
|
||||
#ifdef DEBUG
|
||||
if (aStream->mListeners.Length() == 0) {
|
||||
STREAM_LOG(LogLevel::Error, ("No listeners in NotifyPull aStream=%p desired=%f current end=%f",
|
||||
aStream, MediaTimeToSeconds(t),
|
||||
MediaTimeToSeconds(aStream->mBuffer.GetEnd())));
|
||||
MediaTimeToSeconds(aStream->mTracks.GetEnd())));
|
||||
aStream->DumpTrackInfo();
|
||||
}
|
||||
#endif
|
||||
@ -181,12 +181,12 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
|
||||
}
|
||||
}
|
||||
finished = aStream->mUpdateFinished;
|
||||
bool notifiedTrackCreated = false;
|
||||
bool shouldNotifyTrackCreated = false;
|
||||
for (int32_t i = aStream->mUpdateTracks.Length() - 1; i >= 0; --i) {
|
||||
SourceMediaStream::TrackData* data = &aStream->mUpdateTracks[i];
|
||||
aStream->ApplyTrackDisabling(data->mID, data->mData);
|
||||
StreamTime offset = (data->mCommands & SourceMediaStream::TRACK_CREATE)
|
||||
? data->mStart : aStream->mBuffer.FindTrack(data->mID)->GetSegment()->GetDuration();
|
||||
? data->mStart : aStream->mTracks.FindTrack(data->mID)->GetSegment()->GetDuration();
|
||||
for (MediaStreamListener* l : aStream->mListeners) {
|
||||
l->NotifyQueuedTrackChanges(this, data->mID,
|
||||
offset, data->mCommands, *data->mData);
|
||||
@ -207,14 +207,14 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
|
||||
int64_t(segment->GetDuration())));
|
||||
|
||||
data->mEndOfFlushedData += segment->GetDuration();
|
||||
aStream->mBuffer.AddTrack(data->mID, data->mStart, segment);
|
||||
aStream->mTracks.AddTrack(data->mID, data->mStart, segment);
|
||||
// The track has taken ownership of data->mData, so let's replace
|
||||
// data->mData with an empty clone.
|
||||
data->mData = segment->CreateEmptyClone();
|
||||
data->mCommands &= ~SourceMediaStream::TRACK_CREATE;
|
||||
notifiedTrackCreated = true;
|
||||
shouldNotifyTrackCreated = true;
|
||||
} else if (data->mData->GetDuration() > 0) {
|
||||
MediaSegment* dest = aStream->mBuffer.FindTrack(data->mID)->GetSegment();
|
||||
MediaSegment* dest = aStream->mTracks.FindTrack(data->mID)->GetSegment();
|
||||
STREAM_LOG(LogLevel::Verbose, ("SourceMediaStream %p track %d, advancing end from %lld to %lld",
|
||||
aStream, data->mID,
|
||||
int64_t(dest->GetDuration()),
|
||||
@ -223,20 +223,20 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
|
||||
dest->AppendFrom(data->mData);
|
||||
}
|
||||
if (data->mCommands & SourceMediaStream::TRACK_END) {
|
||||
aStream->mBuffer.FindTrack(data->mID)->SetEnded();
|
||||
aStream->mTracks.FindTrack(data->mID)->SetEnded();
|
||||
aStream->mUpdateTracks.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
if (notifiedTrackCreated) {
|
||||
if (shouldNotifyTrackCreated) {
|
||||
for (MediaStreamListener* l : aStream->mListeners) {
|
||||
l->NotifyFinishedTrackCreation(this);
|
||||
}
|
||||
}
|
||||
if (!aStream->mFinished) {
|
||||
aStream->mBuffer.AdvanceKnownTracksTime(aStream->mUpdateKnownTracksTime);
|
||||
aStream->mTracks.AdvanceKnownTracksTime(aStream->mUpdateKnownTracksTime);
|
||||
}
|
||||
}
|
||||
if (aStream->mBuffer.GetEnd() > 0) {
|
||||
if (aStream->mTracks.GetEnd() > 0) {
|
||||
aStream->mHasCurrentData = true;
|
||||
}
|
||||
if (finished) {
|
||||
@ -251,7 +251,7 @@ MediaStreamGraphImpl::GraphTimeToStreamTimeWithBlocking(MediaStream* aStream,
|
||||
MOZ_ASSERT(aTime <= mStateComputedTime,
|
||||
"Don't ask about times where we haven't made blocking decisions yet");
|
||||
return std::max<StreamTime>(0,
|
||||
std::min(aTime, aStream->mStartBlocking) - aStream->mBufferStartTime);
|
||||
std::min(aTime, aStream->mStartBlocking) - aStream->mTracksStartTime);
|
||||
}
|
||||
|
||||
GraphTime
|
||||
@ -274,7 +274,7 @@ MediaStreamGraphImpl::UpdateCurrentTimeForStreams(GraphTime aPrevCurrentTime)
|
||||
blockedTime);
|
||||
STREAM_LOG(LogLevel::Verbose,
|
||||
("MediaStream %p bufferStartTime=%f blockedTime=%f", stream,
|
||||
MediaTimeToSeconds(stream->mBufferStartTime),
|
||||
MediaTimeToSeconds(stream->mTracksStartTime),
|
||||
MediaTimeToSeconds(blockedTime)));
|
||||
stream->mStartBlocking = mStateComputedTime;
|
||||
|
||||
@ -306,7 +306,7 @@ MediaStreamGraphImpl::UpdateCurrentTimeForStreams(GraphTime aPrevCurrentTime)
|
||||
// out.
|
||||
if (stream->mFinished && !stream->mNotifiedFinished &&
|
||||
mProcessedTime >=
|
||||
stream->StreamTimeToGraphTime(stream->GetStreamBuffer().GetAllTracksEnd())) {
|
||||
stream->StreamTimeToGraphTime(stream->GetStreamTracks().GetAllTracksEnd())) {
|
||||
stream->mNotifiedFinished = true;
|
||||
SetStreamOrderDirty();
|
||||
for (uint32_t j = 0; j < stream->mListeners.Length(); ++j) {
|
||||
@ -362,7 +362,7 @@ MediaStreamGraphImpl::ProcessChunkMetadata(GraphTime aPrevCurrentTime)
|
||||
for (MediaStream* stream : AllStreams()) {
|
||||
StreamTime iterationStart = stream->GraphTimeToStreamTime(aPrevCurrentTime);
|
||||
StreamTime iterationEnd = stream->GraphTimeToStreamTime(mProcessedTime);
|
||||
for (StreamBuffer::TrackIter tracks(stream->mBuffer);
|
||||
for (StreamTracks::TrackIter tracks(stream->mTracks);
|
||||
!tracks.IsEnded(); tracks.Next()) {
|
||||
MediaSegment* segment = tracks->GetSegment();
|
||||
if (!segment) {
|
||||
@ -396,13 +396,13 @@ MediaStreamGraphImpl::WillUnderrun(MediaStream* aStream,
|
||||
// This stream isn't finished or suspended. We don't need to call
|
||||
// StreamTimeToGraphTime since an underrun is the only thing that can block
|
||||
// it.
|
||||
GraphTime bufferEnd = aStream->GetBufferEnd() + aStream->mBufferStartTime;
|
||||
GraphTime bufferEnd = aStream->GetTracksEnd() + aStream->mTracksStartTime;
|
||||
#ifdef DEBUG
|
||||
if (bufferEnd < mProcessedTime) {
|
||||
STREAM_LOG(LogLevel::Error, ("MediaStream %p underrun, "
|
||||
"bufferEnd %f < mProcessedTime %f (%lld < %lld), Streamtime %lld",
|
||||
aStream, MediaTimeToSeconds(bufferEnd), MediaTimeToSeconds(mProcessedTime),
|
||||
bufferEnd, mProcessedTime, aStream->GetBufferEnd()));
|
||||
bufferEnd, mProcessedTime, aStream->GetTracksEnd()));
|
||||
aStream->DumpTrackInfo();
|
||||
NS_ASSERTION(bufferEnd >= mProcessedTime, "Buffer underran");
|
||||
}
|
||||
@ -435,7 +435,7 @@ MediaStreamGraphImpl::AudioTrackPresent(bool& aNeedsAEC)
|
||||
if (stream->AsAudioNodeStream()) {
|
||||
audioTrackPresent = true;
|
||||
} else {
|
||||
for (StreamBuffer::TrackIter tracks(stream->GetStreamBuffer(), MediaSegment::AUDIO);
|
||||
for (StreamTracks::TrackIter tracks(stream->GetStreamTracks(), MediaSegment::AUDIO);
|
||||
!tracks.IsEnded(); tracks.Next()) {
|
||||
audioTrackPresent = true;
|
||||
}
|
||||
@ -729,7 +729,7 @@ MediaStreamGraphImpl::CreateOrDestroyAudioStreams(MediaStream* aStream)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aStream->GetStreamBuffer().GetAndResetTracksDirty() &&
|
||||
if (!aStream->GetStreamTracks().GetAndResetTracksDirty() &&
|
||||
!aStream->mAudioOutputStreams.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
@ -741,7 +741,7 @@ MediaStreamGraphImpl::CreateOrDestroyAudioStreams(MediaStream* aStream)
|
||||
audioOutputStreamsFound.AppendElement(false);
|
||||
}
|
||||
|
||||
for (StreamBuffer::TrackIter tracks(aStream->GetStreamBuffer(), MediaSegment::AUDIO);
|
||||
for (StreamTracks::TrackIter tracks(aStream->GetStreamTracks(), MediaSegment::AUDIO);
|
||||
!tracks.IsEnded(); tracks.Next()) {
|
||||
uint32_t i;
|
||||
for (i = 0; i < audioOutputStreamsFound.Length(); ++i) {
|
||||
@ -800,13 +800,13 @@ MediaStreamGraphImpl::PlayAudio(MediaStream* aStream)
|
||||
ticksWritten = 0;
|
||||
|
||||
MediaStream::AudioOutputStream& audioOutput = aStream->mAudioOutputStreams[i];
|
||||
StreamBuffer::Track* track = aStream->mBuffer.FindTrack(audioOutput.mTrackID);
|
||||
StreamTracks::Track* track = aStream->mTracks.FindTrack(audioOutput.mTrackID);
|
||||
AudioSegment* audio = track->Get<AudioSegment>();
|
||||
AudioSegment output;
|
||||
|
||||
StreamTime offset = aStream->GraphTimeToStreamTime(mProcessedTime);
|
||||
|
||||
// We don't update aStream->mBufferStartTime here to account for time spent
|
||||
// We don't update aStream->mTracksStartTime here to account for time spent
|
||||
// blocked. Instead, we'll update it in UpdateCurrentTimeForStreams after
|
||||
// the blocked period has completed. But we do need to make sure we play
|
||||
// from the right offsets in the stream buffer, even if we've already
|
||||
@ -925,7 +925,7 @@ MediaStreamGraphImpl::PlayVideo(MediaStream* aStream)
|
||||
PrincipalHandle lastPrincipalHandle = PRINCIPAL_HANDLE_NONE;
|
||||
RefPtr<Image> blackImage;
|
||||
|
||||
MOZ_ASSERT(mProcessedTime >= aStream->mBufferStartTime, "frame position before buffer?");
|
||||
MOZ_ASSERT(mProcessedTime >= aStream->mTracksStartTime, "frame position before buffer?");
|
||||
// We only look at the non-blocking interval
|
||||
StreamTime frameBufferTime = aStream->GraphTimeToStreamTime(mProcessedTime);
|
||||
StreamTime bufferEndTime = aStream->GraphTimeToStreamTime(aStream->mStartBlocking);
|
||||
@ -937,7 +937,7 @@ MediaStreamGraphImpl::PlayVideo(MediaStream* aStream)
|
||||
// Pick the last track that has a video chunk for the time, and
|
||||
// schedule its frame.
|
||||
chunk = nullptr;
|
||||
for (StreamBuffer::TrackIter tracks(aStream->GetStreamBuffer(),
|
||||
for (StreamTracks::TrackIter tracks(aStream->GetStreamTracks(),
|
||||
MediaSegment::VIDEO);
|
||||
!tracks.IsEnded();
|
||||
tracks.Next()) {
|
||||
@ -1368,14 +1368,14 @@ MediaStreamGraphImpl::UpdateGraph(GraphTime aEndBlockingDecisions)
|
||||
// The stream's not suspended, and since it's finished, underruns won't
|
||||
// stop it playing out. So there's no blocking other than what we impose
|
||||
// here.
|
||||
GraphTime endTime = stream->GetStreamBuffer().GetAllTracksEnd() +
|
||||
stream->mBufferStartTime;
|
||||
GraphTime endTime = stream->GetStreamTracks().GetAllTracksEnd() +
|
||||
stream->mTracksStartTime;
|
||||
if (endTime <= mStateComputedTime) {
|
||||
STREAM_LOG(LogLevel::Verbose, ("MediaStream %p is blocked due to being finished", stream));
|
||||
stream->mStartBlocking = mStateComputedTime;
|
||||
} else {
|
||||
STREAM_LOG(LogLevel::Verbose, ("MediaStream %p is finished, but not blocked yet (end at %f, with blocking at %f)",
|
||||
stream, MediaTimeToSeconds(stream->GetBufferEnd()),
|
||||
stream, MediaTimeToSeconds(stream->GetTracksEnd()),
|
||||
MediaTimeToSeconds(endTime)));
|
||||
// Data can't be added to a finished stream, so underruns are irrelevant.
|
||||
stream->mStartBlocking = std::min(endTime, aEndBlockingDecisions);
|
||||
@ -1439,7 +1439,7 @@ MediaStreamGraphImpl::Process()
|
||||
} else {
|
||||
ps->ProcessInput(mProcessedTime, mStateComputedTime,
|
||||
ProcessedMediaStream::ALLOW_FINISH);
|
||||
NS_WARN_IF_FALSE(stream->mBuffer.GetEnd() >=
|
||||
NS_WARN_IF_FALSE(stream->mTracks.GetEnd() >=
|
||||
GraphTimeToStreamTimeWithBlocking(stream, mStateComputedTime),
|
||||
"Stream did not produce enough data");
|
||||
}
|
||||
@ -1922,7 +1922,7 @@ MediaStreamGraphImpl::AppendMessage(UniquePtr<ControlMessage> aMessage)
|
||||
}
|
||||
|
||||
MediaStream::MediaStream(DOMMediaStream* aWrapper)
|
||||
: mBufferStartTime(0)
|
||||
: mTracksStartTime(0)
|
||||
, mStartBlocking(GRAPH_TIME_MAX)
|
||||
, mSuspendedCount(0)
|
||||
, mFinished(false)
|
||||
@ -1962,7 +1962,7 @@ MediaStream::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
// - mListeners - elements
|
||||
// - mAudioOutputStream - elements
|
||||
|
||||
amount += mBuffer.SizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mTracks.SizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mAudioOutputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mVideoOutputs.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mListeners.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
@ -1997,7 +1997,7 @@ MediaStream::SetGraphImpl(MediaStreamGraphImpl* aGraph)
|
||||
MOZ_ASSERT(!mGraph, "Should only be called once");
|
||||
mGraph = aGraph;
|
||||
mAudioChannelType = aGraph->AudioChannel();
|
||||
mBuffer.InitGraphRate(aGraph->GraphRate());
|
||||
mTracks.InitGraphRate(aGraph->GraphRate());
|
||||
}
|
||||
|
||||
void
|
||||
@ -2013,16 +2013,16 @@ MediaStream::GraphTimeToStreamTime(GraphTime aTime)
|
||||
NS_ASSERTION(mStartBlocking == GraphImpl()->mStateComputedTime ||
|
||||
aTime <= mStartBlocking,
|
||||
"Incorrectly ignoring blocking!");
|
||||
return aTime - mBufferStartTime;
|
||||
return aTime - mTracksStartTime;
|
||||
}
|
||||
|
||||
GraphTime
|
||||
MediaStream::StreamTimeToGraphTime(StreamTime aTime)
|
||||
{
|
||||
NS_ASSERTION(mStartBlocking == GraphImpl()->mStateComputedTime ||
|
||||
aTime + mBufferStartTime <= mStartBlocking,
|
||||
aTime + mTracksStartTime <= mStartBlocking,
|
||||
"Incorrectly ignoring blocking!");
|
||||
return aTime + mBufferStartTime;
|
||||
return aTime + mTracksStartTime;
|
||||
}
|
||||
|
||||
StreamTime
|
||||
@ -2037,16 +2037,16 @@ MediaStream::FinishOnGraphThread()
|
||||
GraphImpl()->FinishStream(this);
|
||||
}
|
||||
|
||||
StreamBuffer::Track*
|
||||
StreamTracks::Track*
|
||||
MediaStream::FindTrack(TrackID aID)
|
||||
{
|
||||
return mBuffer.FindTrack(aID);
|
||||
return mTracks.FindTrack(aID);
|
||||
}
|
||||
|
||||
StreamBuffer::Track*
|
||||
StreamTracks::Track*
|
||||
MediaStream::EnsureTrack(TrackID aTrackId)
|
||||
{
|
||||
StreamBuffer::Track* track = mBuffer.FindTrack(aTrackId);
|
||||
StreamTracks::Track* track = mTracks.FindTrack(aTrackId);
|
||||
if (!track) {
|
||||
nsAutoPtr<MediaSegment> segment(new AudioSegment());
|
||||
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
|
||||
@ -2058,7 +2058,7 @@ MediaStream::EnsureTrack(TrackID aTrackId)
|
||||
// change this.
|
||||
l->NotifyFinishedTrackCreation(Graph());
|
||||
}
|
||||
track = &mBuffer.AddTrack(aTrackId, 0, segment.forget());
|
||||
track = &mTracks.AddTrack(aTrackId, 0, segment.forget());
|
||||
}
|
||||
return track;
|
||||
}
|
||||
@ -2374,7 +2374,7 @@ MediaStream::AddTrackListenerImpl(already_AddRefed<MediaStreamTrackListener> aLi
|
||||
l->mListener = aListener;
|
||||
l->mTrackID = aTrackID;
|
||||
|
||||
StreamBuffer::Track* track = FindTrack(aTrackID);
|
||||
StreamTracks::Track* track = FindTrack(aTrackID);
|
||||
if (!track) {
|
||||
return;
|
||||
}
|
||||
@ -2933,20 +2933,22 @@ SourceMediaStream::FinishWithLockHeld()
|
||||
void
|
||||
SourceMediaStream::SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
for (TrackBound<MediaStreamTrackDirectListener>& l: mDirectTrackListeners) {
|
||||
if (l.mTrackID == aTrackID) {
|
||||
bool oldEnabled = !mDisabledTrackIDs.Contains(aTrackID);
|
||||
if (!oldEnabled && aEnabled) {
|
||||
STREAM_LOG(LogLevel::Debug, ("SourceMediaStream %p track %d setting "
|
||||
"direct listener enabled",
|
||||
this, aTrackID));
|
||||
l.mListener->DecreaseDisabled();
|
||||
} else if (oldEnabled && !aEnabled) {
|
||||
STREAM_LOG(LogLevel::Debug, ("SourceMediaStream %p track %d setting "
|
||||
"direct listener disabled",
|
||||
this, aTrackID));
|
||||
l.mListener->IncreaseDisabled();
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
for (TrackBound<MediaStreamTrackDirectListener>& l: mDirectTrackListeners) {
|
||||
if (l.mTrackID == aTrackID) {
|
||||
bool oldEnabled = !mDisabledTrackIDs.Contains(aTrackID);
|
||||
if (!oldEnabled && aEnabled) {
|
||||
STREAM_LOG(LogLevel::Debug, ("SourceMediaStream %p track %d setting "
|
||||
"direct listener enabled",
|
||||
this, aTrackID));
|
||||
l.mListener->DecreaseDisabled();
|
||||
} else if (oldEnabled && !aEnabled) {
|
||||
STREAM_LOG(LogLevel::Debug, ("SourceMediaStream %p track %d setting "
|
||||
"direct listener disabled",
|
||||
this, aTrackID));
|
||||
l.mListener->IncreaseDisabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "AudioStream.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "StreamTracks.h"
|
||||
#include "VideoFrameContainer.h"
|
||||
#include "VideoSegment.h"
|
||||
#include "MainThreadUtils.h"
|
||||
@ -265,7 +265,7 @@ protected:
|
||||
|
||||
/**
|
||||
* This is a base class for media graph thread listener direct callbacks
|
||||
* from within AppendToTrack(). Note that your regular listener will
|
||||
* 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.
|
||||
*/
|
||||
@ -311,13 +311,12 @@ public:
|
||||
/*
|
||||
* This will be called on any MediaStreamTrackDirectListener added to a
|
||||
* SourceMediaStream when AppendToTrack() is called for the listener's bound
|
||||
* track. The MediaSegment will be the RawSegment (unresampled) if available
|
||||
* in AppendToTrack().
|
||||
* 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.
|
||||
* Note that NotifyQueuedTrackChanges() calls will also still occur.
|
||||
*/
|
||||
virtual void NotifyRealtimeTrackData(MediaStreamGraph* aGraph,
|
||||
StreamTime aTrackOffset,
|
||||
@ -477,7 +476,7 @@ struct TrackBound
|
||||
* time. To ensure video plays in sync with audio, make sure that the same
|
||||
* stream is playing both the audio and video.
|
||||
*
|
||||
* The data in a stream is managed by StreamBuffer. It consists of a set of
|
||||
* The data in a stream is managed by StreamTracks. It consists of a set of
|
||||
* tracks of various types that can start and end over time.
|
||||
*
|
||||
* Streams are explicitly managed. The client creates them via
|
||||
@ -495,8 +494,8 @@ struct TrackBound
|
||||
* wrapper; the DOM wrappers own their associated MediaStreams. When a DOM
|
||||
* wrapper is destroyed, it sends a Destroy message for the associated
|
||||
* MediaStream and clears its reference (the last main-thread reference to
|
||||
* the object). When the Destroy message is processed on the graph
|
||||
* manager thread we immediately release the affected objects (disentangling them
|
||||
* the object). When the Destroy message is processed on the graph manager
|
||||
* thread we immediately release the affected objects (disentangling them
|
||||
* from other objects as necessary).
|
||||
*
|
||||
* This could cause problems for media processing if a MediaStream is
|
||||
@ -541,7 +540,7 @@ public:
|
||||
/**
|
||||
* Returns sample rate of the graph.
|
||||
*/
|
||||
TrackRate GraphRate() { return mBuffer.GraphRate(); }
|
||||
TrackRate GraphRate() { return mTracks.GraphRate(); }
|
||||
|
||||
// Control API.
|
||||
// Since a stream can be played multiple ways, we need to combine independent
|
||||
@ -674,9 +673,9 @@ public:
|
||||
* This must be idempotent.
|
||||
*/
|
||||
virtual void DestroyImpl();
|
||||
StreamTime GetBufferEnd() { return mBuffer.GetEnd(); }
|
||||
StreamTime GetTracksEnd() { return mTracks.GetEnd(); }
|
||||
#ifdef DEBUG
|
||||
void DumpTrackInfo() { return mBuffer.DumpTrackInfo(); }
|
||||
void DumpTrackInfo() { return mTracks.DumpTrackInfo(); }
|
||||
#endif
|
||||
void SetAudioOutputVolumeImpl(void* aKey, float aVolume);
|
||||
void AddAudioOutputImpl(void* aKey);
|
||||
@ -713,36 +712,36 @@ public:
|
||||
{
|
||||
return mConsumers.Length();
|
||||
}
|
||||
StreamBuffer& GetStreamBuffer() { return mBuffer; }
|
||||
GraphTime GetStreamBufferStartTime() { return mBufferStartTime; }
|
||||
StreamTracks& GetStreamTracks() { return mTracks; }
|
||||
GraphTime GetStreamTracksStartTime() { return mTracksStartTime; }
|
||||
|
||||
double StreamTimeToSeconds(StreamTime aTime)
|
||||
{
|
||||
NS_ASSERTION(0 <= aTime && aTime <= STREAM_TIME_MAX, "Bad time");
|
||||
return static_cast<double>(aTime)/mBuffer.GraphRate();
|
||||
return static_cast<double>(aTime)/mTracks.GraphRate();
|
||||
}
|
||||
int64_t StreamTimeToMicroseconds(StreamTime aTime)
|
||||
{
|
||||
NS_ASSERTION(0 <= aTime && aTime <= STREAM_TIME_MAX, "Bad time");
|
||||
return (aTime*1000000)/mBuffer.GraphRate();
|
||||
return (aTime*1000000)/mTracks.GraphRate();
|
||||
}
|
||||
StreamTime SecondsToNearestStreamTime(double aSeconds)
|
||||
{
|
||||
NS_ASSERTION(0 <= aSeconds && aSeconds <= TRACK_TICKS_MAX/TRACK_RATE_MAX,
|
||||
"Bad seconds");
|
||||
return mBuffer.GraphRate() * aSeconds + 0.5;
|
||||
return mTracks.GraphRate() * aSeconds + 0.5;
|
||||
}
|
||||
StreamTime MicrosecondsToStreamTimeRoundDown(int64_t aMicroseconds) {
|
||||
return (aMicroseconds*mBuffer.GraphRate())/1000000;
|
||||
return (aMicroseconds*mTracks.GraphRate())/1000000;
|
||||
}
|
||||
|
||||
TrackTicks TimeToTicksRoundUp(TrackRate aRate, StreamTime aTime)
|
||||
{
|
||||
return RateConvertTicksRoundUp(aRate, mBuffer.GraphRate(), aTime);
|
||||
return RateConvertTicksRoundUp(aRate, mTracks.GraphRate(), aTime);
|
||||
}
|
||||
StreamTime TicksToTimeRoundDown(TrackRate aRate, TrackTicks aTicks)
|
||||
{
|
||||
return RateConvertTicksRoundDown(mBuffer.GraphRate(), aRate, aTicks);
|
||||
return RateConvertTicksRoundDown(mTracks.GraphRate(), aRate, aTicks);
|
||||
}
|
||||
/**
|
||||
* Convert graph time to stream time. aTime must be <= mStateComputedTime
|
||||
@ -773,9 +772,9 @@ public:
|
||||
/**
|
||||
* Find track by track id.
|
||||
*/
|
||||
StreamBuffer::Track* FindTrack(TrackID aID);
|
||||
StreamTracks::Track* FindTrack(TrackID aID);
|
||||
|
||||
StreamBuffer::Track* EnsureTrack(TrackID aTrack);
|
||||
StreamTracks::Track* EnsureTrack(TrackID aTrack);
|
||||
|
||||
virtual void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, MediaSegment* aRawSegment = nullptr);
|
||||
|
||||
@ -808,8 +807,8 @@ public:
|
||||
protected:
|
||||
void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime, GraphTime aBlockedTime)
|
||||
{
|
||||
mBufferStartTime += aBlockedTime;
|
||||
mBuffer.ForgetUpTo(aCurrentTime - mBufferStartTime);
|
||||
mTracksStartTime += aBlockedTime;
|
||||
mTracks.ForgetUpTo(aCurrentTime - mTracksStartTime);
|
||||
}
|
||||
|
||||
void NotifyMainThreadListeners()
|
||||
@ -836,14 +835,14 @@ protected:
|
||||
// This state is all initialized on the main thread but
|
||||
// otherwise modified only on the media graph thread.
|
||||
|
||||
// Buffered data. The start of the buffer corresponds to mBufferStartTime.
|
||||
// Buffered data. The start of the buffer corresponds to mTracksStartTime.
|
||||
// Conceptually the buffer contains everything this stream has ever played,
|
||||
// but we forget some prefix of the buffered data to bound the space usage.
|
||||
StreamBuffer mBuffer;
|
||||
StreamTracks mTracks;
|
||||
// The time when the buffered data could be considered to have started playing.
|
||||
// This increases over time to account for time the stream was blocked before
|
||||
// mCurrentTime.
|
||||
GraphTime mBufferStartTime;
|
||||
GraphTime mTracksStartTime;
|
||||
|
||||
// Client-set volume of this stream
|
||||
struct AudioOutput {
|
||||
@ -863,7 +862,7 @@ protected:
|
||||
|
||||
// GraphTime at which this stream starts blocking.
|
||||
// This is only valid up to mStateComputedTime. The stream is considered to
|
||||
// have not been blocked before mCurrentTime (its mBufferStartTime is increased
|
||||
// have not been blocked before mCurrentTime (its mTracksStartTime is increased
|
||||
// as necessary to account for that time instead).
|
||||
GraphTime mStartBlocking;
|
||||
|
||||
@ -1078,16 +1077,6 @@ public:
|
||||
friend class MediaStreamGraphImpl;
|
||||
|
||||
protected:
|
||||
struct ThreadAndRunnable {
|
||||
void Init(TaskQueue* aTarget, nsIRunnable* aRunnable)
|
||||
{
|
||||
mTarget = aTarget;
|
||||
mRunnable = aRunnable;
|
||||
}
|
||||
|
||||
RefPtr<TaskQueue> mTarget;
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
};
|
||||
enum TrackCommands {
|
||||
TRACK_CREATE = MediaStreamListener::TRACK_EVENT_CREATED,
|
||||
TRACK_END = MediaStreamListener::TRACK_EVENT_ENDED
|
||||
@ -1455,7 +1444,6 @@ public:
|
||||
// IdealAudioBlockSize()/AudioStream::PreferredSampleRate(). A stream that
|
||||
// never blocks and has a track with the ideal audio rate will produce audio
|
||||
// in multiples of the block size.
|
||||
//
|
||||
|
||||
// Initializing an graph that outputs audio can be quite long on some
|
||||
// platforms. Code that want to output audio at some point can express the
|
||||
|
@ -91,8 +91,9 @@ public:
|
||||
* file. It's not in the anonymous namespace because MediaStream needs to
|
||||
* be able to friend it.
|
||||
*
|
||||
* Currently we have one global instance per process, and one per each
|
||||
* OfflineAudioContext object.
|
||||
* There can be multiple MediaStreamGraph per process: one per AudioChannel.
|
||||
* Additionaly, each OfflineAudioContext object creates its own MediaStreamGraph
|
||||
* object too.
|
||||
*/
|
||||
class MediaStreamGraphImpl : public MediaStreamGraph,
|
||||
public nsIMemoryReporter
|
||||
@ -104,10 +105,10 @@ public:
|
||||
/**
|
||||
* Use aGraphDriverRequested with SYSTEM_THREAD_DRIVER or AUDIO_THREAD_DRIVER
|
||||
* to create a MediaStreamGraph which provides support for real-time audio
|
||||
* and/or video. Set it to false in order to create a non-realtime instance
|
||||
* which just churns through its inputs and produces output. Those objects
|
||||
* currently only support audio, and are used to implement
|
||||
* OfflineAudioContext. They do not support MediaStream inputs.
|
||||
* and/or video. Set it to OFFLINE_THREAD_DRIVER in order to create a
|
||||
* non-realtime instance which just churns through its inputs and produces
|
||||
* output. Those objects currently only support audio, and are used to
|
||||
* implement OfflineAudioContext. They do not support MediaStream inputs.
|
||||
*/
|
||||
explicit MediaStreamGraphImpl(GraphDriverType aGraphDriverRequested,
|
||||
TrackRate aSampleRate,
|
||||
@ -403,7 +404,7 @@ public:
|
||||
void PlayVideo(MediaStream* aStream);
|
||||
/**
|
||||
* No more data will be forthcoming for aStream. The stream will end
|
||||
* at the current buffer end point. The StreamBuffer's tracks must be
|
||||
* at the current buffer end point. The StreamTracks's tracks must be
|
||||
* explicitly set to finished by the caller.
|
||||
*/
|
||||
void OpenAudioInputImpl(int aID,
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "nsError.h"
|
||||
#include "nsID.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "StreamTracks.h"
|
||||
#include "MediaTrackConstraints.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
#include "PrincipalChangeObserver.h"
|
||||
|
117
dom/media/StreamTracks.cpp
Normal file
117
dom/media/StreamTracks.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
/* -*- 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 "StreamTracks.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
extern LazyLogModule gMediaStreamGraphLog;
|
||||
#define STREAM_LOG(type, msg) MOZ_LOG(gMediaStreamGraphLog, type, msg)
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
StreamTracks::DumpTrackInfo() const
|
||||
{
|
||||
STREAM_LOG(LogLevel::Info, ("DumpTracks: mTracksKnownTime %lld", mTracksKnownTime));
|
||||
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
|
||||
Track* track = mTracks[i];
|
||||
if (track->IsEnded()) {
|
||||
STREAM_LOG(LogLevel::Info, ("Track[%d] %d: ended", i, track->GetID()));
|
||||
} else {
|
||||
STREAM_LOG(LogLevel::Info, ("Track[%d] %d: %lld", i, track->GetID(),
|
||||
track->GetEnd()));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
StreamTime
|
||||
StreamTracks::GetEnd() const
|
||||
{
|
||||
StreamTime t = mTracksKnownTime;
|
||||
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
|
||||
Track* track = mTracks[i];
|
||||
if (!track->IsEnded()) {
|
||||
t = std::min(t, track->GetEnd());
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
StreamTime
|
||||
StreamTracks::GetAllTracksEnd() const
|
||||
{
|
||||
if (mTracksKnownTime < STREAM_TIME_MAX) {
|
||||
// A track might be added.
|
||||
return STREAM_TIME_MAX;
|
||||
}
|
||||
StreamTime t = 0;
|
||||
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
|
||||
Track* track = mTracks[i];
|
||||
if (!track->IsEnded()) {
|
||||
return STREAM_TIME_MAX;
|
||||
}
|
||||
t = std::max(t, track->GetEnd());
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
StreamTracks::Track*
|
||||
StreamTracks::FindTrack(TrackID aID)
|
||||
{
|
||||
if (aID == TRACK_NONE || mTracks.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The tracks are sorted by ID. We can use a binary search.
|
||||
|
||||
uint32_t left = 0, right = mTracks.Length() - 1;
|
||||
while (left <= right) {
|
||||
uint32_t middle = (left + right) / 2;
|
||||
if (mTracks[middle]->GetID() == aID) {
|
||||
return mTracks[middle];
|
||||
}
|
||||
|
||||
if (mTracks[middle]->GetID() > aID) {
|
||||
if (middle == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
right = middle - 1;
|
||||
} else {
|
||||
left = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
StreamTracks::ForgetUpTo(StreamTime aTime)
|
||||
{
|
||||
// Only prune if there is a reasonable chunk (50ms @ 48kHz) to forget, so we
|
||||
// don't spend too much time pruning segments.
|
||||
const StreamTime minChunkSize = 2400;
|
||||
if (aTime < mForgottenTime + minChunkSize) {
|
||||
return;
|
||||
}
|
||||
mForgottenTime = aTime;
|
||||
|
||||
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
|
||||
Track* track = mTracks[i];
|
||||
if (track->IsEnded() && track->GetEnd() <= aTime) {
|
||||
mTracks.RemoveElementAt(i);
|
||||
mTracksDirty = true;
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
StreamTime forgetTo = std::min(track->GetEnd() - 1, aTime);
|
||||
track->ForgetUpTo(forgetTo);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
343
dom/media/StreamTracks.h
Normal file
343
dom/media/StreamTracks.h
Normal file
@ -0,0 +1,343 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef MOZILLA_STREAMTRACKS_H_
|
||||
#define MOZILLA_STREAMTRACKS_H_
|
||||
|
||||
#include "MediaSegment.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Unique ID for track within a StreamTracks. Tracks from different
|
||||
* StreamTrackss may have the same ID; this matters when appending StreamTrackss,
|
||||
* since tracks with the same ID are matched. Only IDs greater than 0 are allowed.
|
||||
*/
|
||||
typedef int32_t TrackID;
|
||||
const TrackID TRACK_NONE = 0;
|
||||
const TrackID TRACK_INVALID = -1;
|
||||
const TrackID TRACK_ANY = -2;
|
||||
|
||||
inline bool IsTrackIDExplicit(const TrackID& aId) {
|
||||
return aId > TRACK_NONE;
|
||||
}
|
||||
|
||||
inline TrackTicks RateConvertTicksRoundDown(TrackRate aOutRate,
|
||||
TrackRate aInRate,
|
||||
TrackTicks aTicks)
|
||||
{
|
||||
NS_ASSERTION(0 < aOutRate && aOutRate <= TRACK_RATE_MAX, "Bad out rate");
|
||||
NS_ASSERTION(0 < aInRate && aInRate <= TRACK_RATE_MAX, "Bad in rate");
|
||||
NS_WARN_IF_FALSE(0 <= aTicks && aTicks <= TRACK_TICKS_MAX, "Bad ticks"); // bug 957691
|
||||
return (aTicks * aOutRate) / aInRate;
|
||||
}
|
||||
inline TrackTicks RateConvertTicksRoundUp(TrackRate aOutRate,
|
||||
TrackRate aInRate, TrackTicks aTicks)
|
||||
{
|
||||
NS_ASSERTION(0 < aOutRate && aOutRate <= TRACK_RATE_MAX, "Bad out rate");
|
||||
NS_ASSERTION(0 < aInRate && aInRate <= TRACK_RATE_MAX, "Bad in rate");
|
||||
NS_ASSERTION(0 <= aTicks && aTicks <= TRACK_TICKS_MAX, "Bad ticks");
|
||||
return (aTicks * aOutRate + aInRate - 1) / aInRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* This object contains the decoded data for a stream's tracks.
|
||||
* A StreamTracks can be appended to. Logically a StreamTracks only gets longer,
|
||||
* but we also have the ability to "forget" data before a certain time that
|
||||
* we know won't be used again. (We prune a whole number of seconds internally.)
|
||||
*
|
||||
* StreamTrackss should only be used from one thread at a time.
|
||||
*
|
||||
* A StreamTracks has a set of tracks that can be of arbitrary types ---
|
||||
* the data for each track is a MediaSegment. The set of tracks can vary
|
||||
* over the timeline of the StreamTracks.
|
||||
*/
|
||||
class StreamTracks
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Every track has a start time --- when it started in the StreamTracks.
|
||||
* It has an end flag; when false, no end point is known; when true,
|
||||
* the track ends when the data we have for the track runs out.
|
||||
* Tracks have a unique ID assigned at creation. This allows us to identify
|
||||
* the same track across StreamTrackss. A StreamTracks should never have
|
||||
* two tracks with the same ID (even if they don't overlap in time).
|
||||
* TODO Tracks can also be enabled and disabled over time.
|
||||
* Takes ownership of aSegment.
|
||||
*/
|
||||
class Track final
|
||||
{
|
||||
Track(TrackID aID, StreamTime aStart, MediaSegment* aSegment)
|
||||
: mStart(aStart),
|
||||
mSegment(aSegment),
|
||||
mID(aID),
|
||||
mEnded(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(Track);
|
||||
|
||||
NS_ASSERTION(aID > TRACK_NONE, "Bad track ID");
|
||||
NS_ASSERTION(0 <= aStart && aStart <= aSegment->GetDuration(), "Bad start position");
|
||||
}
|
||||
|
||||
public:
|
||||
~Track()
|
||||
{
|
||||
MOZ_COUNT_DTOR(Track);
|
||||
}
|
||||
|
||||
template <class T> T* Get() const
|
||||
{
|
||||
if (mSegment->GetType() == T::StaticType()) {
|
||||
return static_cast<T*>(mSegment.get());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MediaSegment* GetSegment() const { return mSegment; }
|
||||
TrackID GetID() const { return mID; }
|
||||
bool IsEnded() const { return mEnded; }
|
||||
StreamTime GetStart() const { return mStart; }
|
||||
StreamTime GetEnd() const { return mSegment->GetDuration(); }
|
||||
MediaSegment::Type GetType() const { return mSegment->GetType(); }
|
||||
|
||||
void SetEnded() { mEnded = true; }
|
||||
void AppendFrom(Track* aTrack)
|
||||
{
|
||||
NS_ASSERTION(!mEnded, "Can't append to ended track");
|
||||
NS_ASSERTION(aTrack->mID == mID, "IDs must match");
|
||||
NS_ASSERTION(aTrack->mStart == 0, "Source track must start at zero");
|
||||
NS_ASSERTION(aTrack->mSegment->GetType() == GetType(), "Track types must match");
|
||||
|
||||
mSegment->AppendFrom(aTrack->mSegment);
|
||||
mEnded = aTrack->mEnded;
|
||||
}
|
||||
MediaSegment* RemoveSegment()
|
||||
{
|
||||
return mSegment.forget();
|
||||
}
|
||||
void ForgetUpTo(StreamTime aTime)
|
||||
{
|
||||
mSegment->ForgetUpTo(aTime);
|
||||
}
|
||||
void FlushAfter(StreamTime aNewEnd)
|
||||
{
|
||||
// Forget everything after a given endpoint
|
||||
// a specified amount
|
||||
mSegment->FlushAfter(aNewEnd);
|
||||
}
|
||||
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
size_t amount = aMallocSizeOf(this);
|
||||
if (mSegment) {
|
||||
amount += mSegment->SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class StreamTracks;
|
||||
|
||||
// Start offset is in ticks at rate mRate
|
||||
StreamTime mStart;
|
||||
// The segment data starts at the start of the owning StreamTracks, i.e.,
|
||||
// there's mStart silence/no video at the beginning.
|
||||
nsAutoPtr<MediaSegment> mSegment;
|
||||
// Unique ID
|
||||
TrackID mID;
|
||||
// True when the track ends with the data in mSegment
|
||||
bool mEnded;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS CompareTracksByID final
|
||||
{
|
||||
public:
|
||||
bool Equals(Track* aA, Track* aB) const {
|
||||
return aA->GetID() == aB->GetID();
|
||||
}
|
||||
bool LessThan(Track* aA, Track* aB) const {
|
||||
return aA->GetID() < aB->GetID();
|
||||
}
|
||||
};
|
||||
|
||||
StreamTracks()
|
||||
: mGraphRate(0)
|
||||
, mTracksKnownTime(0)
|
||||
, mForgottenTime(0)
|
||||
, mTracksDirty(false)
|
||||
#ifdef DEBUG
|
||||
, mGraphRateIsSet(false)
|
||||
#endif
|
||||
{
|
||||
MOZ_COUNT_CTOR(StreamTracks);
|
||||
}
|
||||
~StreamTracks()
|
||||
{
|
||||
MOZ_COUNT_DTOR(StreamTracks);
|
||||
}
|
||||
|
||||
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
size_t amount = 0;
|
||||
amount += mTracks.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
for (size_t i = 0; i < mTracks.Length(); i++) {
|
||||
amount += mTracks[i]->SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the graph rate for use in calculating StreamTimes from track
|
||||
* ticks. Called when a MediaStream's graph pointer is initialized.
|
||||
*/
|
||||
void InitGraphRate(TrackRate aGraphRate)
|
||||
{
|
||||
mGraphRate = aGraphRate;
|
||||
#if DEBUG
|
||||
MOZ_ASSERT(!mGraphRateIsSet);
|
||||
mGraphRateIsSet = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
TrackRate GraphRate() const
|
||||
{
|
||||
MOZ_ASSERT(mGraphRateIsSet);
|
||||
return mGraphRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes ownership of aSegment. Don't do this while iterating, or while
|
||||
* holding a Track reference.
|
||||
* aSegment must have aStart worth of null data.
|
||||
*/
|
||||
Track& AddTrack(TrackID aID, StreamTime aStart, MediaSegment* aSegment)
|
||||
{
|
||||
NS_ASSERTION(!FindTrack(aID), "Track with this ID already exists");
|
||||
|
||||
Track* track = new Track(aID, aStart, aSegment);
|
||||
mTracks.InsertElementSorted(track, CompareTracksByID());
|
||||
mTracksDirty = true;
|
||||
|
||||
if (mTracksKnownTime == STREAM_TIME_MAX) {
|
||||
// There exists code like
|
||||
// http://mxr.mozilla.org/mozilla-central/source/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp?rev=96b197deb91e&mark=1292-1297#1292
|
||||
NS_WARNING("Adding track to StreamTracks that should have no more tracks");
|
||||
} else {
|
||||
NS_ASSERTION(mTracksKnownTime <= aStart, "Start time too early");
|
||||
}
|
||||
return *track;
|
||||
}
|
||||
|
||||
void AdvanceKnownTracksTime(StreamTime aKnownTime)
|
||||
{
|
||||
NS_ASSERTION(aKnownTime >= mTracksKnownTime, "Can't move tracks-known time earlier");
|
||||
mTracksKnownTime = aKnownTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* The end time for the StreamTracks is the latest time for which we have
|
||||
* data for all tracks that haven't ended by that time.
|
||||
*/
|
||||
StreamTime GetEnd() const;
|
||||
|
||||
/**
|
||||
* Returns the earliest time >= 0 at which all tracks have ended
|
||||
* and all their data has been played out and no new tracks can be added,
|
||||
* or STREAM_TIME_MAX if there is no such time.
|
||||
*/
|
||||
StreamTime GetAllTracksEnd() const;
|
||||
|
||||
#ifdef DEBUG
|
||||
void DumpTrackInfo() const;
|
||||
#endif
|
||||
|
||||
Track* FindTrack(TrackID aID);
|
||||
|
||||
class MOZ_STACK_CLASS TrackIter final
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Iterate through the tracks of aBuffer in order of ID.
|
||||
*/
|
||||
explicit TrackIter(const StreamTracks& aBuffer) :
|
||||
mBuffer(&aBuffer.mTracks), mIndex(0), mMatchType(false) {}
|
||||
/**
|
||||
* Iterate through the tracks of aBuffer with type aType, in order of ID.
|
||||
*/
|
||||
TrackIter(const StreamTracks& aBuffer, MediaSegment::Type aType) :
|
||||
mBuffer(&aBuffer.mTracks), mIndex(0), mType(aType), mMatchType(true) { FindMatch(); }
|
||||
bool IsEnded() { return mIndex >= mBuffer->Length(); }
|
||||
void Next()
|
||||
{
|
||||
++mIndex;
|
||||
FindMatch();
|
||||
}
|
||||
Track* get() { return mBuffer->ElementAt(mIndex); }
|
||||
Track& operator*() { return *mBuffer->ElementAt(mIndex); }
|
||||
Track* operator->() { return mBuffer->ElementAt(mIndex); }
|
||||
private:
|
||||
void FindMatch()
|
||||
{
|
||||
if (!mMatchType)
|
||||
return;
|
||||
while (mIndex < mBuffer->Length() &&
|
||||
mBuffer->ElementAt(mIndex)->GetType() != mType) {
|
||||
++mIndex;
|
||||
}
|
||||
}
|
||||
|
||||
const nsTArray<nsAutoPtr<Track> >* mBuffer;
|
||||
uint32_t mIndex;
|
||||
MediaSegment::Type mType;
|
||||
bool mMatchType;
|
||||
};
|
||||
friend class TrackIter;
|
||||
|
||||
/**
|
||||
* Forget stream data before aTime; they will no longer be needed.
|
||||
* Also can forget entire tracks that have ended at or before aTime.
|
||||
* Can't be used to forget beyond GetEnd().
|
||||
*/
|
||||
void ForgetUpTo(StreamTime aTime);
|
||||
/**
|
||||
* Returns the latest time passed to ForgetUpTo.
|
||||
*/
|
||||
StreamTime GetForgottenDuration()
|
||||
{
|
||||
return mForgottenTime;
|
||||
}
|
||||
|
||||
bool GetAndResetTracksDirty()
|
||||
{
|
||||
if (!mTracksDirty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mTracksDirty = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
TrackRate mGraphRate; // StreamTime per second
|
||||
// Any new tracks added will start at or after this time. In other words, the track
|
||||
// list is complete and correct for all times less than this time.
|
||||
StreamTime mTracksKnownTime;
|
||||
StreamTime mForgottenTime;
|
||||
|
||||
private:
|
||||
// All known tracks for this StreamTracks
|
||||
nsTArray<nsAutoPtr<Track>> mTracks;
|
||||
bool mTracksDirty;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool mGraphRateIsSet;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* MOZILLA_STREAMTRACKS_H_ */
|
||||
|
@ -87,14 +87,14 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
|
||||
allHaveCurrentData = false;
|
||||
}
|
||||
bool trackAdded = false;
|
||||
for (StreamBuffer::TrackIter tracks(stream->GetStreamBuffer());
|
||||
for (StreamTracks::TrackIter tracks(stream->GetStreamTracks());
|
||||
!tracks.IsEnded(); tracks.Next()) {
|
||||
bool found = false;
|
||||
for (uint32_t j = 0; j < mTrackMap.Length(); ++j) {
|
||||
TrackMapEntry* map = &mTrackMap[j];
|
||||
if (map->mInputPort == mInputs[i] && map->mInputTrackID == tracks->GetID()) {
|
||||
bool trackFinished;
|
||||
StreamBuffer::Track* outputTrack = mBuffer.FindTrack(map->mOutputTrackID);
|
||||
bool trackFinished = false;
|
||||
StreamTracks::Track* outputTrack = mTracks.FindTrack(map->mOutputTrackID);
|
||||
found = true;
|
||||
if (!outputTrack || outputTrack->IsEnded() ||
|
||||
!mInputs[i]->PassTrackThrough(tracks->GetID())) {
|
||||
@ -138,7 +138,7 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
|
||||
// so we're finished now.
|
||||
FinishOnGraphThread();
|
||||
} else {
|
||||
mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTimeWithBlocking(aTo));
|
||||
mTracks.AdvanceKnownTracksTime(GraphTimeToStreamTimeWithBlocking(aTo));
|
||||
}
|
||||
if (allHaveCurrentData) {
|
||||
// We can make progress if we're not blocked
|
||||
@ -146,7 +146,7 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t TrackUnionStream::AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack,
|
||||
uint32_t TrackUnionStream::AddTrack(MediaInputPort* aPort, StreamTracks::Track* aTrack,
|
||||
GraphTime aFrom)
|
||||
{
|
||||
STREAM_LOG(LogLevel::Verbose, ("TrackUnionStream %p adding track %d for "
|
||||
@ -205,8 +205,8 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
|
||||
aPort->GetSource(), aTrack->GetID());
|
||||
}
|
||||
segment->AppendNullData(outputStart);
|
||||
StreamBuffer::Track* track =
|
||||
&mBuffer.AddTrack(id, outputStart, segment.forget());
|
||||
StreamTracks::Track* track =
|
||||
&mTracks.AddTrack(id, outputStart, segment.forget());
|
||||
STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p added track %d for input stream %p track %d, start ticks %lld",
|
||||
this, track->GetID(), aPort->GetSource(), aTrack->GetID(),
|
||||
(long long)outputStart));
|
||||
@ -246,7 +246,7 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
|
||||
|
||||
void TrackUnionStream::EndTrack(uint32_t aIndex)
|
||||
{
|
||||
StreamBuffer::Track* outputTrack = mBuffer.FindTrack(mTrackMap[aIndex].mOutputTrackID);
|
||||
StreamTracks::Track* outputTrack = mTracks.FindTrack(mTrackMap[aIndex].mOutputTrackID);
|
||||
if (!outputTrack || outputTrack->IsEnded())
|
||||
return;
|
||||
STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p ending track %d", this, outputTrack->GetID()));
|
||||
@ -269,12 +269,12 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
|
||||
outputTrack->SetEnded();
|
||||
}
|
||||
|
||||
void TrackUnionStream::CopyTrackData(StreamBuffer::Track* aInputTrack,
|
||||
void TrackUnionStream::CopyTrackData(StreamTracks::Track* aInputTrack,
|
||||
uint32_t aMapIndex, GraphTime aFrom, GraphTime aTo,
|
||||
bool* aOutputTrackFinished)
|
||||
{
|
||||
TrackMapEntry* map = &mTrackMap[aMapIndex];
|
||||
StreamBuffer::Track* outputTrack = mBuffer.FindTrack(map->mOutputTrackID);
|
||||
StreamTracks::Track* outputTrack = mTracks.FindTrack(map->mOutputTrackID);
|
||||
MOZ_ASSERT(outputTrack && !outputTrack->IsEnded(), "Can't copy to ended track");
|
||||
|
||||
MediaSegment* segment = map->mSegment;
|
||||
|
@ -41,7 +41,7 @@ protected:
|
||||
// We keep track IDs instead of track pointers because
|
||||
// tracks can be removed without us being notified (e.g.
|
||||
// when a finished track is forgotten.) When we need a Track*,
|
||||
// we call StreamBuffer::FindTrack, which will return null if
|
||||
// we call StreamTracks::FindTrack, which will return null if
|
||||
// the track has been deleted.
|
||||
TrackID mInputTrackID;
|
||||
TrackID mOutputTrackID;
|
||||
@ -54,10 +54,10 @@ protected:
|
||||
|
||||
// Add the track to this stream, retaining its TrackID if it has never
|
||||
// been previously used in this stream, allocating a new TrackID otherwise.
|
||||
uint32_t AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack,
|
||||
uint32_t AddTrack(MediaInputPort* aPort, StreamTracks::Track* aTrack,
|
||||
GraphTime aFrom);
|
||||
void EndTrack(uint32_t aIndex);
|
||||
void CopyTrackData(StreamBuffer::Track* aInputTrack,
|
||||
void CopyTrackData(StreamTracks::Track* aInputTrack,
|
||||
uint32_t aMapIndex, GraphTime aFrom, GraphTime aTo,
|
||||
bool* aOutputTrackFinished);
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include "AudioSegment.h"
|
||||
#include "EncodedFrameContainer.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "StreamTracks.h"
|
||||
#include "TrackMetadataBase.h"
|
||||
#include "VideoSegment.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
|
@ -140,7 +140,7 @@ EXPORTS += [
|
||||
'SeekTask.h',
|
||||
'SelfRef.h',
|
||||
'SharedBuffer.h',
|
||||
'StreamBuffer.h',
|
||||
'StreamTracks.h',
|
||||
'ThreadPoolCOMListener.h',
|
||||
'TimeUnits.h',
|
||||
'TrackUnionStream.h',
|
||||
@ -244,7 +244,7 @@ UNIFIED_SOURCES += [
|
||||
'RtspMediaResource.cpp',
|
||||
'SeekJob.cpp',
|
||||
'SeekTask.cpp',
|
||||
'StreamBuffer.cpp',
|
||||
'StreamTracks.cpp',
|
||||
'TextTrack.cpp',
|
||||
'TextTrackCue.cpp',
|
||||
'TextTrackCueList.cpp',
|
||||
|
@ -685,7 +685,7 @@ skip-if = (os != 'win' || os_version == '5.1') # Only gmp-clearkey on Windows Vi
|
||||
skip-if = os == 'win' && !debug # bug 1228605
|
||||
tags=msg
|
||||
[test_mediarecorder_bitrate.html]
|
||||
skip-if = (toolkit == 'gonk' || toolkit == 'android') # B2G emulator is too slow to run this without timing out and Fennec does not support video recording
|
||||
skip-if = (toolkit == 'gonk') # B2G emulator is too slow to run this without timing out.
|
||||
tags=msg
|
||||
[test_mediarecorder_creation.html]
|
||||
tags=msg capturestream
|
||||
|
@ -152,9 +152,9 @@ AudioNodeExternalInputStream::ProcessInput(GraphTime aFrom, GraphTime aTo,
|
||||
MediaStream* source = mInputs[0]->GetSource();
|
||||
AutoTArray<AudioSegment,1> audioSegments;
|
||||
uint32_t inputChannels = 0;
|
||||
for (StreamBuffer::TrackIter tracks(source->mBuffer, MediaSegment::AUDIO);
|
||||
for (StreamTracks::TrackIter tracks(source->mTracks, MediaSegment::AUDIO);
|
||||
!tracks.IsEnded(); tracks.Next()) {
|
||||
const StreamBuffer::Track& inputTrack = *tracks;
|
||||
const StreamTracks::Track& inputTrack = *tracks;
|
||||
if (!mInputs[0]->PassTrackThrough(tracks->GetID())) {
|
||||
continue;
|
||||
}
|
||||
|
@ -384,9 +384,9 @@ public:
|
||||
void Run() override
|
||||
{
|
||||
auto ns = static_cast<AudioNodeStream*>(mStream);
|
||||
ns->mBufferStartTime -= mAdvance;
|
||||
ns->mTracksStartTime -= mAdvance;
|
||||
|
||||
StreamBuffer::Track* track = ns->EnsureTrack(AUDIO_TRACK);
|
||||
StreamTracks::Track* track = ns->EnsureTrack(AUDIO_TRACK);
|
||||
track->Get<AudioSegment>()->AppendNullData(mAdvance);
|
||||
|
||||
ns->GraphImpl()->DecrementSuspendCount(mStream);
|
||||
@ -631,9 +631,9 @@ AudioNodeStream::ProduceOutputBeforeInput(GraphTime aFrom)
|
||||
void
|
||||
AudioNodeStream::AdvanceOutputSegment()
|
||||
{
|
||||
StreamBuffer::Track* track = EnsureTrack(AUDIO_TRACK);
|
||||
StreamTracks::Track* track = EnsureTrack(AUDIO_TRACK);
|
||||
// No more tracks will be coming
|
||||
mBuffer.AdvanceKnownTracksTime(STREAM_TIME_MAX);
|
||||
mTracks.AdvanceKnownTracksTime(STREAM_TIME_MAX);
|
||||
|
||||
AudioSegment* segment = track->Get<AudioSegment>();
|
||||
|
||||
@ -656,7 +656,7 @@ AudioNodeStream::AdvanceOutputSegment()
|
||||
void
|
||||
AudioNodeStream::FinishOutput()
|
||||
{
|
||||
StreamBuffer::Track* track = EnsureTrack(AUDIO_TRACK);
|
||||
StreamTracks::Track* track = EnsureTrack(AUDIO_TRACK);
|
||||
track->SetEnded();
|
||||
|
||||
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
|
||||
|
@ -30,9 +30,9 @@ MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode(AudioContext* a
|
||||
ChannelCountMode::Explicit,
|
||||
ChannelInterpretation::Speakers)
|
||||
, mDOMStream(
|
||||
DOMAudioNodeMediaStream::CreateTrackUnionStream(GetOwner(),
|
||||
this,
|
||||
aContext->Graph()))
|
||||
DOMAudioNodeMediaStream::CreateTrackUnionStreamAsInput(GetOwner(),
|
||||
this,
|
||||
aContext->Graph()))
|
||||
{
|
||||
// Ensure an audio track with the correct ID is exposed to JS
|
||||
nsIDocument* doc = aContext->GetParentObject()->GetExtantDoc();
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "MediaEngine.h"
|
||||
#include "VideoSegment.h"
|
||||
#include "AudioSegment.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "StreamTracks.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "MediaTrackConstraints.h"
|
||||
|
||||
@ -134,7 +134,7 @@ public:
|
||||
const PrincipalHandle& aPrincipalHandle) override
|
||||
{
|
||||
#ifdef DEBUG
|
||||
StreamBuffer::Track* data = aSource->FindTrack(aId);
|
||||
StreamTracks::Track* data = aSource->FindTrack(aId);
|
||||
NS_WARN_IF_FALSE(!data || data->IsEnded() ||
|
||||
aDesiredTime <= aSource->GetEndOfAppendedData(aId),
|
||||
"MediaEngineDefaultAudioSource data underrun");
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "MediaEngineCameraVideoSource.h"
|
||||
#include "VideoSegment.h"
|
||||
#include "AudioSegment.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "StreamTracks.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
|
||||
#include "MediaEngineWrapper.h"
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include "prenv.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#endif
|
||||
|
||||
static mozilla::LogModule*
|
||||
GetUserMediaLog()
|
||||
@ -298,6 +301,16 @@ MediaEngineWebRTC::EnumerateVideoDevices(dom::MediaSourceEnum aMediaSource,
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
MediaEngineWebRTC::SupportsDuplex()
|
||||
{
|
||||
#ifndef XP_WIN
|
||||
return mFullDuplex;
|
||||
#else
|
||||
return IsVistaOrLater() && mFullDuplex;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource,
|
||||
nsTArray<RefPtr<MediaEngineAudioSource> >* aASources)
|
||||
@ -350,7 +363,7 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource,
|
||||
}
|
||||
|
||||
if (!mAudioInput) {
|
||||
if (mFullDuplex) {
|
||||
if (SupportsDuplex()) {
|
||||
// The platform_supports_full_duplex.
|
||||
mAudioInput = new mozilla::AudioInputCubeb(mVoiceEngine);
|
||||
} else {
|
||||
@ -394,7 +407,7 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource,
|
||||
aASources->AppendElement(aSource.get());
|
||||
} else {
|
||||
AudioInput* audioinput = mAudioInput;
|
||||
if (mFullDuplex) {
|
||||
if (SupportsDuplex()) {
|
||||
// The platform_supports_full_duplex.
|
||||
|
||||
// For cubeb, it has state (the selected ID)
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "MediaEngineCameraVideoSource.h"
|
||||
#include "VideoSegment.h"
|
||||
#include "AudioSegment.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "StreamTracks.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "cubeb/cubeb.h"
|
||||
#include "CubebUtils.h"
|
||||
@ -569,6 +569,9 @@ public:
|
||||
// before invoking Shutdown on this class.
|
||||
void Shutdown() override;
|
||||
|
||||
// Returns whether the host supports duplex audio stream.
|
||||
bool SupportsDuplex();
|
||||
|
||||
void EnumerateVideoDevices(dom::MediaSourceEnum,
|
||||
nsTArray<RefPtr<MediaEngineVideoSource>>*) override;
|
||||
void EnumerateAudioDevices(dom::MediaSourceEnum,
|
||||
|
@ -1,10 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1045897 - Test CSP base-uri directive</title>
|
||||
<base href="http://mochi.test">
|
||||
</head>
|
||||
<body onload='window.parent.postMessage({result: document.baseURI}, "*");'>
|
||||
<!-- just making use of the 'base' tag for this test -->
|
||||
</body>
|
||||
</html>
|
61
dom/security/test/csp/file_base_uri_server.sjs
Normal file
61
dom/security/test/csp/file_base_uri_server.sjs
Normal file
@ -0,0 +1,61 @@
|
||||
// Custom *.sjs file specifically for the needs of
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1263286
|
||||
|
||||
"use strict";
|
||||
Components.utils.importGlobalProperties(["URLSearchParams"]);
|
||||
|
||||
const PRE_BASE = `
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1045897 - Test CSP base-uri directive</title>`;
|
||||
|
||||
const REGULAR_POST_BASE =`
|
||||
</head>
|
||||
<body onload='window.parent.postMessage({result: document.baseURI}, "*");'>
|
||||
<!-- just making use of the 'base' tag for this test -->
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const SCRIPT_POST_BASE = `
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
document.getElementById("base1").removeAttribute("href");
|
||||
window.parent.postMessage({result: document.baseURI}, "*");
|
||||
</script>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
function handleRequest(request, response) {
|
||||
const query = new URLSearchParams(request.queryString);
|
||||
|
||||
// avoid confusing cache behaviors
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
|
||||
// Deliver the CSP policy encoded in the URL
|
||||
response.setHeader("Content-Security-Policy", query.get("csp"), false);
|
||||
|
||||
// Send HTML to test allowed/blocked behaviors
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.write(PRE_BASE);
|
||||
var base1 =
|
||||
"<base id=\"base1\" href=\"" + query.get("base1") + "\">";
|
||||
var base2 =
|
||||
"<base id=\"base2\" href=\"" + query.get("base2") + "\">";
|
||||
response.write(base1 + base2);
|
||||
|
||||
if (query.get("action") === "enforce-csp") {
|
||||
response.write(REGULAR_POST_BASE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (query.get("action") === "remove-base1") {
|
||||
response.write(SCRIPT_POST_BASE);
|
||||
return;
|
||||
}
|
||||
|
||||
// we should never get here, but just in case
|
||||
// return something unexpected
|
||||
response.write("do'h");
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
file_base-uri.html
|
||||
file_base_uri_server.sjs
|
||||
file_blob_data_schemes.html
|
||||
file_connect-src.html
|
||||
file_connect-src-fetch.html
|
||||
|
@ -16,30 +16,64 @@
|
||||
|
||||
/*
|
||||
* Description of the test:
|
||||
* We load a page in an iframe (served over http://example.com) that tries to set the 'base'
|
||||
* to (http://mochi.test). We load that page using different policies and verify that
|
||||
* setting the base-uri is correctly blocked by CSP.
|
||||
* We load a page in an iframe (served over http://example.com) that tries to
|
||||
* modify the 'base' either through setting or also removing the base-uri. We
|
||||
* load that page using different policies and verify that setting the base-uri
|
||||
* is correctly blocked by CSP.
|
||||
*/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var tests = [
|
||||
{
|
||||
policy: "base-uri http://mochi.test;",
|
||||
result: "http://mochi.test"
|
||||
{ csp: "base-uri http://mochi.test;",
|
||||
base1: "http://mochi.test",
|
||||
base2: "",
|
||||
action: "enforce-csp",
|
||||
result: "http://mochi.test",
|
||||
desc: "CSP allows base uri"
|
||||
},
|
||||
{
|
||||
policy: "base-uri http://example.com;",
|
||||
result: "http://example.com"
|
||||
{ csp: "base-uri http://example.com;",
|
||||
base1: "http://mochi.test",
|
||||
base2: "",
|
||||
action: "enforce-csp",
|
||||
result: "http://example.com",
|
||||
desc: "CSP blocks base uri"
|
||||
},
|
||||
{
|
||||
policy: "base-uri https:",
|
||||
result: "http://example.com"
|
||||
{ csp: "base-uri https:",
|
||||
base1: "http://mochi.test",
|
||||
base2: "",
|
||||
action: "enforce-csp",
|
||||
result: "http://example.com",
|
||||
desc: "CSP blocks http base"
|
||||
},
|
||||
{ csp: "base-uri 'none'",
|
||||
base1: "http://mochi.test",
|
||||
base2: "",
|
||||
action: "enforce-csp",
|
||||
result: "http://example.com",
|
||||
desc: "CSP allows no base modification"
|
||||
},
|
||||
{ csp: "",
|
||||
base1: "http://foo:foo/",
|
||||
base2: "",
|
||||
action: "enforce-csp",
|
||||
result: "http://example.com",
|
||||
desc: "Invalid base should be ignored"
|
||||
},
|
||||
{ csp: "base-uri http://mochi.test",
|
||||
base1: "http://mochi.test",
|
||||
base2: "http://test1.example.com",
|
||||
action: "remove-base1",
|
||||
result: "http://example.com",
|
||||
desc: "Removing first base should result in fallback base"
|
||||
},
|
||||
{ csp: "",
|
||||
base1: "http://mochi.test",
|
||||
base2: "http://test1.example.com",
|
||||
action: "remove-base1",
|
||||
result: "http://test1.example.com",
|
||||
desc: "Removing first base should result in the second base"
|
||||
},
|
||||
{
|
||||
policy: "base-uri 'none'",
|
||||
result: "http://example.com"
|
||||
}
|
||||
];
|
||||
|
||||
// initializing to -1 so we start at index 0 when we start the test
|
||||
@ -57,7 +91,9 @@ function receiveMessage(event) {
|
||||
var result = event.data.result;
|
||||
// we only care about the base uri, so instead of comparing the complete uri
|
||||
// we just make sure that the base is correct which is sufficient here.
|
||||
ok(result.startsWith(tests[counter].result), "Restricting base-uri in test " + counter + "!");
|
||||
ok(result.startsWith(tests[counter].result),
|
||||
`${tests[counter].desc}: Expected a base URI that starts
|
||||
with ${tests[counter].result} but got ${result}`);
|
||||
loadNextTest();
|
||||
}
|
||||
|
||||
@ -67,12 +103,16 @@ function loadNextTest() {
|
||||
finishTest();
|
||||
return;
|
||||
}
|
||||
var src = "http://example.com/tests/dom/security/test/csp/file_testserver.sjs";
|
||||
// append the file that should be served
|
||||
src += "?file=" + escape("tests/dom/security/test/csp/file_base-uri.html");
|
||||
var src = "http://example.com/tests/dom/security/test/csp/file_base_uri_server.sjs";
|
||||
// append the CSP that should be used to serve the file
|
||||
// please note that we have to include 'unsafe-inline' to permit sending the postMessage
|
||||
src += "&csp=" + escape("script-src 'unsafe-inline'; " + tests[counter].policy);
|
||||
src += "?csp=" + escape("script-src 'unsafe-inline'; " + tests[counter].csp);
|
||||
// append potential base tags
|
||||
src += "&base1=" + escape(tests[counter].base1);
|
||||
src += "&base2=" + escape(tests[counter].base2);
|
||||
// append potential action
|
||||
src += "&action=" + escape(tests[counter].action);
|
||||
|
||||
document.getElementById("testframe").src = src;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,10 @@
|
||||
<title>Test for Utility Methods for other FIDO Universal Second Factor tests</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/u2f/tests/u2futil.js"></script>
|
||||
<script type="text/javascript" src="pkijs/common.js"></script>
|
||||
<script type="text/javascript" src="pkijs/asn1.js"></script>
|
||||
<script type="text/javascript" src="pkijs/x509_schema.js"></script>
|
||||
<script type="text/javascript" src="pkijs/x509_simpl.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -130,29 +130,33 @@ function assembleRegistrationSignedData(appParam, challengeParam, keyHandle, pub
|
||||
return signedData;
|
||||
}
|
||||
|
||||
function verifySignature(key, data, derSig) {
|
||||
if (derSig.byteLength < 70) {
|
||||
console.log("bad sig: " + hexEncode(derSig))
|
||||
throw "Invalid signature length: " + derSig.byteLength;
|
||||
function sanitizeSigArray(arr) {
|
||||
// ECDSA signature fields into WebCrypto must be exactly 32 bytes long, so
|
||||
// this method strips leading padding bytes, if added, and also appends
|
||||
// padding zeros, if needed.
|
||||
if (arr.length > 32) {
|
||||
arr = arr.slice(arr.length - 32)
|
||||
}
|
||||
var ret = new Uint8Array(32);
|
||||
ret.set(arr, ret.length - arr.length);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Poor man's ASN.1 decode
|
||||
// R and S are always 32 bytes. If ether has a DER
|
||||
// length > 32, it's just zeros we can chop off.
|
||||
var lenR = derSig[3];
|
||||
var lenS = derSig[3 + lenR + 2];
|
||||
var padR = lenR - 32;
|
||||
var padS = lenS - 32;
|
||||
var sig = new Uint8Array(64);
|
||||
derSig.slice(4 + padR, 4 + lenR).map((x, i) => sig[i] = x);
|
||||
derSig.slice(4 + lenR + 2 + padS, 4 + lenR + 2 + lenS).map(
|
||||
(x, i) => sig[32 + i] = x
|
||||
);
|
||||
function verifySignature(key, data, derSig) {
|
||||
var sigAsn1 = org.pkijs.fromBER(derSig.buffer);
|
||||
var sigR = new Uint8Array(sigAsn1.result.value_block.value[0].value_block.value_hex);
|
||||
var sigS = new Uint8Array(sigAsn1.result.value_block.value[1].value_block.value_hex);
|
||||
|
||||
console.log("data: " + hexEncode(data));
|
||||
console.log("der: " + hexEncode(derSig));
|
||||
console.log("raw: " + hexEncode(sig));
|
||||
// The resulting R and S values from the ASN.1 Sequence must be fit into 32
|
||||
// bytes. Sometimes they have leading zeros, sometimes they're too short, it
|
||||
// all depends on what lib generated the signature.
|
||||
var R = sanitizeSigArray(sigR);
|
||||
var S = sanitizeSigArray(sigS);
|
||||
|
||||
var sigData = new Uint8Array(R.length + S.length);
|
||||
sigData.set(R);
|
||||
sigData.set(S, R.length);
|
||||
|
||||
var alg = {name: "ECDSA", hash: "SHA-256"};
|
||||
return crypto.subtle.verify(alg, key, sig, data);
|
||||
return crypto.subtle.verify(alg, key, sigData, data);
|
||||
}
|
||||
|
@ -10,6 +10,16 @@
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
|
||||
dictionary EventListenerOptions {
|
||||
boolean capture = false;
|
||||
};
|
||||
|
||||
dictionary AddEventListenerOptions : EventListenerOptions {
|
||||
boolean passive = false;
|
||||
boolean once = false;
|
||||
};
|
||||
|
||||
[Exposed=(Window,Worker,WorkerDebugger,System)]
|
||||
interface EventTarget {
|
||||
/* Passing null for wantsUntrusted means "default behavior", which
|
||||
@ -19,12 +29,12 @@ interface EventTarget {
|
||||
[Throws]
|
||||
void addEventListener(DOMString type,
|
||||
EventListener? listener,
|
||||
optional boolean capture = false,
|
||||
optional (AddEventListenerOptions or boolean) options,
|
||||
optional boolean? wantsUntrusted = null);
|
||||
[Throws]
|
||||
void removeEventListener(DOMString type,
|
||||
EventListener? listener,
|
||||
optional boolean capture = false);
|
||||
optional (EventListenerOptions or boolean) options);
|
||||
[Throws]
|
||||
boolean dispatchEvent(Event event);
|
||||
};
|
||||
|
2
dom/workers/test/serviceworkers/bug1240436_worker.js
Normal file
2
dom/workers/test/serviceworkers/bug1240436_worker.js
Normal file
@ -0,0 +1,2 @@
|
||||
// a contains a ZERO WIDTH JOINER (0x200D)
|
||||
var a = "";
|
@ -127,6 +127,7 @@ support-files =
|
||||
importscript_worker.js
|
||||
bug1151916_worker.js
|
||||
bug1151916_driver.html
|
||||
bug1240436_worker.js
|
||||
notificationclick.html
|
||||
notificationclick-otherwindow.html
|
||||
notificationclick.js
|
||||
@ -204,6 +205,7 @@ support-files =
|
||||
!/dom/tests/mochitest/notification/NotificationTest.js
|
||||
|
||||
[test_bug1151916.html]
|
||||
[test_bug1240436.html]
|
||||
[test_claim.html]
|
||||
[test_claim_fetch.html]
|
||||
[test_claim_oninstall.html]
|
||||
|
34
dom/workers/test/serviceworkers/test_bug1240436.html
Normal file
34
dom/workers/test/serviceworkers/test_bug1240436.html
Normal file
@ -0,0 +1,34 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for encoding of service workers</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTest() {
|
||||
navigator.serviceWorker.register("bug1240436_worker.js")
|
||||
.then(reg => reg.unregister())
|
||||
.then(() => ok(true, "service worker register script succeed"))
|
||||
.catch(err => ok(false, "service worker register script faled " + err))
|
||||
.then(() => SimpleTest.finish());
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -1035,7 +1035,7 @@ nsHTMLEditor::UpdateBaseURL()
|
||||
// If no base tag, then set baseURL to the document's URL. This is very
|
||||
// important, else relative URLs for links and images are wrong
|
||||
if (!nodeList || !nodeList->Item(0)) {
|
||||
return doc->SetBaseURI(doc->GetDocumentURI());
|
||||
doc->SetBaseURI(doc->GetDocumentURI());
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -195,6 +195,31 @@ BufferTextureData::CreateForYCbCr(ClientIPCAllocator* aAllocator,
|
||||
aTextureFlags);
|
||||
}
|
||||
|
||||
void
|
||||
BufferTextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
{
|
||||
aInfo.size = GetSize();
|
||||
aInfo.format = GetFormat();
|
||||
aInfo.hasSynchronization = false;
|
||||
aInfo.canExposeMappedData = true;
|
||||
|
||||
if (mDescriptor.type() == BufferDescriptor::TYCbCrDescriptor) {
|
||||
aInfo.hasIntermediateBuffer = true;
|
||||
} else {
|
||||
aInfo.hasIntermediateBuffer = mDescriptor.get_RGBDescriptor().hasIntermediateBuffer();
|
||||
}
|
||||
|
||||
switch (aInfo.format) {
|
||||
case gfx::SurfaceFormat::YUV:
|
||||
case gfx::SurfaceFormat::NV12:
|
||||
case gfx::SurfaceFormat::UNKNOWN:
|
||||
aInfo.supportsMoz2D = false;
|
||||
break;
|
||||
default:
|
||||
aInfo.supportsMoz2D = true;
|
||||
}
|
||||
}
|
||||
|
||||
gfx::IntSize
|
||||
BufferTextureData::GetSize() const
|
||||
{
|
||||
@ -207,29 +232,6 @@ BufferTextureData::GetFormat() const
|
||||
return ImageDataSerializer::FormatFromBufferDescriptor(mDescriptor);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BufferTextureData::HasIntermediateBuffer() const
|
||||
{
|
||||
if (mDescriptor.type() == BufferDescriptor::TYCbCrDescriptor) {
|
||||
return true;
|
||||
}
|
||||
return mDescriptor.get_RGBDescriptor().hasIntermediateBuffer();
|
||||
}
|
||||
|
||||
bool
|
||||
BufferTextureData::SupportsMoz2D() const
|
||||
{
|
||||
switch (GetFormat()) {
|
||||
case gfx::SurfaceFormat::YUV:
|
||||
case gfx::SurfaceFormat::NV12:
|
||||
case gfx::SurfaceFormat::UNKNOWN:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DrawTarget>
|
||||
BufferTextureData::BorrowDrawTarget()
|
||||
{
|
||||
|
@ -41,22 +41,14 @@ public:
|
||||
|
||||
virtual void Unlock() override {}
|
||||
|
||||
virtual gfx::IntSize GetSize() const override;
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override;
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const override;
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
|
||||
|
||||
virtual bool CanExposeMappedData() const override { return true; }
|
||||
|
||||
virtual bool BorrowMappedData(MappedTextureData& aMap) override;
|
||||
|
||||
virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap) override;
|
||||
|
||||
virtual bool SupportsMoz2D() const override;
|
||||
|
||||
virtual bool HasIntermediateBuffer() const override;
|
||||
|
||||
// use TextureClient's default implementation
|
||||
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
|
||||
|
||||
@ -64,6 +56,10 @@ public:
|
||||
void SetDesciptor(const BufferDescriptor& aDesc);
|
||||
|
||||
protected:
|
||||
gfx::IntSize GetSize() const;
|
||||
|
||||
gfx::SurfaceFormat GetFormat() const;
|
||||
|
||||
static BufferTextureData* CreateInternal(ClientIPCAllocator* aAllocator,
|
||||
const BufferDescriptor& aDesc,
|
||||
gfx::BackendType aMoz2DBackend,
|
||||
|
@ -117,6 +117,17 @@ public:
|
||||
HBITMAP mBitmap;
|
||||
};
|
||||
|
||||
void
|
||||
DIBTextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
{
|
||||
aInfo.size = mSize;
|
||||
aInfo.format = mFormat;
|
||||
aInfo.hasIntermediateBuffer = true;
|
||||
aInfo.hasSynchronization = false;
|
||||
aInfo.supportsMoz2D = true;
|
||||
aInfo.canExposeMappedData = false;
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DrawTarget>
|
||||
DIBTextureData::BorrowDrawTarget()
|
||||
{
|
||||
@ -257,7 +268,7 @@ ShmemDIBTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
|
||||
bool
|
||||
ShmemDIBTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
if (GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
|
||||
if (mFormat == gfx::SurfaceFormat::UNKNOWN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -22,16 +22,10 @@ public:
|
||||
|
||||
virtual void Unlock() override {}
|
||||
|
||||
virtual gfx::IntSize GetSize() const override { return mSize; }
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
|
||||
virtual bool SupportsMoz2D() const override { return true; }
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const override;
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
|
||||
|
||||
virtual bool HasIntermediateBuffer() const override { return true; }
|
||||
|
||||
static
|
||||
DIBTextureData* Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
ClientIPCAllocator* aAllocator);
|
||||
|
@ -36,14 +36,6 @@ public:
|
||||
*/
|
||||
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
|
||||
|
||||
/**
|
||||
* Acknowledges the recipt of a scroll offset update for the scrollable
|
||||
* frame with the given scroll id. This is used to maintain consistency
|
||||
* between APZ and other sources of scroll changes.
|
||||
*/
|
||||
virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration) = 0;
|
||||
|
||||
/**
|
||||
* Requests handling of a double tap. |aPoint| is in CSS pixels, relative to
|
||||
* the current scroll offset. This should eventually round-trip back to
|
||||
|
@ -3456,9 +3456,6 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe
|
||||
CancelAnimation();
|
||||
|
||||
mScrollMetadata = aScrollMetadata;
|
||||
if (scrollOffsetUpdated) {
|
||||
AcknowledgeScrollUpdate();
|
||||
}
|
||||
mExpectedGeckoMetrics = aLayerMetrics;
|
||||
ShareCompositorFrameMetrics();
|
||||
|
||||
@ -3532,7 +3529,6 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe
|
||||
// correct this we need to update mExpectedGeckoMetrics to be the
|
||||
// last thing we know was painted by Gecko.
|
||||
mFrameMetrics.CopyScrollInfoFrom(aLayerMetrics);
|
||||
AcknowledgeScrollUpdate();
|
||||
mExpectedGeckoMetrics = aLayerMetrics;
|
||||
|
||||
// Cancel the animation (which might also trigger a repaint request)
|
||||
@ -3564,7 +3560,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe
|
||||
// See comment on the similar code in the |if (scrollOffsetUpdated)| block
|
||||
// above.
|
||||
mFrameMetrics.CopySmoothScrollInfoFrom(aLayerMetrics);
|
||||
AcknowledgeScrollUpdate();
|
||||
needContentRepaint = true;
|
||||
mExpectedGeckoMetrics = aLayerMetrics;
|
||||
|
||||
SmoothScrollTo(mFrameMetrics.GetSmoothScrollOffset());
|
||||
@ -3576,21 +3572,6 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
}
|
||||
|
||||
void
|
||||
AsyncPanZoomController::AcknowledgeScrollUpdate() const
|
||||
{
|
||||
// Once layout issues a scroll offset update, it becomes impervious to
|
||||
// scroll offset updates from APZ until we acknowledge the update it sent.
|
||||
// This prevents APZ updates from clobbering scroll updates from other
|
||||
// more "legitimate" sources like content scripts.
|
||||
RefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (controller) {
|
||||
APZC_LOG("%p sending scroll update acknowledgement with gen %u\n", this, mFrameMetrics.GetScrollGeneration());
|
||||
controller->AcknowledgeScrollUpdate(mFrameMetrics.GetScrollId(),
|
||||
mFrameMetrics.GetScrollGeneration());
|
||||
}
|
||||
}
|
||||
|
||||
const FrameMetrics& AsyncPanZoomController::GetFrameMetrics() const {
|
||||
mMonitor.AssertCurrentThreadIn();
|
||||
return mFrameMetrics;
|
||||
|
@ -896,8 +896,6 @@ private:
|
||||
// Returns whether overscroll is allowed during an event.
|
||||
bool AllowScrollHandoffInCurrentBlock() const;
|
||||
|
||||
void AcknowledgeScrollUpdate() const;
|
||||
|
||||
/* ===================================================================
|
||||
* The functions and members in this section are used to make ancestor chains
|
||||
* out of APZC instances. These chains can only be walked or manipulated
|
||||
|
@ -124,9 +124,9 @@ ScrollFrame(nsIContent* aContent,
|
||||
// Scroll the window to the desired spot
|
||||
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId());
|
||||
if (sf) {
|
||||
sf->ResetScrollInfoIfGeneration(aMetrics.GetScrollGeneration());
|
||||
sf->SetScrollableByAPZ(!aMetrics.IsScrollInfoLayer());
|
||||
}
|
||||
|
||||
bool scrollUpdated = false;
|
||||
CSSPoint apzScrollOffset = aMetrics.GetScrollOffset();
|
||||
CSSPoint actualScrollOffset = ScrollFrameTo(sf, apzScrollOffset, scrollUpdated);
|
||||
@ -330,54 +330,6 @@ APZCCallbackHelper::InitializeRootDisplayport(nsIPresShell* aPresShell)
|
||||
}
|
||||
}
|
||||
|
||||
class AcknowledgeScrollUpdateEvent : public Runnable
|
||||
{
|
||||
typedef mozilla::layers::FrameMetrics::ViewID ViewID;
|
||||
|
||||
public:
|
||||
AcknowledgeScrollUpdateEvent(const ViewID& aScrollId, const uint32_t& aScrollGeneration)
|
||||
: mScrollId(aScrollId)
|
||||
, mScrollGeneration(aScrollGeneration)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(mScrollId);
|
||||
if (sf) {
|
||||
sf->ResetScrollInfoIfGeneration(mScrollGeneration);
|
||||
}
|
||||
|
||||
// Since the APZ and content are in sync, we need to clear any callback transform
|
||||
// that might have been set on the last repaint request (which might have failed
|
||||
// due to the inflight scroll update that this message is acknowledging).
|
||||
nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(mScrollId);
|
||||
if (content) {
|
||||
content->SetProperty(nsGkAtoms::apzCallbackTransform, new CSSPoint(),
|
||||
nsINode::DeleteProperty<CSSPoint>);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
ViewID mScrollId;
|
||||
uint32_t mScrollGeneration;
|
||||
};
|
||||
|
||||
void
|
||||
APZCCallbackHelper::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> r1 = new AcknowledgeScrollUpdateEvent(aScrollId, aScrollGeneration);
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_DispatchToMainThread(r1);
|
||||
} else {
|
||||
r1->Run();
|
||||
}
|
||||
}
|
||||
|
||||
nsIPresShell*
|
||||
APZCCallbackHelper::GetRootContentDocumentPresShellForContent(nsIContent* aContent)
|
||||
{
|
||||
|
@ -66,11 +66,6 @@ public:
|
||||
given presShell. */
|
||||
static void InitializeRootDisplayport(nsIPresShell* aPresShell);
|
||||
|
||||
/* Tell layout that we received the scroll offset update for the given view ID, so
|
||||
that it accepts future scroll offset updates from APZ. */
|
||||
static void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration);
|
||||
|
||||
/* Get the pres shell associated with the root content document enclosing |aContent|. */
|
||||
static nsIPresShell* GetRootContentDocumentPresShellForContent(nsIContent* aContent);
|
||||
|
||||
|
@ -68,13 +68,6 @@ ChromeProcessController::PostDelayedTask(Task* aTask, int aDelayMs)
|
||||
MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs);
|
||||
}
|
||||
|
||||
void
|
||||
ChromeProcessController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration)
|
||||
{
|
||||
APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
|
||||
}
|
||||
|
||||
void
|
||||
ChromeProcessController::Destroy()
|
||||
{
|
||||
|
@ -40,9 +40,6 @@ public:
|
||||
// GeckoContentController interface
|
||||
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override;
|
||||
virtual void PostDelayedTask(Task* aTask, int aDelayMs) override;
|
||||
virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration) override;
|
||||
|
||||
virtual void HandleDoubleTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
|
||||
const ScrollableLayerGuid& aGuid) override;
|
||||
virtual void HandleSingleTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
|
||||
|
@ -47,6 +47,16 @@ X11TextureData::Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
X11TextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
{
|
||||
aInfo.size = mSize;
|
||||
aInfo.format = mFormat;
|
||||
aInfo.supportsMoz2D = true;
|
||||
aInfo.hasIntermediateBuffer = false;
|
||||
aInfo.hasSynchronization = false;
|
||||
aInfo.canExposeMappedData = false;
|
||||
}
|
||||
|
||||
bool
|
||||
X11TextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
|
@ -25,16 +25,10 @@ public:
|
||||
|
||||
virtual void Unlock() override;
|
||||
|
||||
virtual gfx::IntSize GetSize() const override { return mSize; }
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const override;
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
|
||||
|
||||
virtual bool SupportsMoz2D() const override { return true; }
|
||||
|
||||
virtual bool HasIntermediateBuffer() const override { return false; }
|
||||
|
||||
virtual void Deallocate(ClientIPCAllocator*) override;
|
||||
|
||||
virtual TextureData*
|
||||
|
@ -73,7 +73,7 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (backend == LayersBackend::LAYERS_D3D11) {
|
||||
useDoubleBuffering = gfxWindowsPlatform::GetPlatform()->GetRenderMode() == gfxWindowsPlatform::RENDER_DIRECT2D;
|
||||
useDoubleBuffering = gfxWindowsPlatform::GetPlatform()->IsDirect2DBackend();
|
||||
} else
|
||||
#endif
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
|
@ -97,7 +97,6 @@ public:
|
||||
|
||||
TextureChild()
|
||||
: mForwarder(nullptr)
|
||||
, mMonitor("TextureChild")
|
||||
, mTextureClient(nullptr)
|
||||
, mTextureData(nullptr)
|
||||
, mDestroyed(false)
|
||||
@ -117,10 +116,10 @@ public:
|
||||
|
||||
void WaitForCompositorRecycle()
|
||||
{
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mWaitForRecycle = mDestroyed ? nullptr : mTextureClient;
|
||||
}
|
||||
Lock();
|
||||
mWaitForRecycle = mDestroyed ? nullptr : mTextureClient;
|
||||
Unlock();
|
||||
|
||||
RECYCLE_LOG("[CLIENT] Wait for recycle %p\n", mWaitForRecycle.get());
|
||||
MOZ_ASSERT(CanSend());
|
||||
SendClientRecycle();
|
||||
@ -129,10 +128,10 @@ public:
|
||||
void CancelWaitForCompositorRecycle()
|
||||
{
|
||||
RECYCLE_LOG("[CLIENT] Cancelling wait for recycle %p\n", mWaitForRecycle.get());
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mWaitForRecycle = nullptr;
|
||||
}
|
||||
|
||||
Lock();
|
||||
mWaitForRecycle = nullptr;
|
||||
Unlock();
|
||||
}
|
||||
|
||||
CompositableForwarder* GetForwarder() { return mForwarder; }
|
||||
@ -143,6 +142,10 @@ public:
|
||||
|
||||
bool IPCOpen() const { return mIPCOpen; }
|
||||
|
||||
void Lock() const { mLock.Enter(); }
|
||||
|
||||
void Unlock() const { mLock.Leave(); }
|
||||
|
||||
private:
|
||||
|
||||
// AddIPDLReference and ReleaseIPDLReference are only to be called by CreateIPDLActor
|
||||
@ -160,16 +163,11 @@ private:
|
||||
Release();
|
||||
}
|
||||
|
||||
void SetTextureClient(TextureClient* aTextureClient) {
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mTextureClient = aTextureClient;
|
||||
}
|
||||
mutable gfx::CriticalSection mLock;
|
||||
|
||||
RefPtr<CompositableForwarder> mForwarder;
|
||||
RefPtr<TextureClient> mWaitForRecycle;
|
||||
|
||||
// Monitor protecting mTextureClient.
|
||||
Monitor mMonitor;
|
||||
TextureClient* mTextureClient;
|
||||
TextureData* mTextureData;
|
||||
Atomic<bool> mDestroyed;
|
||||
@ -320,12 +318,15 @@ DeallocateTextureClient(TextureDeallocParams params)
|
||||
|
||||
void TextureClient::Destroy(bool aForceSync)
|
||||
{
|
||||
MOZ_ASSERT(!IsLocked());
|
||||
if (mActor) {
|
||||
mActor->Lock();
|
||||
}
|
||||
|
||||
RefPtr<TextureChild> actor = mActor;
|
||||
mActor = nullptr;
|
||||
|
||||
if (actor && !actor->mDestroyed.compareExchange(false, true)) {
|
||||
actor->Unlock();
|
||||
actor = nullptr;
|
||||
}
|
||||
|
||||
@ -349,6 +350,14 @@ void TextureClient::Destroy(bool aForceSync)
|
||||
// client side, but having asynchronous deallocate in some of the cases will
|
||||
// be a worthwhile optimization.
|
||||
params.syncDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT) || aForceSync;
|
||||
|
||||
// Release the lock before calling DeallocateTextureClient because the latter
|
||||
// may wait for the main thread which could create a dead-lock.
|
||||
|
||||
if (actor) {
|
||||
actor->Unlock();
|
||||
}
|
||||
|
||||
DeallocateTextureClient(params);
|
||||
}
|
||||
}
|
||||
@ -361,6 +370,22 @@ TextureClient::DestroyFallback(PTextureChild* aActor)
|
||||
return aActor->SendDestroySync();
|
||||
}
|
||||
|
||||
void
|
||||
TextureClient::LockActor() const
|
||||
{
|
||||
if (mActor) {
|
||||
mActor->Lock();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TextureClient::UnlockActor() const
|
||||
{
|
||||
if (mActor) {
|
||||
mActor->Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TextureClient::Lock(OpenMode aMode)
|
||||
{
|
||||
@ -375,6 +400,8 @@ TextureClient::Lock(OpenMode aMode)
|
||||
mRemoveFromCompositableWaiter = nullptr;
|
||||
}
|
||||
|
||||
LockActor();
|
||||
|
||||
mIsLocked = mData->Lock(aMode, mReleaseFenceHandle.IsValid() ? &mReleaseFenceHandle : nullptr);
|
||||
mOpenMode = aMode;
|
||||
|
||||
@ -396,6 +423,10 @@ TextureClient::Lock(OpenMode aMode)
|
||||
}
|
||||
}
|
||||
|
||||
if (!mIsLocked) {
|
||||
UnlockActor();
|
||||
}
|
||||
|
||||
return mIsLocked;
|
||||
}
|
||||
|
||||
@ -426,27 +457,8 @@ TextureClient::Unlock()
|
||||
mData->Unlock();
|
||||
mIsLocked = false;
|
||||
mOpenMode = OpenMode::OPEN_NONE;
|
||||
}
|
||||
|
||||
bool
|
||||
TextureClient::HasIntermediateBuffer() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
return mData->HasIntermediateBuffer();
|
||||
}
|
||||
|
||||
gfx::IntSize
|
||||
TextureClient::GetSize() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
return mData->GetSize();
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat
|
||||
TextureClient::GetFormat() const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
return mData->GetFormat();
|
||||
UnlockActor();
|
||||
}
|
||||
|
||||
TextureClient::~TextureClient()
|
||||
@ -491,7 +503,16 @@ already_AddRefed<TextureClient>
|
||||
TextureClient::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
MOZ_ASSERT(!mIsLocked);
|
||||
if (mIsLocked) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LockActor();
|
||||
TextureData* data = mData->CreateSimilar(mAllocator, aFlags, aAllocFlags);
|
||||
UnlockActor();
|
||||
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -539,21 +560,23 @@ TextureClient::BorrowMappedData(MappedTextureData& aMap)
|
||||
// return nullptr;
|
||||
//}
|
||||
|
||||
return mData->BorrowMappedData(aMap);
|
||||
return mData ? mData->BorrowMappedData(aMap) : false;
|
||||
}
|
||||
|
||||
bool
|
||||
TextureClient::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
return mData->BorrowMappedYCbCrData(aMap);
|
||||
|
||||
return mData ? mData->BorrowMappedYCbCrData(aMap) : false;
|
||||
}
|
||||
|
||||
bool
|
||||
TextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
return mData->Serialize(aOutDescriptor);
|
||||
|
||||
return mData ? mData->Serialize(aOutDescriptor) : false;
|
||||
}
|
||||
|
||||
void
|
||||
@ -590,18 +613,29 @@ TextureClient::DestroyIPDLActor(PTextureChild* actor)
|
||||
}
|
||||
|
||||
// static
|
||||
TextureClient*
|
||||
already_AddRefed<TextureClient>
|
||||
TextureClient::AsTextureClient(PTextureChild* actor)
|
||||
{
|
||||
if (!actor) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TextureChild* tc = static_cast<TextureChild*>(actor);
|
||||
|
||||
// TODO: This is not entirely race-free because TextureClient's ref count
|
||||
// can reach zero on another thread and AsTextureClient gets called before
|
||||
// Destroy.
|
||||
tc->Lock();
|
||||
|
||||
if (tc->mDestroyed) {
|
||||
tc->Unlock();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return tc->mTextureClient;
|
||||
RefPtr<TextureClient> texture = tc->mTextureClient;
|
||||
tc->Unlock();
|
||||
|
||||
return texture.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -635,6 +669,12 @@ void
|
||||
TextureClient::RecycleTexture(TextureFlags aFlags)
|
||||
{
|
||||
MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE);
|
||||
MOZ_ASSERT(!mIsLocked);
|
||||
if (mIsLocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
LockActor();
|
||||
|
||||
mAddedToCompositableClient = false;
|
||||
if (mFlags != aFlags) {
|
||||
@ -643,6 +683,8 @@ TextureClient::RecycleTexture(TextureFlags aFlags)
|
||||
mActor->SendRecycleTexture(mFlags);
|
||||
}
|
||||
}
|
||||
|
||||
UnlockActor();
|
||||
}
|
||||
|
||||
void
|
||||
@ -706,6 +748,13 @@ TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
|
||||
mActor->mForwarder = aForwarder;
|
||||
mActor->mTextureClient = this;
|
||||
mActor->mMainThreadOnly = !!(mFlags & TextureFlags::DEALLOCATE_MAIN_THREAD);
|
||||
|
||||
// If the TextureClient is already locked, we have to lock TextureChild's mutex
|
||||
// since it will be unlocked in TextureClient::Unlock.
|
||||
if (mIsLocked) {
|
||||
LockActor();
|
||||
}
|
||||
|
||||
return mActor->IPCOpen();
|
||||
}
|
||||
|
||||
@ -922,6 +971,7 @@ TextureClient::TextureClient(TextureData* aData, TextureFlags aFlags, ClientIPCA
|
||||
, mPoolTracker(nullptr)
|
||||
#endif
|
||||
{
|
||||
mData->FillInfo(mInfo);
|
||||
mFlags |= mData->GetTextureFlags();
|
||||
}
|
||||
|
||||
@ -984,6 +1034,22 @@ TextureClient::SetRemoveFromCompositableWaiter(AsyncTransactionWaiter* aWaiter)
|
||||
mRemoveFromCompositableWaiter = aWaiter;
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DataSourceSurface>
|
||||
TextureClient::GetAsSurface()
|
||||
{
|
||||
Lock(OpenMode::OPEN_READ);
|
||||
RefPtr<gfx::DataSourceSurface> data;
|
||||
RefPtr<gfx::DrawTarget> dt = BorrowDrawTarget();
|
||||
if (dt) {
|
||||
RefPtr<gfx::SourceSurface> surf = dt->Snapshot();
|
||||
if (surf) {
|
||||
data = surf->GetDataSurface();
|
||||
}
|
||||
}
|
||||
Unlock();
|
||||
return data.forget();
|
||||
}
|
||||
|
||||
void
|
||||
TextureClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
||||
{
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "mozilla/gfx/CriticalSection.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsISupportsImpl.h" // for TextureImage::AddRef, etc
|
||||
@ -181,26 +182,33 @@ class D3D11TextureData;
|
||||
|
||||
class TextureData {
|
||||
public:
|
||||
struct Info {
|
||||
gfx::IntSize size;
|
||||
gfx::SurfaceFormat format;
|
||||
bool hasIntermediateBuffer;
|
||||
bool hasSynchronization;
|
||||
bool supportsMoz2D;
|
||||
bool canExposeMappedData;
|
||||
|
||||
Info()
|
||||
: format(gfx::SurfaceFormat::UNKNOWN)
|
||||
, hasIntermediateBuffer(false)
|
||||
, hasSynchronization(false)
|
||||
, supportsMoz2D(false)
|
||||
, canExposeMappedData(false)
|
||||
{}
|
||||
};
|
||||
|
||||
TextureData() { MOZ_COUNT_CTOR(TextureData); }
|
||||
|
||||
virtual ~TextureData() { MOZ_COUNT_DTOR(TextureData); }
|
||||
|
||||
virtual gfx::IntSize GetSize() const = 0;
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const = 0;
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const = 0;
|
||||
|
||||
virtual bool Lock(OpenMode aMode, FenceHandle* aFence) = 0;
|
||||
|
||||
virtual void Unlock() = 0;
|
||||
|
||||
virtual bool SupportsMoz2D() const { return false; }
|
||||
|
||||
virtual bool CanExposeMappedData() const { return false; }
|
||||
|
||||
virtual bool HasIntermediateBuffer() const = 0;
|
||||
|
||||
virtual bool HasSynchronization() const { return false; }
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() { return nullptr; }
|
||||
|
||||
virtual bool BorrowMappedData(MappedTextureData&) { return false; }
|
||||
@ -327,9 +335,29 @@ public:
|
||||
|
||||
bool IsLocked() const { return mIsLocked; }
|
||||
|
||||
bool CanExposeDrawTarget() const { return mData->SupportsMoz2D(); }
|
||||
gfx::IntSize GetSize() const { return mInfo.size; }
|
||||
|
||||
bool CanExposeMappedData() const { return mData->CanExposeMappedData(); }
|
||||
gfx::SurfaceFormat GetFormat() const { return mInfo.format; }
|
||||
|
||||
/**
|
||||
* Returns true if this texture has a synchronization mechanism (mutex, fence, etc.).
|
||||
* Textures that do not implement synchronization should be immutable or should
|
||||
* use immediate uploads (see TextureFlags in CompositorTypes.h)
|
||||
* Even if a texture does not implement synchronization, Lock and Unlock need
|
||||
* to be used appropriately since the latter are also there to map/numap data.
|
||||
*/
|
||||
bool HasSynchronization() const { return mInfo.hasSynchronization; }
|
||||
|
||||
/**
|
||||
* Indicates whether the TextureClient implementation is backed by an
|
||||
* in-memory buffer. The consequence of this is that locking the
|
||||
* TextureClient does not contend with locking the texture on the host side.
|
||||
*/
|
||||
bool HasIntermediateBuffer() const { return mInfo.hasIntermediateBuffer; }
|
||||
|
||||
bool CanExposeDrawTarget() const { return mInfo.supportsMoz2D; }
|
||||
|
||||
bool CanExposeMappedData() const { return mInfo.canExposeMappedData; }
|
||||
|
||||
/**
|
||||
* Returns a DrawTarget to draw into the TextureClient.
|
||||
@ -372,25 +400,11 @@ public:
|
||||
*/
|
||||
void UpdateFromSurface(gfx::SourceSurface* aSurface);
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const;
|
||||
|
||||
/**
|
||||
* This method is strictly for debugging. It causes locking and
|
||||
* needless copies.
|
||||
*/
|
||||
already_AddRefed<gfx::DataSourceSurface> GetAsSurface() {
|
||||
Lock(OpenMode::OPEN_READ);
|
||||
RefPtr<gfx::DataSourceSurface> data;
|
||||
RefPtr<gfx::DrawTarget> dt = BorrowDrawTarget();
|
||||
if (dt) {
|
||||
RefPtr<gfx::SourceSurface> surf = dt->Snapshot();
|
||||
if (surf) {
|
||||
data = surf->GetDataSurface();
|
||||
}
|
||||
}
|
||||
Unlock();
|
||||
return data.forget();
|
||||
}
|
||||
already_AddRefed<gfx::DataSourceSurface> GetAsSurface();
|
||||
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
|
||||
|
||||
@ -403,22 +417,6 @@ public:
|
||||
const gfx::IntRect* aRect,
|
||||
const gfx::IntPoint* aPoint);
|
||||
|
||||
/**
|
||||
* Returns true if this texture has a synchronization mechanism (mutex, fence, etc.).
|
||||
* Textures that do not implement synchronization should be immutable or should
|
||||
* use immediate uploads (see TextureFlags in CompositorTypes.h)
|
||||
* Even if a texture does not implement synchronization, Lock and Unlock need
|
||||
* to be used appropriately since the latter are also there to map/numap data.
|
||||
*/
|
||||
bool HasSynchronization() const { return false; }
|
||||
|
||||
/**
|
||||
* Indicates whether the TextureClient implementation is backed by an
|
||||
* in-memory buffer. The consequence of this is that locking the
|
||||
* TextureClient does not contend with locking the texture on the host side.
|
||||
*/
|
||||
bool HasIntermediateBuffer() const;
|
||||
|
||||
/**
|
||||
* Allocate and deallocate a TextureChild actor.
|
||||
*
|
||||
@ -435,9 +433,7 @@ public:
|
||||
/**
|
||||
* Get the TextureClient corresponding to the actor passed in parameter.
|
||||
*/
|
||||
static TextureClient* AsTextureClient(PTextureChild* actor);
|
||||
|
||||
gfx::IntSize GetSize() const;
|
||||
static already_AddRefed<TextureClient> AsTextureClient(PTextureChild* actor);
|
||||
|
||||
/**
|
||||
* TextureFlags contain important information about various aspects
|
||||
@ -456,6 +452,7 @@ public:
|
||||
|
||||
void RemoveFlags(TextureFlags aFlags);
|
||||
|
||||
// The TextureClient must not be locked when calling this method.
|
||||
void RecycleTexture(TextureFlags aFlags);
|
||||
|
||||
/**
|
||||
@ -505,6 +502,7 @@ public:
|
||||
* Create and init the TextureChild/Parent IPDL actor pair.
|
||||
*
|
||||
* Should be called only once per TextureClient.
|
||||
* The TextureClient must not be locked when calling this method.
|
||||
*/
|
||||
bool InitIPDLActor(CompositableForwarder* aForwarder);
|
||||
|
||||
@ -618,6 +616,10 @@ protected:
|
||||
*/
|
||||
bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor);
|
||||
|
||||
void LockActor() const;
|
||||
void UnlockActor() const;
|
||||
|
||||
TextureData::Info mInfo;
|
||||
|
||||
RefPtr<ClientIPCAllocator> mAllocator;
|
||||
RefPtr<TextureChild> mActor;
|
||||
|
@ -35,10 +35,15 @@ void
|
||||
SharedSurfaceTextureData::Deallocate(ClientIPCAllocator*)
|
||||
{}
|
||||
|
||||
gfx::IntSize
|
||||
SharedSurfaceTextureData::GetSize() const
|
||||
void
|
||||
SharedSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
{
|
||||
return mSurf->mSize;
|
||||
aInfo.size = mSurf->mSize;
|
||||
aInfo.format = gfx::SurfaceFormat::UNKNOWN;
|
||||
aInfo.hasIntermediateBuffer = false;
|
||||
aInfo.hasSynchronization = false;
|
||||
aInfo.supportsMoz2D = false;
|
||||
aInfo.canExposeMappedData = false;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -44,13 +44,7 @@ public:
|
||||
|
||||
virtual void Unlock() override {}
|
||||
|
||||
virtual bool HasIntermediateBuffer() const override { return false; }
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override {
|
||||
return gfx::SurfaceFormat::UNKNOWN;
|
||||
}
|
||||
|
||||
virtual gfx::IntSize GetSize() const override;
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const override;
|
||||
|
||||
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
|
@ -283,11 +283,11 @@ DXGITextureData::PrepareDrawTargetInLock(OpenMode aMode)
|
||||
}
|
||||
|
||||
if (mNeedsClear) {
|
||||
mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
|
||||
mDrawTarget->ClearRect(Rect(0, 0, mSize.width, mSize.height));
|
||||
mNeedsClear = false;
|
||||
}
|
||||
if (mNeedsClearWhite) {
|
||||
mDrawTarget->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
|
||||
mDrawTarget->FillRect(Rect(0, 0, mSize.width, mSize.height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
|
||||
mNeedsClearWhite = false;
|
||||
}
|
||||
|
||||
@ -300,6 +300,17 @@ D3D11TextureData::Unlock()
|
||||
UnlockD3DTexture(mTexture.get());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DXGITextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
{
|
||||
aInfo.size = mSize;
|
||||
aInfo.format = mFormat;
|
||||
aInfo.supportsMoz2D = true;
|
||||
aInfo.hasIntermediateBuffer = false;
|
||||
aInfo.hasSynchronization = mHasSynchronization;
|
||||
}
|
||||
|
||||
void
|
||||
D3D11TextureData::SyncWithObject(SyncObject* aSyncObject)
|
||||
{
|
||||
@ -498,12 +509,22 @@ DXGIYCbCrTextureData::Create(ClientIPCAllocator* aAllocator,
|
||||
aSize, aSizeY, aSizeCbCr);
|
||||
}
|
||||
|
||||
void
|
||||
DXGIYCbCrTextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
{
|
||||
aInfo.size = mSize;
|
||||
aInfo.format = gfx::SurfaceFormat::YUV;
|
||||
aInfo.supportsMoz2D = false;
|
||||
aInfo.hasIntermediateBuffer = false;
|
||||
aInfo.hasSynchronization = false;
|
||||
}
|
||||
|
||||
bool
|
||||
DXGIYCbCrTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
aOutDescriptor = SurfaceDescriptorDXGIYCbCr(
|
||||
(WindowsHandle)mHandles[0], (WindowsHandle)mHandles[1], (WindowsHandle)mHandles[2],
|
||||
GetSize(), mSizeY, mSizeCbCr
|
||||
mSize, mSizeY, mSizeCbCr
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
@ -24,15 +24,7 @@ class CompositorD3D11;
|
||||
class DXGITextureData : public TextureData
|
||||
{
|
||||
public:
|
||||
virtual gfx::IntSize GetSize() const override { return mSize; }
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
|
||||
virtual bool SupportsMoz2D() const override { return true; }
|
||||
|
||||
virtual bool HasIntermediateBuffer() const override { return false; }
|
||||
|
||||
virtual bool HasSynchronization() const override { return mHasSynchronization; }
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const override;
|
||||
|
||||
virtual bool Serialize(SurfaceDescriptor& aOutDescrptor) override;
|
||||
|
||||
@ -139,17 +131,10 @@ public:
|
||||
|
||||
virtual void Unlock() override {}
|
||||
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const override;
|
||||
|
||||
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
// TODO - DXGIYCbCrTextureClient returned true but that looks like a mistake
|
||||
virtual bool HasIntermediateBuffer() const override{ return false; }
|
||||
|
||||
virtual gfx::IntSize GetSize() const override { return mSize; }
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override { return gfx::SurfaceFormat::YUV; }
|
||||
|
||||
virtual bool SupportsMoz2D() const override { return false; }
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override { return nullptr; }
|
||||
|
||||
// This TextureData should not be used in a context where we use CreateSimilar
|
||||
|
@ -592,6 +592,17 @@ D3D9TextureData::CreateSimilar(ClientIPCAllocator*, TextureFlags aFlags, Texture
|
||||
return D3D9TextureData::Create(mSize, mFormat, aAllocFlags);
|
||||
}
|
||||
|
||||
void
|
||||
D3D9TextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
{
|
||||
aInfo.size = mSize;
|
||||
aInfo.format = mFormat;
|
||||
aInfo.hasIntermediateBuffer = true;
|
||||
aInfo.supportsMoz2D = true;
|
||||
aInfo.canExposeMappedData = false;
|
||||
aInfo.hasSynchronization = false;
|
||||
}
|
||||
|
||||
bool
|
||||
D3D9TextureData::Lock(OpenMode aMode, FenceHandle*)
|
||||
{
|
||||
@ -668,11 +679,11 @@ D3D9TextureData::BorrowDrawTarget()
|
||||
}
|
||||
|
||||
if (mNeedsClear) {
|
||||
dt->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
|
||||
dt->ClearRect(Rect(0, 0, mSize.width, mSize.height));
|
||||
mNeedsClear = false;
|
||||
}
|
||||
if (mNeedsClearWhite) {
|
||||
dt->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
|
||||
dt->FillRect(Rect(0, 0, mSize.width, mSize.height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
|
||||
mNeedsClearWhite = false;
|
||||
}
|
||||
|
||||
@ -774,6 +785,17 @@ DXGID3D9TextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
DXGID3D9TextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
{
|
||||
aInfo.size = GetSize();
|
||||
aInfo.format = mFormat;
|
||||
aInfo.supportsMoz2D = false;
|
||||
aInfo.canExposeMappedData = false;
|
||||
aInfo.hasIntermediateBuffer = false;
|
||||
aInfo.hasSynchronization = false;
|
||||
}
|
||||
|
||||
already_AddRefed<IDirect3DSurface9>
|
||||
DXGID3D9TextureData::GetD3D9Surface() const
|
||||
{
|
||||
|
@ -182,22 +182,16 @@ class D3D9TextureData : public TextureData
|
||||
public:
|
||||
~D3D9TextureData();
|
||||
|
||||
virtual bool SupportsMoz2D() const override { return true; }
|
||||
|
||||
virtual bool HasIntermediateBuffer() const override { return true; }
|
||||
|
||||
virtual bool Serialize(SurfaceDescriptor& aOutDescrptor) override;
|
||||
|
||||
virtual bool Lock(OpenMode aMode, FenceHandle*) override;
|
||||
|
||||
virtual void Unlock() override;
|
||||
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const override;
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
|
||||
virtual gfx::IntSize GetSize() const override { return mSize; }
|
||||
|
||||
virtual bool UpdateFromSurface(gfx::SourceSurface* aSurface) override;
|
||||
|
||||
virtual TextureData*
|
||||
@ -236,9 +230,7 @@ public:
|
||||
|
||||
~DXGID3D9TextureData();
|
||||
|
||||
virtual gfx::IntSize GetSize() const override { return gfx::IntSize(mDesc.Width, mDesc.Height); }
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const override;
|
||||
|
||||
virtual bool Lock(OpenMode, FenceHandle*) override { return true; }
|
||||
|
||||
@ -246,8 +238,6 @@ public:
|
||||
|
||||
virtual bool Serialize(SurfaceDescriptor& aOutDescriptor) override;
|
||||
|
||||
virtual bool HasIntermediateBuffer() const override { return false; }
|
||||
|
||||
virtual void Deallocate(ClientIPCAllocator* aAllocator) override {}
|
||||
|
||||
IDirect3DDevice9* GetD3D9Device() { return mDevice; }
|
||||
@ -260,6 +250,8 @@ public:
|
||||
return mDesc;
|
||||
}
|
||||
|
||||
gfx::IntSize GetSize() const { return gfx::IntSize(mDesc.Width, mDesc.Height); }
|
||||
|
||||
protected:
|
||||
DXGID3D9TextureData(gfx::SurfaceFormat aFormat,
|
||||
IDirect3DTexture9* aTexture, HANDLE aHandle,
|
||||
|
@ -99,14 +99,6 @@ APZChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
|
||||
return mBrowser->UpdateFrame(aFrameMetrics);
|
||||
}
|
||||
|
||||
bool
|
||||
APZChild::RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration)
|
||||
{
|
||||
APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
APZChild::RecvHandleDoubleTap(const CSSPoint& aPoint,
|
||||
const Modifiers& aModifiers,
|
||||
|
@ -28,9 +28,6 @@ public:
|
||||
|
||||
virtual bool RecvUpdateFrame(const FrameMetrics& frame) override;
|
||||
|
||||
virtual bool RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration) override;
|
||||
|
||||
virtual bool RecvHandleDoubleTap(const CSSPoint& aPoint,
|
||||
const Modifiers& aModifiers,
|
||||
const ScrollableLayerGuid& aGuid) override;
|
||||
|
@ -39,12 +39,9 @@ LayerTransactionChild::Destroy()
|
||||
|
||||
const ManagedContainer<PTextureChild>& textures = ManagedPTextureChild();
|
||||
for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
TextureClient* texture = TextureClient::AsTextureClient(iter.Get()->GetKey());
|
||||
RefPtr<TextureClient> texture = TextureClient::AsTextureClient(iter.Get()->GetKey());
|
||||
|
||||
if (texture) {
|
||||
// TODO: cf bug 1242448.
|
||||
//gfxDevCrash(gfx::LogReason::TextureAliveAfterShutdown)
|
||||
// << "A texture is held alive after shutdown (PCompositorBridge)";
|
||||
texture->Destroy();
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,6 @@ child:
|
||||
// The following methods correspond to functions on the GeckoContentController
|
||||
// interface in gfx/layers/apz/public/GeckoContentController.h. Refer to documentation
|
||||
// in that file for these functions.
|
||||
async AcknowledgeScrollUpdate(ViewID aScrollId, uint32_t aScrollGeneration);
|
||||
async HandleDoubleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
|
||||
async HandleSingleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid, bool aCallTakeFocusForClickFromTap);
|
||||
async HandleLongTap(CSSPoint point, Modifiers aModifiers, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
|
||||
|
@ -50,24 +50,6 @@ RemoteContentController::RequestContentRepaint(const FrameMetrics& aFrameMetrics
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RemoteContentController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration)
|
||||
{
|
||||
if (MessageLoop::current() != mUILoop) {
|
||||
// We have to send this message from the "UI thread" (main
|
||||
// thread).
|
||||
mUILoop->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &RemoteContentController::AcknowledgeScrollUpdate,
|
||||
aScrollId, aScrollGeneration));
|
||||
return;
|
||||
}
|
||||
if (CanSend()) {
|
||||
Unused << SendAcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RemoteContentController::HandleDoubleTap(const CSSPoint& aPoint,
|
||||
Modifiers aModifiers,
|
||||
|
@ -42,9 +42,6 @@ public:
|
||||
// Needs to be called on the main thread.
|
||||
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override;
|
||||
|
||||
virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration) override;
|
||||
|
||||
virtual void HandleDoubleTap(const CSSPoint& aPoint,
|
||||
Modifiers aModifiers,
|
||||
const ScrollableLayerGuid& aGuid) override;
|
||||
|
@ -133,6 +133,17 @@ GrallocTextureData::Forget(ClientIPCAllocator* aAllocator)
|
||||
mGraphicBuffer = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GrallocTextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
{
|
||||
aInfo.size = mSize;
|
||||
aInfo.format = mFormat;
|
||||
aInfo.hasIntermediateBuffer = false;
|
||||
aInfo.hasSynchronization = true;
|
||||
aInfo.supportsMoz2D = true;
|
||||
aInfo.canExposeMappedData = true;
|
||||
}
|
||||
|
||||
bool
|
||||
GrallocTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
{
|
||||
|
@ -45,22 +45,12 @@ public:
|
||||
|
||||
virtual void Unlock() override;
|
||||
|
||||
virtual gfx::IntSize GetSize() const override { return mSize; }
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
|
||||
virtual void FillInfo(TextureData::Info& aInfo) const override;
|
||||
|
||||
virtual already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() override;
|
||||
|
||||
virtual bool CanExposeMappedData() const override { return true; }
|
||||
|
||||
virtual bool BorrowMappedData(MappedTextureData& aMap) override;
|
||||
|
||||
virtual bool SupportsMoz2D() const override { return true; }
|
||||
|
||||
virtual bool HasIntermediateBuffer() const override { return false; }
|
||||
|
||||
virtual bool HasSynchronization() const override { return true; }
|
||||
|
||||
virtual void Deallocate(ClientIPCAllocator*) override;
|
||||
|
||||
virtual void Forget(ClientIPCAllocator*) override;
|
||||
|
@ -39,16 +39,15 @@ MacIOSurfaceTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
|
||||
return true;
|
||||
}
|
||||
|
||||
gfx::IntSize
|
||||
MacIOSurfaceTextureData::GetSize() const
|
||||
void
|
||||
MacIOSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const
|
||||
{
|
||||
return gfx::IntSize(mSurface->GetDevicePixelWidth(), mSurface->GetDevicePixelHeight());
|
||||
}
|
||||
|
||||
gfx::SurfaceFormat
|
||||
MacIOSurfaceTextureData::GetFormat() const
|
||||
{
|
||||
return mSurface->GetFormat();
|
||||
aInfo.size = gfx::IntSize(mSurface->GetDevicePixelWidth(), mSurface->GetDevicePixelHeight());
|
||||
aInfo.format = mSurface->GetFormat();
|
||||
aInfo.hasIntermediateBuffer = false;
|
||||
aInfo.hasSynchronization = false;
|
||||
aInfo.supportsMoz2D = false;
|
||||
aInfo.canExposeMappedData = false;
|
||||
}
|
||||
|
||||
already_AddRefed<gfx::DataSourceSurface>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user