mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c. a=merge
This commit is contained in:
commit
9ca5e70312
3
CLOBBER
3
CLOBBER
@ -22,4 +22,5 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Merge day clobber
|
||||
Hitting failures with Taskcluster-based jobs that seem like needs-clobber.
|
||||
|
||||
|
@ -552,8 +552,7 @@ nsContextMenu.prototype = {
|
||||
|
||||
const xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
if (aNode.namespaceURI == xulNS ||
|
||||
aNode.nodeType == Node.DOCUMENT_NODE ||
|
||||
this.isDisabledForEvents(aNode)) {
|
||||
aNode.nodeType == Node.DOCUMENT_NODE) {
|
||||
this.shouldDisplay = false;
|
||||
return;
|
||||
}
|
||||
@ -1534,16 +1533,6 @@ nsContextMenu.prototype = {
|
||||
"contextMenu.hasBGImage = " + this.hasBGImage + "\n";
|
||||
},
|
||||
|
||||
isDisabledForEvents: function(aNode) {
|
||||
let ownerDoc = aNode.ownerDocument;
|
||||
return
|
||||
ownerDoc.defaultView &&
|
||||
ownerDoc.defaultView
|
||||
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils)
|
||||
.isNodeDisabledForEvents(aNode);
|
||||
},
|
||||
|
||||
isTargetATextBox: function(node) {
|
||||
if (node instanceof HTMLInputElement)
|
||||
return node.mozIsTextField(false);
|
||||
|
@ -50,7 +50,7 @@ _SUBDIR_CONFIG_ARGS="$ac_configure_args"
|
||||
dnl Set the version number of the libs included with mozilla
|
||||
dnl ========================================================
|
||||
MOZJPEG=62
|
||||
MOZPNG=10616
|
||||
MOZPNG=10617
|
||||
NSPR_VERSION=4
|
||||
NSPR_MINVER=4.10.8
|
||||
NSS_VERSION=3
|
||||
|
@ -46,32 +46,43 @@ function enableOfflineCacheForApp(aPrincipal) {
|
||||
}
|
||||
|
||||
|
||||
function storeCache(applicationCache, url, file, itemType) {
|
||||
function storeCache(applicationCache, url, file, itemType, metadata) {
|
||||
let storage =
|
||||
Services.cache2.appCacheStorage(LoadContextInfo.default, applicationCache);
|
||||
let uri = Services.io.newURI(url, null, null);
|
||||
let nowGMT = new Date().toGMTString();
|
||||
metadata = metadata || {};
|
||||
metadata.lastFetched = metadata.lastFetched || nowGMT;
|
||||
metadata.lastModified = metadata.lastModified || nowGMT;
|
||||
storage.asyncOpenURI(uri, "", nsICacheStorage.OPEN_TRUNCATE, {
|
||||
onCacheEntryAvailable:
|
||||
function (cacheEntry, isNew, appCache, result) {
|
||||
cacheEntry.setMetaDataElement('request-method', 'GET');
|
||||
cacheEntry.setMetaDataElement('response-head', 'HTTP/1.1 200 OK\r\n');
|
||||
cacheEntry.setMetaDataElement("request-method", "GET");
|
||||
cacheEntry.setMetaDataElement("response-head",
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Date: " + metadata.lastFetched + "\r\n" +
|
||||
"Last-Modified: " + metadata.lastModified + "\r\n" +
|
||||
"Cache-Control: no-cache\r\n");
|
||||
|
||||
let outputStream = cacheEntry.openOutputStream(0);
|
||||
|
||||
// Input-Output stream machinery in order to push nsIFile content into cache
|
||||
let inputStream = Cc['@mozilla.org/network/file-input-stream;1']
|
||||
// Input-Output stream machinery in order to push nsIFile content into
|
||||
// cache
|
||||
let inputStream = Cc["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Ci.nsIFileInputStream);
|
||||
inputStream.init(file, 1, -1, null);
|
||||
let bufferedOutputStream = Cc['@mozilla.org/network/buffered-output-stream;1']
|
||||
.createInstance(Ci.nsIBufferedOutputStream);
|
||||
let bufferedOutputStream =
|
||||
Cc["@mozilla.org/network/buffered-output-stream;1"]
|
||||
.createInstance(Ci.nsIBufferedOutputStream);
|
||||
bufferedOutputStream.init(outputStream, 1024);
|
||||
bufferedOutputStream.writeFrom(inputStream, inputStream.available());
|
||||
bufferedOutputStream.flush();
|
||||
bufferedOutputStream.close();
|
||||
inputStream.close();
|
||||
|
||||
cacheEntry.setExpirationTime(0);
|
||||
cacheEntry.markValid();
|
||||
debug (file.path + ' -> ' + url + ' (' + itemType + ')');
|
||||
debug (file.path + " -> " + url + " (" + itemType + ")");
|
||||
applicationCache.markEntry(url, itemType);
|
||||
cacheEntry.close();
|
||||
}
|
||||
@ -206,8 +217,12 @@ function installCache(app) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cacheDir = makeFile(app.cachePath)
|
||||
let cacheDir = makeFile(app.cachePath);
|
||||
cacheDir.append(app.appId);
|
||||
|
||||
let resourcesMetadata = cacheDir.clone();
|
||||
resourcesMetadata.append('resources_metadata.json');
|
||||
|
||||
cacheDir.append('cache');
|
||||
if (!cacheDir.exists())
|
||||
return;
|
||||
@ -218,55 +233,72 @@ function installCache(app) {
|
||||
return;
|
||||
|
||||
let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(
|
||||
app.origin, app.localId, false);
|
||||
app.origin, app.localId, false);
|
||||
|
||||
enableOfflineCacheForApp(principal);
|
||||
// If the build has been correctly configured, this should not happen!
|
||||
// If we install the cache anyway, it won't be updateable. If we don't install
|
||||
// it, the application won't be useable offline.
|
||||
let metadataLoaded;
|
||||
if (!resourcesMetadata.exists()) {
|
||||
// Not debug, since this is something that should be logged always!
|
||||
dump("OfflineCacheInstaller: App " + app.appId + " does have an app cache" +
|
||||
" but does not have a resources_metadata.json file!");
|
||||
metadataLoaded = Promise.resolve({});
|
||||
} else {
|
||||
metadataLoaded = new Promise(
|
||||
(resolve, reject) =>
|
||||
readFile(resourcesMetadata, principal, content => resolve(JSON.parse(content))));
|
||||
}
|
||||
|
||||
// Get the url for the manifest.
|
||||
let appcacheURL = app.appcache_path;
|
||||
metadataLoaded.then(function(metadata) {
|
||||
enableOfflineCacheForApp(principal);
|
||||
|
||||
// The group ID contains application id and 'f' for not being hosted in
|
||||
// a browser element, but a mozbrowser iframe.
|
||||
// See netwerk/cache/nsDiskCacheDeviceSQL.cpp: AppendJARIdentifier
|
||||
let groupID = appcacheURL + '#' + app.localId+ '+f';
|
||||
let applicationCache = applicationCacheService.createApplicationCache(groupID);
|
||||
applicationCache.activate();
|
||||
// Get the url for the manifest.
|
||||
let appcacheURL = app.appcache_path;
|
||||
|
||||
readFile(cacheManifest, principal, function readAppCache(content) {
|
||||
let entries = parseAppCache(app, cacheManifest.path, content);
|
||||
// The group ID contains application id and 'f' for not being hosted in
|
||||
// a browser element, but a mozbrowser iframe.
|
||||
// See netwerk/cache/nsDiskCacheDeviceSQL.cpp: AppendJARIdentifier
|
||||
let groupID = appcacheURL + '#' + app.localId+ '+f';
|
||||
let applicationCache = applicationCacheService.createApplicationCache(groupID);
|
||||
applicationCache.activate();
|
||||
|
||||
entries.urls.forEach(function processCachedFile(url) {
|
||||
// Get this nsIFile from cache folder for this URL
|
||||
// We have absolute urls, so remove the origin part to locate the
|
||||
// files.
|
||||
let path = url.replace(app.origin.spec, '');
|
||||
let file = cacheDir.clone();
|
||||
let paths = path.split('/');
|
||||
paths.forEach(file.append);
|
||||
readFile(cacheManifest, principal, function readAppCache(content) {
|
||||
let entries = parseAppCache(app, cacheManifest.path, content);
|
||||
|
||||
if (!file.exists()) {
|
||||
let msg = 'File ' + file.path + ' exists in the manifest but does ' +
|
||||
'not points to a real file.';
|
||||
throw new Error(msg);
|
||||
}
|
||||
entries.urls.forEach(function processCachedFile(url) {
|
||||
// Get this nsIFile from cache folder for this URL
|
||||
// We have absolute urls, so remove the origin part to locate the
|
||||
// files.
|
||||
let path = url.replace(app.origin.spec, '');
|
||||
let file = cacheDir.clone();
|
||||
let paths = path.split('/');
|
||||
paths.forEach(file.append);
|
||||
|
||||
let itemType = nsIApplicationCache.ITEM_EXPLICIT;
|
||||
if (entries.fallbacks.indexOf(url) > -1) {
|
||||
debug('add fallback: ' + url + '\n');
|
||||
itemType |= nsIApplicationCache.ITEM_FALLBACK;
|
||||
}
|
||||
storeCache(applicationCache, url, file, itemType);
|
||||
if (!file.exists()) {
|
||||
let msg = 'File ' + file.path + ' exists in the manifest but does ' +
|
||||
'not points to a real file.';
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
let itemType = nsIApplicationCache.ITEM_EXPLICIT;
|
||||
if (entries.fallbacks.indexOf(url) > -1) {
|
||||
debug('add fallback: ' + url + '\n');
|
||||
itemType |= nsIApplicationCache.ITEM_FALLBACK;
|
||||
}
|
||||
storeCache(applicationCache, url, file, itemType, metadata[path]);
|
||||
});
|
||||
|
||||
let array = new MutableArray();
|
||||
entries.namespaces.forEach(function processNamespace([type, spec, data]) {
|
||||
debug('add namespace: ' + type + ' - ' + spec + ' - ' + data + '\n');
|
||||
array.appendElement(new Namespace(type, spec, data), false);
|
||||
});
|
||||
applicationCache.addNamespaces(array);
|
||||
|
||||
storeCache(applicationCache, appcacheURL, cacheManifest,
|
||||
nsIApplicationCache.ITEM_MANIFEST);
|
||||
});
|
||||
|
||||
let array = new MutableArray();
|
||||
entries.namespaces.forEach(function processNamespace([type, spec, data]) {
|
||||
debug('add namespace: ' + type + ' - ' + spec + ' - ' + data + '\n');
|
||||
array.appendElement(new Namespace(type, spec, data), false);
|
||||
});
|
||||
applicationCache.addNamespaces(array);
|
||||
|
||||
storeCache(applicationCache, appcacheURL, cacheManifest,
|
||||
nsIApplicationCache.ITEM_MANIFEST);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -125,8 +125,7 @@ public:
|
||||
void FailConnection(uint16_t reasonCode,
|
||||
const nsACString& aReasonString = EmptyCString());
|
||||
nsresult CloseConnection(uint16_t reasonCode,
|
||||
const nsACString& aReasonString = EmptyCString(),
|
||||
bool aCanceling = false);
|
||||
const nsACString& aReasonString = EmptyCString());
|
||||
nsresult Disconnect();
|
||||
void DisconnectInternal();
|
||||
|
||||
@ -385,38 +384,6 @@ WebSocketImpl::PrintErrorOnConsole(const char *aBundleURI,
|
||||
|
||||
namespace {
|
||||
|
||||
class CloseRunnable final : public WorkerMainThreadRunnable
|
||||
{
|
||||
public:
|
||||
CloseRunnable(WebSocketImpl* aImpl, uint16_t aReasonCode,
|
||||
const nsACString& aReasonString)
|
||||
: WorkerMainThreadRunnable(aImpl->mWorkerPrivate)
|
||||
, mImpl(aImpl)
|
||||
, mReasonCode(aReasonCode)
|
||||
, mReasonString(aReasonString)
|
||||
, mRv(NS_ERROR_FAILURE)
|
||||
{ }
|
||||
|
||||
bool MainThreadRun() override
|
||||
{
|
||||
mRv = mImpl->mChannel->Close(mReasonCode, mReasonString);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult ErrorCode() const
|
||||
{
|
||||
return mRv;
|
||||
}
|
||||
|
||||
private:
|
||||
// A raw pointer because this runnable is sync.
|
||||
WebSocketImpl* mImpl;
|
||||
|
||||
uint16_t mReasonCode;
|
||||
const nsACString& mReasonString;
|
||||
nsresult mRv;
|
||||
};
|
||||
|
||||
class CancelWebSocketRunnable final : public nsRunnable
|
||||
{
|
||||
public:
|
||||
@ -469,11 +436,9 @@ private:
|
||||
|
||||
nsresult
|
||||
WebSocketImpl::CloseConnection(uint16_t aReasonCode,
|
||||
const nsACString& aReasonString,
|
||||
bool aCanceling)
|
||||
const nsACString& aReasonString)
|
||||
{
|
||||
AssertIsOnTargetThread();
|
||||
MOZ_ASSERT(!NS_IsMainThread() || !aCanceling);
|
||||
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
return NS_OK;
|
||||
@ -500,16 +465,9 @@ WebSocketImpl::CloseConnection(uint16_t aReasonCode,
|
||||
return mChannel->Close(aReasonCode, aReasonString);
|
||||
}
|
||||
|
||||
if (aCanceling) {
|
||||
nsRefPtr<CancelWebSocketRunnable> runnable =
|
||||
new CancelWebSocketRunnable(mChannel, aReasonCode, aReasonString);
|
||||
return NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
nsRefPtr<CloseRunnable> runnable =
|
||||
new CloseRunnable(this, aReasonCode, aReasonString);
|
||||
runnable->Dispatch(mWorkerPrivate->GetJSContext());
|
||||
return runnable->ErrorCode();
|
||||
nsRefPtr<CancelWebSocketRunnable> runnable =
|
||||
new CancelWebSocketRunnable(mChannel, aReasonCode, aReasonString);
|
||||
return NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
// No channel, but not disconnected: canceled or failed early
|
||||
@ -2033,7 +1991,7 @@ public:
|
||||
}
|
||||
|
||||
mWebSocketImpl->CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY,
|
||||
EmptyCString(), true);
|
||||
EmptyCString());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -340,19 +340,18 @@ nsFrameLoader::ReallyStartLoadingInternal()
|
||||
}
|
||||
|
||||
if (mRemoteFrame) {
|
||||
if (!mRemoteBrowser) {
|
||||
TryRemoteBrowser();
|
||||
|
||||
if (!mRemoteBrowser) {
|
||||
if (!mRemoteBrowser && !TryRemoteBrowser()) {
|
||||
NS_WARNING("Couldn't create child process for iframe.");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (mRemoteBrowserShown || ShowRemoteFrame(ScreenIntSize(0, 0))) {
|
||||
// FIXME get error codes from child
|
||||
mRemoteBrowser->LoadURL(mURIToLoad);
|
||||
} else {
|
||||
// Execute pending frame scripts before loading URL
|
||||
EnsureMessageManager();
|
||||
|
||||
// FIXME get error codes from child
|
||||
mRemoteBrowser->LoadURL(mURIToLoad);
|
||||
|
||||
if (!mRemoteBrowserShown && !ShowRemoteFrame(ScreenIntSize(0, 0))) {
|
||||
NS_WARNING("[nsFrameLoader] ReallyStartLoadingInternal tried but couldn't show remote browser.\n");
|
||||
}
|
||||
|
||||
@ -832,13 +831,9 @@ nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size,
|
||||
{
|
||||
NS_ASSERTION(mRemoteFrame, "ShowRemote only makes sense on remote frames.");
|
||||
|
||||
if (!mRemoteBrowser) {
|
||||
TryRemoteBrowser();
|
||||
|
||||
if (!mRemoteBrowser) {
|
||||
NS_ERROR("Couldn't create child process.");
|
||||
return false;
|
||||
}
|
||||
if (!mRemoteBrowser && !TryRemoteBrowser()) {
|
||||
NS_ERROR("Couldn't create child process.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME/bug 589337: Show()/Hide() is pretty expensive for
|
||||
@ -2262,28 +2257,31 @@ nsFrameLoader::TryRemoteBrowser()
|
||||
|
||||
nsCOMPtr<Element> ownerElement = mOwnerContent;
|
||||
mRemoteBrowser = ContentParent::CreateBrowserOrApp(context, ownerElement, openerContentParent);
|
||||
if (mRemoteBrowser) {
|
||||
mChildID = mRemoteBrowser->Manager()->ChildID();
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootItem;
|
||||
parentDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
|
||||
nsCOMPtr<nsIDOMWindow> rootWin = rootItem->GetWindow();
|
||||
nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
|
||||
|
||||
if (rootChromeWin) {
|
||||
nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
|
||||
rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
|
||||
mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin);
|
||||
}
|
||||
|
||||
mContentParent = mRemoteBrowser->Manager();
|
||||
|
||||
if (mOwnerContent->AttrValueIs(kNameSpaceID_None,
|
||||
nsGkAtoms::mozpasspointerevents,
|
||||
nsGkAtoms::_true,
|
||||
eCaseMatters)) {
|
||||
unused << mRemoteBrowser->SendSetUpdateHitRegion(true);
|
||||
}
|
||||
if (!mRemoteBrowser) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mContentParent = mRemoteBrowser->Manager();
|
||||
mChildID = mRemoteBrowser->Manager()->ChildID();
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootItem;
|
||||
parentDocShell->GetRootTreeItem(getter_AddRefs(rootItem));
|
||||
nsCOMPtr<nsIDOMWindow> rootWin = rootItem->GetWindow();
|
||||
nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
|
||||
|
||||
if (rootChromeWin) {
|
||||
nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
|
||||
rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
|
||||
mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin);
|
||||
}
|
||||
|
||||
if (mOwnerContent->AttrValueIs(kNameSpaceID_None,
|
||||
nsGkAtoms::mozpasspointerevents,
|
||||
nsGkAtoms::_true,
|
||||
eCaseMatters)) {
|
||||
unused << mRemoteBrowser->SendSetUpdateHitRegion(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2528,7 +2526,7 @@ nsFrameLoader::EnsureMessageManager()
|
||||
|
||||
bool useRemoteProcess = ShouldUseRemoteProcess();
|
||||
if (mMessageManager) {
|
||||
if (useRemoteProcess && mRemoteBrowserShown) {
|
||||
if (useRemoteProcess && mRemoteBrowser) {
|
||||
mMessageManager->InitWithCallback(this);
|
||||
}
|
||||
return NS_OK;
|
||||
@ -2553,7 +2551,7 @@ nsFrameLoader::EnsureMessageManager()
|
||||
}
|
||||
|
||||
if (useRemoteProcess) {
|
||||
mMessageManager = new nsFrameMessageManager(mRemoteBrowserShown ? this : nullptr,
|
||||
mMessageManager = new nsFrameMessageManager(mRemoteBrowser ? this : nullptr,
|
||||
static_cast<nsFrameMessageManager*>(parentManager.get()),
|
||||
MM_CHROME);
|
||||
} else {
|
||||
|
@ -260,6 +260,7 @@ nsInProcessTabChildGlobal::GetOwnerContent()
|
||||
nsresult
|
||||
nsInProcessTabChildGlobal::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
aVisitor.mForceContentDispatch = true;
|
||||
aVisitor.mCanHandle = true;
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -299,7 +299,7 @@ CanvasImageCache::Lookup(Element* aImage,
|
||||
|
||||
gImageCache->MarkUsed(entry->mData);
|
||||
|
||||
*aSize = gfx::ToIntSize(entry->mData->mSize);
|
||||
*aSize = entry->mData->mSize;
|
||||
return entry->mData->mSourceSurface;
|
||||
}
|
||||
|
||||
|
@ -4320,7 +4320,7 @@ CanvasRenderingContext2D::DrawImage(const HTMLImageOrCanvasOrVideoElement& image
|
||||
return;
|
||||
}
|
||||
|
||||
imgSize = gfx::ToIntSize(res.mSize);
|
||||
imgSize = res.mSize;
|
||||
|
||||
// Scale sw/sh based on aspect ratio
|
||||
if (image.IsHTMLVideoElement()) {
|
||||
|
@ -55,7 +55,6 @@
|
||||
#if defined(XP_WIN)
|
||||
#define TARGET_SANDBOX_EXPORTS
|
||||
#include "mozilla/sandboxTarget.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#elif defined(XP_LINUX)
|
||||
#include "mozilla/Sandbox.h"
|
||||
#include "mozilla/SandboxInfo.h"
|
||||
@ -1080,76 +1079,6 @@ ContentChild::AllocPProcessHangMonitorChild(Transport* aTransport,
|
||||
return CreateHangMonitorChild(aTransport, aOtherProcess);
|
||||
}
|
||||
|
||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||
static void
|
||||
SetUpSandboxEnvironment()
|
||||
{
|
||||
// Set up a low integrity temp directory. This only makes sense if the
|
||||
// delayed integrity level for the content process is INTEGRITY_LEVEL_LOW.
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIProperties> directoryService =
|
||||
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> lowIntegrityTemp;
|
||||
rv = directoryService->Get(NS_WIN_LOW_INTEGRITY_TEMP, NS_GET_IID(nsIFile),
|
||||
getter_AddRefs(lowIntegrityTemp));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Undefine returns a failure if the property is not already set.
|
||||
unused << directoryService->Undefine(NS_OS_TEMP_DIR);
|
||||
rv = directoryService->Set(NS_OS_TEMP_DIR, lowIntegrityTemp);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set TEMP and TMP environment variables.
|
||||
nsAutoString lowIntegrityTempPath;
|
||||
rv = lowIntegrityTemp->GetPath(lowIntegrityTempPath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool setOK = SetEnvironmentVariableW(L"TEMP", lowIntegrityTempPath.get());
|
||||
NS_WARN_IF_FALSE(setOK, "Failed to set TEMP to low integrity temp path");
|
||||
setOK = SetEnvironmentVariableW(L"TMP", lowIntegrityTempPath.get());
|
||||
NS_WARN_IF_FALSE(setOK, "Failed to set TMP to low integrity temp path");
|
||||
}
|
||||
|
||||
void
|
||||
ContentChild::CleanUpSandboxEnvironment()
|
||||
{
|
||||
// Sandbox environment is only currently a low integrity temp, which only
|
||||
// makes sense for sandbox pref level 1 (and will eventually not be needed
|
||||
// at all, once all file access is via chrome/broker process).
|
||||
if (Preferences::GetInt("security.sandbox.content.level") != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIProperties> directoryService =
|
||||
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> lowIntegrityTemp;
|
||||
rv = directoryService->Get(NS_WIN_LOW_INTEGRITY_TEMP, NS_GET_IID(nsIFile),
|
||||
getter_AddRefs(lowIntegrityTemp));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't check the return value as the directory will only have been created
|
||||
// if it has been used.
|
||||
unused << lowIntegrityTemp->Remove(/* aRecursive */ true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -1268,12 +1197,6 @@ ContentChild::RecvSetProcessSandbox()
|
||||
SetContentProcessSandbox();
|
||||
#elif defined(XP_WIN)
|
||||
mozilla::SandboxTarget::Instance()->StartSandbox();
|
||||
// Sandbox environment is only currently a low integrity temp, which only
|
||||
// makes sense for sandbox pref level 1 (and will eventually not be needed
|
||||
// at all, once all file access is via chrome/broker process).
|
||||
if (Preferences::GetInt("security.sandbox.content.level") == 1) {
|
||||
SetUpSandboxEnvironment();
|
||||
}
|
||||
#elif defined(XP_MACOSX)
|
||||
StartMacOSContentSandbox();
|
||||
#endif
|
||||
|
@ -135,11 +135,6 @@ public:
|
||||
AllocPProcessHangMonitorChild(Transport* aTransport,
|
||||
ProcessId aOtherProcess) override;
|
||||
|
||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||
// Cleans up any resources used by the process when sandboxed.
|
||||
void CleanUpSandboxEnvironment();
|
||||
#endif
|
||||
|
||||
virtual bool RecvSetProcessSandbox() override;
|
||||
|
||||
PBackgroundChild*
|
||||
|
@ -8,11 +8,87 @@
|
||||
|
||||
#include "ContentProcess.h"
|
||||
|
||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsDirectoryService.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#endif
|
||||
|
||||
using mozilla::ipc::IOThreadChild;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||
static already_AddRefed<nsIFile>
|
||||
GetLowIntegrityTemp()
|
||||
{
|
||||
MOZ_ASSERT(nsDirectoryService::gService,
|
||||
"GetLowIntegrityTemp relies on nsDirectoryService being initialized");
|
||||
|
||||
// A low integrity temp only currently makes sense for sandbox pref level 1.
|
||||
if (Preferences::GetInt("security.sandbox.content.level") != 1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> lowIntegrityTemp;
|
||||
nsresult rv = nsDirectoryService::gService->Get(NS_WIN_LOW_INTEGRITY_TEMP,
|
||||
NS_GET_IID(nsIFile),
|
||||
getter_AddRefs(lowIntegrityTemp));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return lowIntegrityTemp.forget();
|
||||
}
|
||||
|
||||
static void
|
||||
SetUpSandboxEnvironment()
|
||||
{
|
||||
MOZ_ASSERT(nsDirectoryService::gService,
|
||||
"SetUpSandboxEnvironment relies on nsDirectoryService being initialized");
|
||||
|
||||
// Setup to use a low integrity temp if available.
|
||||
nsCOMPtr<nsIFile> lowIntegrityTemp = GetLowIntegrityTemp();
|
||||
if (!lowIntegrityTemp) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Undefine returns a failure if the property is not already set.
|
||||
unused << nsDirectoryService::gService->Undefine(NS_OS_TEMP_DIR);
|
||||
nsresult rv = nsDirectoryService::gService->Set(NS_OS_TEMP_DIR, lowIntegrityTemp);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set TEMP and TMP environment variables.
|
||||
nsAutoString lowIntegrityTempPath;
|
||||
rv = lowIntegrityTemp->GetPath(lowIntegrityTempPath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool setOK = SetEnvironmentVariableW(L"TEMP", lowIntegrityTempPath.get());
|
||||
NS_WARN_IF_FALSE(setOK, "Failed to set TEMP to low integrity temp path");
|
||||
setOK = SetEnvironmentVariableW(L"TMP", lowIntegrityTempPath.get());
|
||||
NS_WARN_IF_FALSE(setOK, "Failed to set TMP to low integrity temp path");
|
||||
}
|
||||
|
||||
static void
|
||||
CleanUpSandboxEnvironment()
|
||||
{
|
||||
// Remove low integrity temp if it exists.
|
||||
nsCOMPtr<nsIFile> lowIntegrityTemp = GetLowIntegrityTemp();
|
||||
if (!lowIntegrityTemp) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't check the return value as the directory will only have been created
|
||||
// if it has been used.
|
||||
unused << lowIntegrityTemp->Remove(/* aRecursive */ true);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ContentProcess::SetAppDir(const nsACString& aPath)
|
||||
{
|
||||
@ -27,6 +103,10 @@ ContentProcess::Init()
|
||||
IOThreadChild::channel());
|
||||
mXREEmbed.Start();
|
||||
mContent.InitXPCOM();
|
||||
|
||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||
SetUpSandboxEnvironment();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -35,7 +115,7 @@ void
|
||||
ContentProcess::CleanUp()
|
||||
{
|
||||
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
|
||||
mContent.CleanUpSandboxEnvironment();
|
||||
CleanUpSandboxEnvironment();
|
||||
#endif
|
||||
mXREEmbed.Stop();
|
||||
}
|
||||
|
@ -1693,6 +1693,10 @@ bool
|
||||
TabChild::RecvLoadURL(const nsCString& aURI,
|
||||
const BrowserConfiguration& aConfiguration)
|
||||
{
|
||||
if (!InitTabChildGlobal()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SetProcessNameToAppName();
|
||||
|
||||
nsresult rv = WebNavigation()->LoadURI(NS_ConvertUTF8toUTF16(aURI).get(),
|
||||
|
@ -266,7 +266,6 @@ TabParent::TabParent(nsIContentParent* aManager,
|
||||
, mOrientation(0)
|
||||
, mDPI(0)
|
||||
, mDefaultScale(0)
|
||||
, mShown(false)
|
||||
, mUpdatedDimensions(false)
|
||||
, mChromeOffset(0, 0)
|
||||
, mManager(aManager)
|
||||
@ -754,13 +753,6 @@ TabParent::LoadURL(nsIURI* aURI)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mShown) {
|
||||
NS_WARNING(nsPrintfCString("TabParent::LoadURL(%s) called before "
|
||||
"Show(). Ignoring LoadURL.\n",
|
||||
spec.get()).get());
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t appId = OwnOrContainingAppId();
|
||||
if (mSendOfflineStatus && NS_IsAppOffline(appId)) {
|
||||
// If the app is offline in the parent process
|
||||
@ -824,8 +816,6 @@ TabParent::LoadURL(nsIURI* aURI)
|
||||
void
|
||||
TabParent::Show(const ScreenIntSize& size, bool aParentIsActive)
|
||||
{
|
||||
// sigh
|
||||
mShown = true;
|
||||
mDimensions = size;
|
||||
if (mIsDestroyed) {
|
||||
return;
|
||||
|
@ -429,7 +429,6 @@ protected:
|
||||
ScreenOrientation mOrientation;
|
||||
float mDPI;
|
||||
CSSToLayoutDeviceScale mDefaultScale;
|
||||
bool mShown;
|
||||
bool mUpdatedDimensions;
|
||||
nsIntPoint mChromeOffset;
|
||||
|
||||
|
@ -1,319 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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 "AVCCDecoderModule.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "MediaTaskQueue.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "mp4_demuxer/AnnexB.h"
|
||||
#include "mp4_demuxer/H264.h"
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
|
||||
class AVCCMediaDataDecoder : public MediaDataDecoder {
|
||||
public:
|
||||
|
||||
AVCCMediaDataDecoder(PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback);
|
||||
|
||||
virtual ~AVCCMediaDataDecoder();
|
||||
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
virtual bool IsWaitingMediaResources() override;
|
||||
virtual bool IsDormantNeeded() override;
|
||||
virtual void AllocateMediaResources() override;
|
||||
virtual void ReleaseMediaResources() override;
|
||||
virtual bool IsHardwareAccelerated() const override;
|
||||
|
||||
private:
|
||||
// Will create the required MediaDataDecoder if we have a AVC SPS.
|
||||
// Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and
|
||||
// will set mError accordingly.
|
||||
nsresult CreateDecoder();
|
||||
nsresult CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample);
|
||||
nsresult CheckForSPSChange(mp4_demuxer::MP4Sample* aSample);
|
||||
void UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData);
|
||||
|
||||
nsRefPtr<PlatformDecoderModule> mPDM;
|
||||
mp4_demuxer::VideoDecoderConfig mCurrentConfig;
|
||||
layers::LayersBackend mLayersBackend;
|
||||
nsRefPtr<layers::ImageContainer> mImageContainer;
|
||||
nsRefPtr<FlushableMediaTaskQueue> mVideoTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
nsresult mLastError;
|
||||
};
|
||||
|
||||
AVCCMediaDataDecoder::AVCCMediaDataDecoder(PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
: mPDM(aPDM)
|
||||
, mCurrentConfig(aConfig)
|
||||
, mLayersBackend(aLayersBackend)
|
||||
, mImageContainer(aImageContainer)
|
||||
, mVideoTaskQueue(aVideoTaskQueue)
|
||||
, mCallback(aCallback)
|
||||
, mDecoder(nullptr)
|
||||
, mLastError(NS_OK)
|
||||
{
|
||||
CreateDecoder();
|
||||
}
|
||||
|
||||
AVCCMediaDataDecoder::~AVCCMediaDataDecoder()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Init()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Init();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsresult rv;
|
||||
if (!mDecoder) {
|
||||
// It is not possible to create an AVCC H264 decoder without SPS.
|
||||
// As such, creation will fail if the extra_data just extracted doesn't
|
||||
// contain a SPS.
|
||||
rv = CreateDecoderAndInit(aSample);
|
||||
if (rv == NS_ERROR_NOT_INITIALIZED) {
|
||||
// We are missing the required SPS to create the decoder.
|
||||
// Ignore for the time being, the MP4Sample will be dropped.
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
rv = CheckForSPSChange(aSample);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aSample->extra_data = mCurrentConfig.extra_data;
|
||||
|
||||
return mDecoder->Input(aSample);
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Flush()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Flush();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Drain()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Drain();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Shutdown()
|
||||
{
|
||||
if (mDecoder) {
|
||||
nsresult rv = mDecoder->Shutdown();
|
||||
mDecoder = nullptr;
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCMediaDataDecoder::IsWaitingMediaResources()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->IsWaitingMediaResources();
|
||||
}
|
||||
return MediaDataDecoder::IsWaitingMediaResources();
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCMediaDataDecoder::IsDormantNeeded()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
AVCCMediaDataDecoder::AllocateMediaResources()
|
||||
{
|
||||
// Nothing to do, decoder will be allocated on the fly when required.
|
||||
}
|
||||
|
||||
void
|
||||
AVCCMediaDataDecoder::ReleaseMediaResources()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::CreateDecoder()
|
||||
{
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(mCurrentConfig.extra_data)) {
|
||||
// nothing found yet, will try again later
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
UpdateConfigFromExtraData(mCurrentConfig.extra_data);
|
||||
|
||||
mDecoder = mPDM->CreateVideoDecoder(mCurrentConfig,
|
||||
mLayersBackend,
|
||||
mImageContainer,
|
||||
mVideoTaskQueue,
|
||||
mCallback);
|
||||
if (!mDecoder) {
|
||||
mLastError = NS_ERROR_FAILURE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> extra_data =
|
||||
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
UpdateConfigFromExtraData(extra_data);
|
||||
|
||||
nsresult rv = CreateDecoder();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return Init();
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCMediaDataDecoder::IsHardwareAccelerated() const
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->IsHardwareAccelerated();
|
||||
}
|
||||
return MediaDataDecoder::IsHardwareAccelerated();
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::CheckForSPSChange(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> extra_data =
|
||||
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(extra_data) ||
|
||||
mp4_demuxer::AnnexB::CompareExtraData(extra_data,
|
||||
mCurrentConfig.extra_data)) {
|
||||
return NS_OK;
|
||||
}
|
||||
// The SPS has changed, signal to flush the current decoder and create a
|
||||
// new one.
|
||||
mDecoder->Flush();
|
||||
ReleaseMediaResources();
|
||||
return CreateDecoderAndInit(aSample);
|
||||
}
|
||||
|
||||
void
|
||||
AVCCMediaDataDecoder::UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData)
|
||||
{
|
||||
mp4_demuxer::SPSData spsdata;
|
||||
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata) &&
|
||||
spsdata.pic_width > 0 && spsdata.pic_height > 0) {
|
||||
mp4_demuxer::H264::EnsureSPSIsSane(spsdata);
|
||||
mCurrentConfig.image_width = spsdata.pic_width;
|
||||
mCurrentConfig.image_height = spsdata.pic_height;
|
||||
mCurrentConfig.display_width = spsdata.display_width;
|
||||
mCurrentConfig.display_height = spsdata.display_height;
|
||||
}
|
||||
mCurrentConfig.extra_data = aExtraData;
|
||||
}
|
||||
|
||||
// AVCCDecoderModule
|
||||
|
||||
AVCCDecoderModule::AVCCDecoderModule(PlatformDecoderModule* aPDM)
|
||||
: mPDM(aPDM)
|
||||
{
|
||||
MOZ_ASSERT(aPDM);
|
||||
}
|
||||
|
||||
AVCCDecoderModule::~AVCCDecoderModule()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCDecoderModule::Startup()
|
||||
{
|
||||
return mPDM->Startup();
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
AVCCDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
nsRefPtr<MediaDataDecoder> decoder;
|
||||
|
||||
if ((!aConfig.mime_type.EqualsLiteral("video/avc") &&
|
||||
!aConfig.mime_type.EqualsLiteral("video/mp4")) ||
|
||||
!mPDM->DecoderNeedsAVCC(aConfig)) {
|
||||
// There is no need for an AVCC wrapper for non-AVC content.
|
||||
decoder = mPDM->CreateVideoDecoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aVideoTaskQueue,
|
||||
aCallback);
|
||||
} else {
|
||||
decoder = new AVCCMediaDataDecoder(mPDM,
|
||||
aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aVideoTaskQueue,
|
||||
aCallback);
|
||||
}
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
AVCCDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
return mPDM->CreateAudioDecoder(aConfig,
|
||||
aAudioTaskQueue,
|
||||
aCallback);
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return mPDM->SupportsAudioMimeType(aMimeType);
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCDecoderModule::SupportsVideoMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return mPDM->SupportsVideoMimeType(aMimeType);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -1,53 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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_AVCCDecoderModule_h
|
||||
#define mozilla_AVCCDecoderModule_h
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AVCCMediaDataDecoder;
|
||||
|
||||
// AVCCDecoderModule is a PlatformDecoderModule wrapper used to ensure that
|
||||
// only AVCC format is fed to the underlying PlatformDecoderModule.
|
||||
// The AVCCDecoderModule allows playback of content where the SPS NAL may not be
|
||||
// provided in the init segment (e.g. AVC3 or Annex B)
|
||||
// AVCCDecoderModule will monitor the input data, and will delay creation of the
|
||||
// MediaDataDecoder until a SPS and PPS NALs have been extracted.
|
||||
//
|
||||
// AVCC-only decoder modules are AppleVideoDecoder and EMEH264Decoder.
|
||||
|
||||
class AVCCDecoderModule : public PlatformDecoderModule {
|
||||
public:
|
||||
explicit AVCCDecoderModule(PlatformDecoderModule* aPDM);
|
||||
virtual ~AVCCDecoderModule();
|
||||
|
||||
virtual nsresult Startup() override;
|
||||
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
virtual bool SupportsAudioMimeType(const nsACString& aMimeType) override;
|
||||
virtual bool SupportsVideoMimeType(const nsACString& aMimeType) override;
|
||||
|
||||
private:
|
||||
nsRefPtr<PlatformDecoderModule> mPDM;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_AVCCDecoderModule_h
|
@ -238,11 +238,17 @@ public:
|
||||
}
|
||||
|
||||
virtual bool
|
||||
SupportsAudioMimeType(const nsACString& aMimeType) override
|
||||
SupportsMimeType(const nsACString& aMimeType) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
return kNeedNone;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule()
|
||||
|
@ -158,6 +158,7 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
|
||||
, mIsEncrypted(false)
|
||||
, mAreDecodersSetup(false)
|
||||
, mIndexReady(false)
|
||||
, mLastSeenEnd(-1)
|
||||
, mDemuxerMonitor("MP4 Demuxer")
|
||||
#if defined(MP4_READER_DORMANT_HEURISTIC)
|
||||
, mDormantEnabled(Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false))
|
||||
@ -343,7 +344,7 @@ MP4Reader::IsSupportedAudioMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return (aMimeType.EqualsLiteral("audio/mpeg") ||
|
||||
aMimeType.EqualsLiteral("audio/mp4a-latm")) &&
|
||||
mPlatform->SupportsAudioMimeType(aMimeType);
|
||||
mPlatform->SupportsMimeType(aMimeType);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -352,7 +353,7 @@ MP4Reader::IsSupportedVideoMimeType(const nsACString& aMimeType)
|
||||
return (aMimeType.EqualsLiteral("video/mp4") ||
|
||||
aMimeType.EqualsLiteral("video/avc") ||
|
||||
aMimeType.EqualsLiteral("video/x-vnd.on2.vp6")) &&
|
||||
mPlatform->SupportsVideoMimeType(aMimeType);
|
||||
mPlatform->SupportsMimeType(aMimeType);
|
||||
}
|
||||
|
||||
void
|
||||
@ -513,9 +514,10 @@ MP4Reader::EnsureDecodersSetup()
|
||||
NS_ENSURE_TRUE(IsSupportedAudioMimeType(mDemuxer->AudioConfig().mime_type),
|
||||
false);
|
||||
|
||||
mAudio.mDecoder = mPlatform->CreateAudioDecoder(mDemuxer->AudioConfig(),
|
||||
mAudio.mTaskQueue,
|
||||
mAudio.mCallback);
|
||||
mAudio.mDecoder =
|
||||
mPlatform->CreateDecoder(mDemuxer->AudioConfig(),
|
||||
mAudio.mTaskQueue,
|
||||
mAudio.mCallback);
|
||||
NS_ENSURE_TRUE(mAudio.mDecoder != nullptr, false);
|
||||
nsresult rv = mAudio.mDecoder->Init();
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
@ -534,11 +536,12 @@ MP4Reader::EnsureDecodersSetup()
|
||||
mVideo.mTaskQueue,
|
||||
mVideo.mCallback);
|
||||
} else {
|
||||
mVideo.mDecoder = mPlatform->CreateVideoDecoder(mDemuxer->VideoConfig(),
|
||||
mLayersBackendType,
|
||||
mDecoder->GetImageContainer(),
|
||||
mVideo.mTaskQueue,
|
||||
mVideo.mCallback);
|
||||
mVideo.mDecoder =
|
||||
mPlatform->CreateDecoder(mDemuxer->VideoConfig(),
|
||||
mVideo.mTaskQueue,
|
||||
mVideo.mCallback,
|
||||
mLayersBackendType,
|
||||
mDecoder->GetImageContainer());
|
||||
}
|
||||
NS_ENSURE_TRUE(mVideo.mDecoder != nullptr, false);
|
||||
nsresult rv = mVideo.mDecoder->Init();
|
||||
@ -600,7 +603,7 @@ MP4Reader::DisableHardwareAcceleration()
|
||||
mSharedDecoderManager->DisableHardwareAcceleration();
|
||||
|
||||
const VideoDecoderConfig& video = mDemuxer->VideoConfig();
|
||||
if (!mSharedDecoderManager->Recreate(video, mLayersBackendType, mDecoder->GetImageContainer())) {
|
||||
if (!mSharedDecoderManager->Recreate(video)) {
|
||||
MonitorAutoLock mon(mVideo.mMonitor);
|
||||
mVideo.mError = true;
|
||||
if (mVideo.HasPromise()) {
|
||||
@ -1158,4 +1161,39 @@ MP4Reader::VideoIsHardwareAccelerated() const
|
||||
return mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated();
|
||||
}
|
||||
|
||||
void
|
||||
MP4Reader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mLastSeenEnd < 0) {
|
||||
MonitorAutoLock mon(mDemuxerMonitor);
|
||||
mLastSeenEnd = mDecoder->GetResource()->GetLength();
|
||||
if (mLastSeenEnd < 0) {
|
||||
// We dont have a length. Demuxer would have been blocking already.
|
||||
return;
|
||||
}
|
||||
}
|
||||
int64_t end = aOffset + aLength;
|
||||
if (end <= mLastSeenEnd) {
|
||||
return;
|
||||
}
|
||||
mLastSeenEnd = end;
|
||||
|
||||
if (HasVideo()) {
|
||||
auto& decoder = GetDecoderData(kVideo);
|
||||
MonitorAutoLock lock(decoder.mMonitor);
|
||||
decoder.mDemuxEOS = false;
|
||||
}
|
||||
if (HasAudio()) {
|
||||
auto& decoder = GetDecoderData(kAudio);
|
||||
MonitorAutoLock lock(decoder.mMonitor);
|
||||
decoder.mDemuxEOS = false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -77,6 +77,7 @@ public:
|
||||
virtual bool IsMediaSeekable() override;
|
||||
|
||||
virtual int64_t GetEvictionOffset(double aTime) override;
|
||||
virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) override;
|
||||
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) override;
|
||||
|
||||
@ -287,6 +288,7 @@ private:
|
||||
bool mAreDecodersSetup;
|
||||
|
||||
bool mIndexReady;
|
||||
int64_t mLastSeenEnd;
|
||||
Monitor mDemuxerMonitor;
|
||||
nsRefPtr<SharedDecoderManager> mSharedDecoderManager;
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "AVCCDecoderModule.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "WMFDecoderModule.h"
|
||||
@ -32,6 +31,9 @@
|
||||
#include "SharedThreadPool.h"
|
||||
#include "MediaTaskQueue.h"
|
||||
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "H264Converter.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
|
||||
@ -107,10 +109,7 @@ PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy,
|
||||
}
|
||||
|
||||
nsRefPtr<PlatformDecoderModule> emepdm(
|
||||
new AVCCDecoderModule(new EMEDecoderModule(aProxy,
|
||||
pdm,
|
||||
cdmDecodesAudio,
|
||||
cdmDecodesVideo)));
|
||||
new EMEDecoderModule(aProxy, pdm, cdmDecodesAudio, cdmDecodesVideo));
|
||||
return emepdm.forget();
|
||||
}
|
||||
#endif
|
||||
@ -151,13 +150,12 @@ PlatformDecoderModule::CreatePDM()
|
||||
if (sFFmpegDecoderEnabled) {
|
||||
nsRefPtr<PlatformDecoderModule> m = FFmpegRuntimeLinker::CreateDecoderModule();
|
||||
if (m) {
|
||||
nsRefPtr<PlatformDecoderModule> m2(new AVCCDecoderModule(m));
|
||||
return m2.forget();
|
||||
return m.forget();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_APPLEMEDIA
|
||||
nsRefPtr<PlatformDecoderModule> m(new AVCCDecoderModule(new AppleDecoderModule()));
|
||||
nsRefPtr<PlatformDecoderModule> m(new AppleDecoderModule());
|
||||
return m.forget();
|
||||
#endif
|
||||
#ifdef MOZ_GONK_MEDIACODEC
|
||||
@ -173,28 +171,55 @@ PlatformDecoderModule::CreatePDM()
|
||||
}
|
||||
#endif
|
||||
if (sGMPDecoderEnabled) {
|
||||
nsRefPtr<PlatformDecoderModule> m(new AVCCDecoderModule(new GMPDecoderModule()));
|
||||
nsRefPtr<PlatformDecoderModule> m(new GMPDecoderModule());
|
||||
return m.forget();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
PlatformDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType)
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
PlatformDecoderModule::CreateDecoder(const mp4_demuxer::TrackConfig& aConfig,
|
||||
FlushableMediaTaskQueue* aTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer)
|
||||
{
|
||||
return aMimeType.EqualsLiteral("audio/mp4a-latm");
|
||||
nsRefPtr<MediaDataDecoder> m;
|
||||
|
||||
if (aConfig.IsAudioConfig()) {
|
||||
m = CreateAudioDecoder(static_cast<const mp4_demuxer::AudioDecoderConfig&>(aConfig),
|
||||
aTaskQueue,
|
||||
aCallback);
|
||||
return m.forget();
|
||||
}
|
||||
|
||||
if (!aConfig.IsVideoConfig()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (H264Converter::IsH264(aConfig)) {
|
||||
m = new H264Converter(this,
|
||||
static_cast<const mp4_demuxer::VideoDecoderConfig&>(aConfig),
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aTaskQueue,
|
||||
aCallback);
|
||||
} else {
|
||||
m = CreateVideoDecoder(static_cast<const mp4_demuxer::VideoDecoderConfig&>(aConfig),
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aTaskQueue,
|
||||
aCallback);
|
||||
}
|
||||
return m.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
PlatformDecoderModule::SupportsVideoMimeType(const nsACString& aMimeType)
|
||||
PlatformDecoderModule::SupportsMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return aMimeType.EqualsLiteral("video/mp4") || aMimeType.EqualsLiteral("video/avc");
|
||||
}
|
||||
|
||||
bool
|
||||
PlatformDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
{
|
||||
return false;
|
||||
return aMimeType.EqualsLiteral("audio/mp4a-latm") ||
|
||||
aMimeType.EqualsLiteral("video/mp4") ||
|
||||
aMimeType.EqualsLiteral("video/avc");
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <queue>
|
||||
|
||||
namespace mp4_demuxer {
|
||||
class TrackConfig;
|
||||
class VideoDecoderConfig;
|
||||
class AudioDecoderConfig;
|
||||
class MP4Sample;
|
||||
@ -86,7 +87,44 @@ public:
|
||||
bool aHasVideo);
|
||||
#endif
|
||||
|
||||
// Creates an H.264 decoder. The layers backend is passed in so that
|
||||
// Creates a decoder.
|
||||
// See CreateVideoDecoder and CreateAudioDecoder for implementation details.
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateDecoder(const mp4_demuxer::TrackConfig& aConfig,
|
||||
FlushableMediaTaskQueue* aTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE,
|
||||
layers::ImageContainer* aImageContainer = nullptr);
|
||||
|
||||
// An audio decoder module must support AAC by default.
|
||||
// A video decoder must support H264 by default.
|
||||
// If more codecs are to be supported, SupportsMimeType will have
|
||||
// to be extended
|
||||
virtual bool SupportsMimeType(const nsACString& aMimeType);
|
||||
|
||||
enum ConversionRequired {
|
||||
kNeedNone,
|
||||
kNeedAVCC,
|
||||
kNeedAnnexB,
|
||||
};
|
||||
|
||||
// Indicates that the decoder requires a specific format.
|
||||
// The PlatformDecoderModule will convert the demuxed data accordingly before
|
||||
// feeding it to MediaDataDecoder::Input.
|
||||
virtual ConversionRequired DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const = 0;
|
||||
|
||||
virtual void DisableHardwareAcceleration() {}
|
||||
|
||||
virtual bool SupportsSharedDecoders(const mp4_demuxer::VideoDecoderConfig& aConfig) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
PlatformDecoderModule() {}
|
||||
virtual ~PlatformDecoderModule() {}
|
||||
|
||||
friend class H264Converter;
|
||||
// Creates a Video decoder. The layers backend is passed in so that
|
||||
// decoders can determine whether hardware accelerated decoding can be used.
|
||||
// Asynchronous decoding of video should be done in runnables dispatched
|
||||
// to aVideoTaskQueue. If the task queue isn't needed, the decoder should
|
||||
@ -99,10 +137,10 @@ public:
|
||||
// This is called on the decode task queue.
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) = 0;
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) = 0;
|
||||
|
||||
// Creates an Audio decoder with the specified properties.
|
||||
// Asynchronous decoding of audio should be done in runnables dispatched to
|
||||
@ -119,24 +157,6 @@ public:
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) = 0;
|
||||
|
||||
// An audio decoder module must support AAC by default.
|
||||
// If more audio codec is to be supported, SupportsAudioMimeType will have
|
||||
// to be extended
|
||||
virtual bool SupportsAudioMimeType(const nsACString& aMimeType);
|
||||
virtual bool SupportsVideoMimeType(const nsACString& aMimeType);
|
||||
|
||||
// Indicates if the video decoder requires AVCC format.
|
||||
virtual bool DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig);
|
||||
|
||||
virtual void DisableHardwareAcceleration() {}
|
||||
|
||||
virtual bool SupportsSharedDecoders(const mp4_demuxer::VideoDecoderConfig& aConfig) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
PlatformDecoderModule() {}
|
||||
virtual ~PlatformDecoderModule() {}
|
||||
// Caches pref media.fragmented-mp4.use-blank-decoder
|
||||
static bool sUseBlankDecoder;
|
||||
static bool sFFmpegDecoderEnabled;
|
||||
@ -213,7 +233,6 @@ public:
|
||||
// The MP4Reader will not call Input() while it's calling Flush().
|
||||
virtual nsresult Flush() = 0;
|
||||
|
||||
|
||||
// Causes all complete samples in the pipeline that can be decoded to be
|
||||
// output. If the decoder can't produce samples from the current output,
|
||||
// it drops the input samples. The decoder may be holding onto samples
|
||||
@ -244,6 +263,15 @@ public:
|
||||
virtual void AllocateMediaResources() {}
|
||||
virtual void ReleaseMediaResources() {}
|
||||
virtual bool IsHardwareAccelerated() const { return false; }
|
||||
|
||||
// ConfigurationChanged will be called to inform the video or audio decoder
|
||||
// that the format of the next input sample is about to change.
|
||||
// If video decoder, aConfig will be a VideoDecoderConfig object.
|
||||
// If audio decoder, aConfig will be a AudioDecoderConfig object.
|
||||
virtual nsresult ConfigurationChanged(const mp4_demuxer::TrackConfig& aConfig)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -83,15 +83,18 @@ SharedDecoderManager::CreateVideoDecoder(
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
if (!mDecoder) {
|
||||
mLayersBackend = aLayersBackend;
|
||||
mImageContainer = aImageContainer;
|
||||
// We use the manager's task queue for the decoder, rather than the one
|
||||
// passed in, so that none of the objects sharing the decoder can shutdown
|
||||
// the task queue while we're potentially still using it for a *different*
|
||||
// object also sharing the decoder.
|
||||
mDecoder = aPDM->CreateVideoDecoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
mTaskQueue,
|
||||
mCallback);
|
||||
mDecoder =
|
||||
aPDM->CreateDecoder(aConfig,
|
||||
mTaskQueue,
|
||||
mCallback,
|
||||
mLayersBackend,
|
||||
mImageContainer);
|
||||
if (!mDecoder) {
|
||||
mPDM = nullptr;
|
||||
return nullptr;
|
||||
@ -113,17 +116,15 @@ SharedDecoderManager::DisableHardwareAcceleration()
|
||||
}
|
||||
|
||||
bool
|
||||
SharedDecoderManager::Recreate(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer)
|
||||
SharedDecoderManager::Recreate(const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
{
|
||||
mDecoder->Flush();
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = mPDM->CreateVideoDecoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
mTaskQueue,
|
||||
mCallback);
|
||||
mDecoder = mPDM->CreateDecoder(aConfig,
|
||||
mTaskQueue,
|
||||
mCallback,
|
||||
mLayersBackend,
|
||||
mImageContainer);
|
||||
if (!mDecoder) {
|
||||
return false;
|
||||
}
|
||||
|
@ -42,9 +42,7 @@ public:
|
||||
friend class SharedDecoderCallback;
|
||||
|
||||
void DisableHardwareAcceleration();
|
||||
bool Recreate(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer);
|
||||
bool Recreate(const mp4_demuxer::VideoDecoderConfig& aConfig);
|
||||
|
||||
private:
|
||||
virtual ~SharedDecoderManager();
|
||||
@ -52,6 +50,8 @@ private:
|
||||
|
||||
nsRefPtr<PlatformDecoderModule> mPDM;
|
||||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
layers::LayersBackend mLayersBackend;
|
||||
nsRefPtr<layers::ImageContainer> mImageContainer;
|
||||
nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
|
||||
SharedDecoderProxy* mActiveProxy;
|
||||
MediaDataDecoderCallback* mActiveCallback;
|
||||
|
@ -63,10 +63,6 @@ public:
|
||||
}
|
||||
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override {
|
||||
if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return MediaCodecDataDecoder::Input(aSample);
|
||||
}
|
||||
|
||||
@ -248,8 +244,13 @@ public:
|
||||
};
|
||||
|
||||
|
||||
bool AndroidDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType) {
|
||||
return static_cast<bool>(CreateDecoder(aMimeType));
|
||||
bool AndroidDecoderModule::SupportsMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
if (aMimeType.EqualsLiteral("video/mp4") ||
|
||||
aMimeType.EqualsLiteral("video/avc")) {
|
||||
return true;
|
||||
}
|
||||
return static_cast<bool>(mozilla::CreateDecoder(aMimeType));
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
@ -296,6 +297,16 @@ AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig&
|
||||
|
||||
}
|
||||
|
||||
PlatformDecoderModule::ConversionRequired
|
||||
AndroidDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
if (aConfig.IsVideoConfig()) {
|
||||
return kNeedAnnexB;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType,
|
||||
const nsACString& aMimeType,
|
||||
MediaFormat::Param aFormat,
|
||||
|
@ -35,7 +35,10 @@ public:
|
||||
AndroidDecoderModule() {}
|
||||
virtual ~AndroidDecoderModule() {}
|
||||
|
||||
virtual bool SupportsAudioMimeType(const nsACString& aMimeType) override;
|
||||
virtual bool SupportsMimeType(const nsACString& aMimeType) override;
|
||||
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override;
|
||||
};
|
||||
|
||||
class MediaCodecDataDecoder : public MediaDataDecoder {
|
||||
|
@ -192,15 +192,20 @@ AppleDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aC
|
||||
}
|
||||
|
||||
bool
|
||||
AppleDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType)
|
||||
AppleDecoderModule::SupportsMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return aMimeType.EqualsLiteral("audio/mp4a-latm") || aMimeType.EqualsLiteral("audio/mpeg");
|
||||
return aMimeType.EqualsLiteral("audio/mpeg") ||
|
||||
PlatformDecoderModule::SupportsMimeType(aMimeType);
|
||||
}
|
||||
|
||||
bool
|
||||
AppleDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
PlatformDecoderModule::ConversionRequired
|
||||
AppleDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
return true;
|
||||
if (aConfig.IsVideoConfig()) {
|
||||
return kNeedAVCC;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -32,9 +32,10 @@ public:
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
virtual bool SupportsAudioMimeType(const nsACString& aMimeType) override;
|
||||
virtual bool
|
||||
DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) override;
|
||||
virtual bool SupportsMimeType(const nsACString& aMimeType) override;
|
||||
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override;
|
||||
|
||||
static void Init();
|
||||
static nsresult CanDecode();
|
||||
|
@ -253,11 +253,12 @@ EMEDecoderModule::CreateVideoDecoder(const VideoDecoderConfig& aConfig,
|
||||
return wrapper.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateVideoDecoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aVideoTaskQueue,
|
||||
aCallback));
|
||||
nsRefPtr<MediaDataDecoder> decoder(
|
||||
mPDM->CreateDecoder(aConfig,
|
||||
aVideoTaskQueue,
|
||||
aCallback,
|
||||
aLayersBackend,
|
||||
aImageContainer));
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -286,9 +287,8 @@ EMEDecoderModule::CreateAudioDecoder(const AudioDecoderConfig& aConfig,
|
||||
return wrapper.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateAudioDecoder(aConfig,
|
||||
aAudioTaskQueue,
|
||||
aCallback));
|
||||
nsRefPtr<MediaDataDecoder> decoder(
|
||||
mPDM->CreateDecoder(aConfig, aAudioTaskQueue, aCallback));
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -303,10 +303,14 @@ EMEDecoderModule::CreateAudioDecoder(const AudioDecoderConfig& aConfig,
|
||||
return emeDecoder.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
EMEDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
PlatformDecoderModule::ConversionRequired
|
||||
EMEDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
return mCDMDecodesVideo && aConfig.crypto.valid;
|
||||
if (aConfig.IsVideoConfig()) {
|
||||
return kNeedAVCC;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -42,8 +42,8 @@ public:
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
virtual bool
|
||||
DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) override;
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override;
|
||||
|
||||
private:
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
|
@ -51,19 +51,22 @@ public:
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
virtual bool SupportsAudioMimeType(const nsACString& aMimeType) override
|
||||
virtual bool SupportsMimeType(const nsACString& aMimeType) override
|
||||
{
|
||||
return FFmpegAudioDecoder<V>::GetCodecId(aMimeType) != AV_CODEC_ID_NONE;
|
||||
return FFmpegAudioDecoder<V>::GetCodecId(aMimeType) != AV_CODEC_ID_NONE ||
|
||||
FFmpegH264Decoder<V>::GetCodecId(aMimeType) != AV_CODEC_ID_NONE;
|
||||
}
|
||||
|
||||
virtual bool SupportsVideoMimeType(const nsACString& aMimeType) override
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override
|
||||
{
|
||||
return FFmpegH264Decoder<V>::GetCodecId(aMimeType) != AV_CODEC_ID_NONE;
|
||||
}
|
||||
|
||||
virtual bool DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) override
|
||||
{
|
||||
return true;
|
||||
if (aConfig.IsVideoConfig() &&
|
||||
(aConfig.mime_type.EqualsLiteral("video/avc") ||
|
||||
aConfig.mime_type.EqualsLiteral("video/mp4"))) {
|
||||
return PlatformDecoderModule::kNeedAVCC;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -75,11 +75,15 @@ GMPDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aCon
|
||||
return wrapper.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
GMPDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
PlatformDecoderModule::ConversionRequired
|
||||
GMPDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
// GMPVideoCodecType::kGMPVideoCodecH264 specifies that encoded frames must be in AVCC format.
|
||||
return true;
|
||||
if (aConfig.IsVideoConfig()) {
|
||||
return kNeedAVCC;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -31,7 +31,8 @@ public:
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
virtual bool DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) override;
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -51,4 +51,14 @@ GonkDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aCo
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
PlatformDecoderModule::ConversionRequired
|
||||
GonkDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
if (aConfig.IsVideoConfig()) {
|
||||
return kNeedAVCC;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -31,6 +31,9 @@ public:
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
static void Init();
|
||||
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -452,20 +452,6 @@ GonkVideoDecoderManager::SendSampleToOMX(mp4_demuxer::MP4Sample* aSample)
|
||||
0);
|
||||
}
|
||||
|
||||
bool
|
||||
GonkVideoDecoderManager::PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (aSample != nullptr) {
|
||||
// We must prepare samples in AVC Annex B.
|
||||
if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
|
||||
GVDM_LOG("Failed to convert sample to annex B!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
GonkVideoDecoderManager::ClearQueueFrameTime()
|
||||
{
|
||||
|
@ -58,8 +58,6 @@ public:
|
||||
static void RecycleCallback(TextureClient* aClient, void* aClosure);
|
||||
|
||||
protected:
|
||||
virtual bool PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample) override;
|
||||
|
||||
virtual android::status_t SendSampleToOMX(mp4_demuxer::MP4Sample* aSample) override;
|
||||
|
||||
private:
|
||||
|
@ -5,21 +5,21 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS += [
|
||||
'AVCCDecoderModule.h',
|
||||
'MP4Decoder.h',
|
||||
'MP4Reader.h',
|
||||
'MP4Stream.h',
|
||||
'PlatformDecoderModule.h',
|
||||
'SharedDecoderManager.h',
|
||||
'wrappers/H264Converter.h'
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AVCCDecoderModule.cpp',
|
||||
'BlankDecoderModule.cpp',
|
||||
'MP4Decoder.cpp',
|
||||
'MP4Stream.cpp',
|
||||
'PlatformDecoderModule.cpp',
|
||||
'SharedDecoderManager.cpp',
|
||||
'wrappers/H264Converter.cpp'
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
|
@ -121,19 +121,26 @@ WMFDecoderModule::SupportsSharedDecoders(const mp4_demuxer::VideoDecoderConfig&
|
||||
}
|
||||
|
||||
bool
|
||||
WMFDecoderModule::SupportsVideoMimeType(const nsACString& aMimeType)
|
||||
WMFDecoderModule::SupportsMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return aMimeType.EqualsLiteral("video/mp4") ||
|
||||
aMimeType.EqualsLiteral("video/avc") ||
|
||||
aMimeType.EqualsLiteral("video/webm; codecs=vp8") ||
|
||||
aMimeType.EqualsLiteral("video/webm; codecs=vp9");
|
||||
aMimeType.EqualsLiteral("video/webm; codecs=vp9") ||
|
||||
aMimeType.EqualsLiteral("audio/mp4a-latm") ||
|
||||
aMimeType.EqualsLiteral("audio/mpeg");
|
||||
}
|
||||
|
||||
bool
|
||||
WMFDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType)
|
||||
PlatformDecoderModule::ConversionRequired
|
||||
WMFDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
return aMimeType.EqualsLiteral("audio/mp4a-latm") ||
|
||||
aMimeType.EqualsLiteral("audio/mpeg");
|
||||
if (aConfig.IsVideoConfig() &&
|
||||
(aConfig.mime_type.EqualsLiteral("video/avc") ||
|
||||
aConfig.mime_type.EqualsLiteral("video/mp4"))) {
|
||||
return kNeedAnnexB;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -31,8 +31,7 @@ public:
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
bool SupportsVideoMimeType(const nsACString& aMimeType) override;
|
||||
bool SupportsAudioMimeType(const nsACString& aMimeType) override;
|
||||
bool SupportsMimeType(const nsACString& aMimeType) override;
|
||||
|
||||
virtual void DisableHardwareAcceleration() override
|
||||
{
|
||||
@ -41,6 +40,9 @@ public:
|
||||
|
||||
virtual bool SupportsSharedDecoders(const mp4_demuxer::VideoDecoderConfig& aConfig) const override;
|
||||
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override;
|
||||
|
||||
// Accessors that report whether we have the required MFTs available
|
||||
// on the system to play various codecs. Windows Vista doesn't have the
|
||||
// H.264/AAC decoders if the "Platform Update Supplement for Windows Vista"
|
||||
|
@ -241,12 +241,6 @@ WMFVideoMFTManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
// This can happen during shutdown.
|
||||
return E_FAIL;
|
||||
}
|
||||
if (mStreamType != VP8 && mStreamType != VP9) {
|
||||
// We must prepare samples in AVC Annex B.
|
||||
if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
// Forward sample data to the decoder.
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
|
||||
uint32_t length = aSample->size;
|
||||
|
249
dom/media/fmp4/wrappers/H264Converter.cpp
Normal file
249
dom/media/fmp4/wrappers/H264Converter.cpp
Normal file
@ -0,0 +1,249 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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 "H264Converter.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "MediaTaskQueue.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "mp4_demuxer/AnnexB.h"
|
||||
#include "mp4_demuxer/H264.h"
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
|
||||
// H264 AnnexB or AVCC handler
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "mp4_demuxer/AnnexB.h"
|
||||
#include "mp4_demuxer/H264.h"
|
||||
|
||||
H264Converter::H264Converter(PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
: mPDM(aPDM)
|
||||
, mCurrentConfig(aConfig)
|
||||
, mLayersBackend(aLayersBackend)
|
||||
, mImageContainer(aImageContainer)
|
||||
, mVideoTaskQueue(aVideoTaskQueue)
|
||||
, mCallback(aCallback)
|
||||
, mDecoder(nullptr)
|
||||
, mNeedAVCC(aPDM->DecoderNeedsConversion(aConfig) == PlatformDecoderModule::kNeedAVCC)
|
||||
, mLastError(NS_OK)
|
||||
{
|
||||
CreateDecoder();
|
||||
}
|
||||
|
||||
H264Converter::~H264Converter()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::Init()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Init();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (!mNeedAVCC) {
|
||||
if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
nsresult rv;
|
||||
if (!mDecoder) {
|
||||
// It is not possible to create an AVCC H264 decoder without SPS.
|
||||
// As such, creation will fail if the extra_data just extracted doesn't
|
||||
// contain a SPS.
|
||||
rv = CreateDecoderAndInit(aSample);
|
||||
if (rv == NS_ERROR_NOT_INITIALIZED) {
|
||||
// We are missing the required SPS to create the decoder.
|
||||
// Ignore for the time being, the MP4Sample will be dropped.
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
rv = CheckForSPSChange(aSample);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aSample->extra_data = mCurrentConfig.extra_data;
|
||||
|
||||
return mDecoder->Input(aSample);
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::Flush()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Flush();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::Drain()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Drain();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::Shutdown()
|
||||
{
|
||||
if (mDecoder) {
|
||||
nsresult rv = mDecoder->Shutdown();
|
||||
mDecoder = nullptr;
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
H264Converter::IsWaitingMediaResources()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->IsWaitingMediaResources();
|
||||
}
|
||||
return MediaDataDecoder::IsWaitingMediaResources();
|
||||
}
|
||||
|
||||
bool
|
||||
H264Converter::IsDormantNeeded()
|
||||
{
|
||||
if (mNeedAVCC) {
|
||||
return true;
|
||||
}
|
||||
return mDecoder ?
|
||||
mDecoder->IsDormantNeeded() : MediaDataDecoder::IsDormantNeeded();
|
||||
}
|
||||
|
||||
void
|
||||
H264Converter::AllocateMediaResources()
|
||||
{
|
||||
if (mNeedAVCC) {
|
||||
// Nothing to do, decoder will be allocated on the fly when required.
|
||||
return;
|
||||
}
|
||||
if (mDecoder) {
|
||||
mDecoder->AllocateMediaResources();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
H264Converter::ReleaseMediaResources()
|
||||
{
|
||||
if (mNeedAVCC) {
|
||||
Shutdown();
|
||||
return;
|
||||
}
|
||||
if (mDecoder) {
|
||||
mDecoder->ReleaseMediaResources();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
H264Converter::IsHardwareAccelerated() const
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->IsHardwareAccelerated();
|
||||
}
|
||||
return MediaDataDecoder::IsHardwareAccelerated();
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::CreateDecoder()
|
||||
{
|
||||
if (mNeedAVCC && !mp4_demuxer::AnnexB::HasSPS(mCurrentConfig.extra_data)) {
|
||||
// nothing found yet, will try again later
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
UpdateConfigFromExtraData(mCurrentConfig.extra_data);
|
||||
|
||||
mDecoder = mPDM->CreateVideoDecoder(mCurrentConfig,
|
||||
mLayersBackend,
|
||||
mImageContainer,
|
||||
mVideoTaskQueue,
|
||||
mCallback);
|
||||
if (!mDecoder) {
|
||||
mLastError = NS_ERROR_FAILURE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> extra_data =
|
||||
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
UpdateConfigFromExtraData(extra_data);
|
||||
|
||||
nsresult rv = CreateDecoder();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return Init();
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::CheckForSPSChange(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> extra_data =
|
||||
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(extra_data) ||
|
||||
mp4_demuxer::AnnexB::CompareExtraData(extra_data,
|
||||
mCurrentConfig.extra_data)) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (!mNeedAVCC) {
|
||||
UpdateConfigFromExtraData(extra_data);
|
||||
mDecoder->ConfigurationChanged(mCurrentConfig);
|
||||
return NS_OK;
|
||||
}
|
||||
// The SPS has changed, signal to flush the current decoder and create a
|
||||
// new one.
|
||||
mDecoder->Flush();
|
||||
ReleaseMediaResources();
|
||||
return CreateDecoderAndInit(aSample);
|
||||
}
|
||||
|
||||
void
|
||||
H264Converter::UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData)
|
||||
{
|
||||
mp4_demuxer::SPSData spsdata;
|
||||
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata) &&
|
||||
spsdata.pic_width > 0 && spsdata.pic_height > 0) {
|
||||
mp4_demuxer::H264::EnsureSPSIsSane(spsdata);
|
||||
mCurrentConfig.image_width = spsdata.pic_width;
|
||||
mCurrentConfig.image_height = spsdata.pic_height;
|
||||
mCurrentConfig.display_width = spsdata.display_width;
|
||||
mCurrentConfig.display_height = spsdata.display_height;
|
||||
}
|
||||
mCurrentConfig.extra_data = aExtraData;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
H264Converter::IsH264(const mp4_demuxer::TrackConfig& aConfig)
|
||||
{
|
||||
return aConfig.mime_type.EqualsLiteral("video/avc") ||
|
||||
aConfig.mime_type.EqualsLiteral("video/mp4");
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
68
dom/media/fmp4/wrappers/H264Converter.h
Normal file
68
dom/media/fmp4/wrappers/H264Converter.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* 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_H264Converter_h
|
||||
#define mozilla_H264Converter_h
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// H264Converter is a MediaDataDecoder wrapper used to ensure that
|
||||
// only AVCC or AnnexB is fed to the underlying MediaDataDecoder.
|
||||
// The H264Converter allows playback of content where the SPS NAL may not be
|
||||
// provided in the init segment (e.g. AVC3 or Annex B)
|
||||
// H264Converter will monitor the input data, and will delay creation of the
|
||||
// MediaDataDecoder until a SPS and PPS NALs have been extracted.
|
||||
|
||||
class H264Converter : public MediaDataDecoder {
|
||||
public:
|
||||
|
||||
H264Converter(PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback);
|
||||
virtual ~H264Converter();
|
||||
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
virtual bool IsWaitingMediaResources() override;
|
||||
virtual bool IsDormantNeeded() override;
|
||||
virtual void AllocateMediaResources() override;
|
||||
virtual void ReleaseMediaResources() override;
|
||||
virtual bool IsHardwareAccelerated() const override;
|
||||
|
||||
// Return true if mimetype is H.264.
|
||||
static bool IsH264(const mp4_demuxer::TrackConfig& aConfig);
|
||||
|
||||
private:
|
||||
// Will create the required MediaDataDecoder if need AVCC and we have a SPS NAL.
|
||||
// Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and
|
||||
// will set mError accordingly.
|
||||
nsresult CreateDecoder();
|
||||
nsresult CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample);
|
||||
nsresult CheckForSPSChange(mp4_demuxer::MP4Sample* aSample);
|
||||
void UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData);
|
||||
|
||||
nsRefPtr<PlatformDecoderModule> mPDM;
|
||||
mp4_demuxer::VideoDecoderConfig mCurrentConfig;
|
||||
layers::LayersBackend mLayersBackend;
|
||||
nsRefPtr<layers::ImageContainer> mImageContainer;
|
||||
nsRefPtr<FlushableMediaTaskQueue> mVideoTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
bool mNeedAVCC;
|
||||
nsresult mLastError;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_H264Converter_h
|
@ -565,8 +565,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
|
||||
EXPECT_TRUE(IsGMPStorageIsEmpty());
|
||||
|
||||
const nsString origin1 = NS_LITERAL_STRING("example1.com");
|
||||
const nsString origin2 = NS_LITERAL_STRING("example2.org");
|
||||
const nsString origin1 = NS_LITERAL_STRING("http://example1.com");
|
||||
const nsString origin2 = NS_LITERAL_STRING("http://example2.org");
|
||||
|
||||
nsCString PBnodeId1 = GetNodeId(origin1, origin2, true);
|
||||
nsCString PBnodeId2 = GetNodeId(origin1, origin2, true);
|
||||
@ -602,8 +602,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
|
||||
// Once we clear storage, the node ids generated for the same origin-pair
|
||||
// should be different.
|
||||
const nsString origin1 = NS_LITERAL_STRING("example1.com");
|
||||
const nsString origin2 = NS_LITERAL_STRING("example2.org");
|
||||
const nsString origin1 = NS_LITERAL_STRING("http://example1.com");
|
||||
const nsString origin2 = NS_LITERAL_STRING("http://example2.org");
|
||||
nsCString nodeId3 = GetNodeId(origin1, origin2, false);
|
||||
EXPECT_TRUE(!aNodeId1.Equals(nodeId3));
|
||||
|
||||
@ -707,8 +707,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
Expect(NS_LITERAL_CSTRING("test-storage complete"),
|
||||
NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://example1.com"),
|
||||
NS_LITERAL_STRING("http://example2.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-storage"));
|
||||
}
|
||||
@ -728,8 +728,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
this, &GMPStorageTest::TestForgetThisSite_AnotherSite);
|
||||
Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://example1.com"),
|
||||
NS_LITERAL_STRING("http://example2.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-storage"));
|
||||
}
|
||||
@ -742,8 +742,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
this, &GMPStorageTest::TestForgetThisSite_CollectSiteInfo);
|
||||
Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example3.com"),
|
||||
NS_LITERAL_STRING("example4.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://example3.com"),
|
||||
NS_LITERAL_STRING("http://example4.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-storage"));
|
||||
}
|
||||
@ -771,7 +771,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
|
||||
void TestForgetThisSite_CollectSiteInfo() {
|
||||
nsAutoPtr<NodeInfo> siteInfo(
|
||||
new NodeInfo(NS_LITERAL_CSTRING("example1.com")));
|
||||
new NodeInfo(NS_LITERAL_CSTRING("http://example1.com")));
|
||||
// Collect nodeIds that are expected to remain for later comparison.
|
||||
EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), NodeIdCollector(siteInfo));
|
||||
// Invoke "Forget this site" on the main thread.
|
||||
@ -861,8 +861,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
this, &GMPStorageTest::TestClearRecentHistory1_Clear);
|
||||
Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://example1.com"),
|
||||
NS_LITERAL_STRING("http://example2.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-storage"));
|
||||
}
|
||||
@ -883,8 +883,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
this, &GMPStorageTest::TestClearRecentHistory2_Clear);
|
||||
Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://example1.com"),
|
||||
NS_LITERAL_STRING("http://example2.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-storage"));
|
||||
}
|
||||
@ -905,8 +905,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
this, &GMPStorageTest::TestClearRecentHistory3_Clear);
|
||||
Expect(NS_LITERAL_CSTRING("test-storage complete"), r);
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example1.com"),
|
||||
NS_LITERAL_STRING("example2.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://example1.com"),
|
||||
NS_LITERAL_STRING("http://example2.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-storage"));
|
||||
}
|
||||
@ -1019,8 +1019,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
|
||||
// Open decryptor on one, origin, write a record, and test that that
|
||||
// record can't be read on another origin.
|
||||
CreateDecryptor(NS_LITERAL_STRING("example3.com"),
|
||||
NS_LITERAL_STRING("example4.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://example3.com"),
|
||||
NS_LITERAL_STRING("http://example4.com"),
|
||||
false,
|
||||
update);
|
||||
}
|
||||
@ -1033,8 +1033,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
Expect(NS_LITERAL_CSTRING("retrieve crossOriginTestRecordId succeeded (length 0 bytes)"),
|
||||
NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example5.com"),
|
||||
NS_LITERAL_STRING("example6.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://example5.com"),
|
||||
NS_LITERAL_STRING("http://example6.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("retrieve crossOriginTestRecordId"));
|
||||
}
|
||||
@ -1050,8 +1050,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
// open another, and test that record can be read, close decryptor,
|
||||
// then send pb-last-context-closed notification, then open decryptor
|
||||
// and check that it can't read that data; it should have been purged.
|
||||
CreateDecryptor(NS_LITERAL_STRING("pb1.com"),
|
||||
NS_LITERAL_STRING("pb2.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://pb1.com"),
|
||||
NS_LITERAL_STRING("http://pb2.com"),
|
||||
true,
|
||||
NS_LITERAL_CSTRING("store pbdata test-pb-data"));
|
||||
}
|
||||
@ -1063,8 +1063,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
NS_NewRunnableMethod(this,
|
||||
&GMPStorageTest::TestPBStorage_RecordRetrievedContinuation));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("pb1.com"),
|
||||
NS_LITERAL_STRING("pb2.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://pb1.com"),
|
||||
NS_LITERAL_STRING("http://pb2.com"),
|
||||
true,
|
||||
NS_LITERAL_CSTRING("retrieve pbdata"));
|
||||
}
|
||||
@ -1077,8 +1077,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
NS_NewRunnableMethod(this,
|
||||
&GMPStorageTest::SetFinished));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("pb1.com"),
|
||||
NS_LITERAL_STRING("pb2.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://pb1.com"),
|
||||
NS_LITERAL_STRING("http://pb2.com"),
|
||||
true,
|
||||
NS_LITERAL_CSTRING("retrieve pbdata"));
|
||||
}
|
||||
@ -1108,20 +1108,20 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
void TestAsyncShutdownTimeout() {
|
||||
// Create decryptors that timeout in their async shutdown.
|
||||
// If the gtest hangs on shutdown, test fails!
|
||||
CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("example7.com"),
|
||||
NS_LITERAL_STRING("example8.com"),
|
||||
CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("http://example7.com"),
|
||||
NS_LITERAL_STRING("http://example8.com"),
|
||||
&GMPStorageTest::TestAsyncShutdownTimeout2);
|
||||
};
|
||||
|
||||
void TestAsyncShutdownTimeout2() {
|
||||
CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("example9.com"),
|
||||
NS_LITERAL_STRING("example10.com"),
|
||||
CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("http://example9.com"),
|
||||
NS_LITERAL_STRING("http://example10.com"),
|
||||
&GMPStorageTest::TestAsyncShutdownTimeout3);
|
||||
};
|
||||
|
||||
void TestAsyncShutdownTimeout3() {
|
||||
CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("example11.com"),
|
||||
NS_LITERAL_STRING("example12.com"),
|
||||
CreateAsyncShutdownTimeoutGMP(NS_LITERAL_STRING("http://example11.com"),
|
||||
NS_LITERAL_STRING("http://example12.com"),
|
||||
&GMPStorageTest::SetFinished);
|
||||
};
|
||||
|
||||
@ -1144,8 +1144,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
|
||||
// Test that a GMP can write to storage during shutdown, and retrieve
|
||||
// that written data in a subsequent session.
|
||||
CreateDecryptor(NS_LITERAL_STRING("example13.com"),
|
||||
NS_LITERAL_STRING("example14.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://example13.com"),
|
||||
NS_LITERAL_STRING("http://example14.com"),
|
||||
false,
|
||||
update);
|
||||
}
|
||||
@ -1163,8 +1163,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
Expect(response,
|
||||
NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example13.com"),
|
||||
NS_LITERAL_STRING("example14.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://example13.com"),
|
||||
NS_LITERAL_STRING("http://example14.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("retrieve-shutdown-token"));
|
||||
}
|
||||
@ -1176,8 +1176,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
Expect(NS_LITERAL_CSTRING("OP tests completed"),
|
||||
NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example15.com"),
|
||||
NS_LITERAL_STRING("example16.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://example15.com"),
|
||||
NS_LITERAL_STRING("http://example16.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("test-op-apis"));
|
||||
}
|
||||
@ -1187,8 +1187,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
Expect(NS_LITERAL_CSTRING("retrieved plugin-voucher: gmp-fake placeholder voucher"),
|
||||
NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished));
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("example17.com"),
|
||||
NS_LITERAL_STRING("example18.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://example17.com"),
|
||||
NS_LITERAL_STRING("http://example18.com"),
|
||||
false,
|
||||
NS_LITERAL_CSTRING("retrieve-plugin-voucher"));
|
||||
}
|
||||
@ -1237,8 +1237,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
Expect(response, continuation);
|
||||
}
|
||||
|
||||
CreateDecryptor(NS_LITERAL_STRING("foo.com"),
|
||||
NS_LITERAL_STRING("bar.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://foo.com"),
|
||||
NS_LITERAL_STRING("http://bar.com"),
|
||||
aPrivateBrowsing,
|
||||
Move(updates));
|
||||
}
|
||||
@ -1290,8 +1290,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
|
||||
update.Append(longRecordName);
|
||||
update.AppendLiteral(" ");
|
||||
update.Append(data);
|
||||
CreateDecryptor(NS_LITERAL_STRING("fuz.com"),
|
||||
NS_LITERAL_STRING("baz.com"),
|
||||
CreateDecryptor(NS_LITERAL_STRING("http://fuz.com"),
|
||||
NS_LITERAL_STRING("http://baz.com"),
|
||||
false,
|
||||
update);
|
||||
}
|
||||
|
@ -168,12 +168,16 @@ MediaSourceReader::RequestAudioData()
|
||||
&MediaSourceReader::CompleteAudioSeekAndRejectPromise));
|
||||
break;
|
||||
case SOURCE_NONE:
|
||||
if (mLastAudioTime) {
|
||||
if (!mLastAudioTime) {
|
||||
// This is the first call to RequestAudioData.
|
||||
// Fallback to using decoder with earliest data.
|
||||
mAudioSourceDecoder = FirstDecoder(MediaData::AUDIO_DATA);
|
||||
}
|
||||
if (mLastAudioTime || !mAudioSourceDecoder) {
|
||||
CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime);
|
||||
break;
|
||||
}
|
||||
// Fallback to using first reader
|
||||
mAudioSourceDecoder = mAudioTrack->Decoders()[0];
|
||||
// Fallback to getting first frame from first decoder.
|
||||
default:
|
||||
DoAudioRequest();
|
||||
break;
|
||||
@ -338,12 +342,16 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
|
||||
&MediaSourceReader::CompleteVideoSeekAndRejectPromise));
|
||||
break;
|
||||
case SOURCE_NONE:
|
||||
if (mLastVideoTime) {
|
||||
if (!mLastVideoTime) {
|
||||
// This is the first call to RequestVideoData.
|
||||
// Fallback to using decoder with earliest data.
|
||||
mVideoSourceDecoder = FirstDecoder(MediaData::VIDEO_DATA);
|
||||
}
|
||||
if (mLastVideoTime || !mVideoSourceDecoder) {
|
||||
CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
|
||||
break;
|
||||
}
|
||||
// Fallback to using first reader.
|
||||
mVideoSourceDecoder = mVideoTrack->Decoders()[0];
|
||||
// Fallback to getting first frame from first decoder.
|
||||
default:
|
||||
DoVideoRequest();
|
||||
break;
|
||||
@ -1033,6 +1041,36 @@ MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<SourceBufferDecoder>
|
||||
MediaSourceReader::FirstDecoder(MediaData::Type aType)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
TrackBuffer* trackBuffer =
|
||||
aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
|
||||
MOZ_ASSERT(trackBuffer);
|
||||
const nsTArray<nsRefPtr<SourceBufferDecoder>>& decoders = trackBuffer->Decoders();
|
||||
if (decoders.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<SourceBufferDecoder> firstDecoder;
|
||||
double lowestStartTime = PositiveInfinity<double>();
|
||||
|
||||
for (uint32_t i = 0; i < decoders.Length(); ++i) {
|
||||
nsRefPtr<TimeRanges> r = new TimeRanges();
|
||||
decoders[i]->GetBuffered(r);
|
||||
double start = r->GetStartTime();
|
||||
if (start < 0) {
|
||||
continue;
|
||||
}
|
||||
if (start < lowestStartTime) {
|
||||
firstDecoder = decoders[i];
|
||||
lowestStartTime = start;
|
||||
}
|
||||
}
|
||||
return firstDecoder.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDecoderReader::WaitForDataPromise>
|
||||
MediaSourceReader::WaitForData(MediaData::Type aType)
|
||||
{
|
||||
@ -1053,13 +1091,23 @@ MediaSourceReader::MaybeNotifyHaveData()
|
||||
// The next Request*Data will handle END_OF_STREAM or going back into waiting
|
||||
// mode.
|
||||
if (!IsSeeking() && mAudioTrack) {
|
||||
haveAudio = HaveData(mLastAudioTime, MediaData::AUDIO_DATA);
|
||||
if (!mLastAudioTime) {
|
||||
nsRefPtr<SourceBufferDecoder> d = FirstDecoder(MediaData::AUDIO_DATA);
|
||||
haveAudio = !!d;
|
||||
} else {
|
||||
haveAudio = HaveData(mLastAudioTime, MediaData::AUDIO_DATA);
|
||||
}
|
||||
if (ended || haveAudio) {
|
||||
WaitPromise(MediaData::AUDIO_DATA).ResolveIfExists(MediaData::AUDIO_DATA, __func__);
|
||||
}
|
||||
}
|
||||
if (!IsSeeking() && mVideoTrack) {
|
||||
haveVideo = HaveData(mLastVideoTime, MediaData::VIDEO_DATA);
|
||||
if (!mLastVideoTime) {
|
||||
nsRefPtr<SourceBufferDecoder> d = FirstDecoder(MediaData::VIDEO_DATA);
|
||||
haveVideo = !!d;
|
||||
} else {
|
||||
haveVideo = HaveData(mLastVideoTime, MediaData::VIDEO_DATA);
|
||||
}
|
||||
if (ended || haveVideo) {
|
||||
WaitPromise(MediaData::VIDEO_DATA).ResolveIfExists(MediaData::VIDEO_DATA, __func__);
|
||||
}
|
||||
|
@ -223,6 +223,7 @@ private:
|
||||
int64_t aTolerance /* microseconds */,
|
||||
const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders);
|
||||
bool HaveData(int64_t aTarget, MediaData::Type aType);
|
||||
already_AddRefed<SourceBufferDecoder> FirstDecoder(MediaData::Type aType);
|
||||
|
||||
void AttemptSeek();
|
||||
bool IsSeeking() { return mPendingSeekTime != -1; }
|
||||
|
@ -116,7 +116,7 @@ IntelWebMVideoDecoder::IsSupportedVideoMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return (aMimeType.EqualsLiteral("video/webm; codecs=vp8") ||
|
||||
aMimeType.EqualsLiteral("video/webm; codecs=vp9")) &&
|
||||
mPlatform->SupportsVideoMimeType(aMimeType);
|
||||
mPlatform->SupportsMimeType(aMimeType);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -147,11 +147,12 @@ IntelWebMVideoDecoder::Init(unsigned int aWidth, unsigned int aHeight)
|
||||
if (!IsSupportedVideoMimeType(video.mime_type)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mMediaDataDecoder = mPlatform->CreateVideoDecoder(video,
|
||||
mReader->GetLayersBackendType(),
|
||||
mReader->GetDecoder()->GetImageContainer(),
|
||||
mTaskQueue,
|
||||
this);
|
||||
mMediaDataDecoder =
|
||||
mPlatform->CreateDecoder(video,
|
||||
mTaskQueue,
|
||||
this,
|
||||
mReader->GetLayersBackendType(),
|
||||
mReader->GetDecoder()->GetImageContainer());
|
||||
if (!mMediaDataDecoder) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -470,8 +470,9 @@ MediaEngineGonkVideoSource::StartImpl(webrtc::CaptureCapability aCapability) {
|
||||
config.mMode = ICameraControl::kPictureMode;
|
||||
config.mPreviewSize.width = aCapability.width;
|
||||
config.mPreviewSize.height = aCapability.height;
|
||||
config.mPictureSize.width = aCapability.width;
|
||||
config.mPictureSize.height = aCapability.height;
|
||||
mCameraControl->Start(&config);
|
||||
mCameraControl->Set(CAMERA_PARAM_PICTURE_SIZE, config.mPreviewSize);
|
||||
|
||||
hal::RegisterScreenConfigurationObserver(this);
|
||||
}
|
||||
|
@ -321,6 +321,9 @@ function testOpenWithoutClose() {
|
||||
closed.push(socket.closed);
|
||||
}
|
||||
|
||||
SpecialPowers.gc();
|
||||
info('all unrefereced socket should be closed right after GC');
|
||||
|
||||
return Promise.all(closed);
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ CreateDrawTargetForSurface(gfxASurface *aSurface)
|
||||
}
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(),
|
||||
ToIntSize(gfxIntSize(aSurface->GetSize())),
|
||||
aSurface->GetSize(),
|
||||
&format);
|
||||
aSurface->SetData(&kDrawTarget, drawTarget, nullptr);
|
||||
return drawTarget;
|
||||
|
@ -1441,35 +1441,13 @@ PromiseWorkerProxy::StoreISupports(nsISupports* aSupports)
|
||||
mSupportsArray.AppendElement(supports);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class PromiseWorkerProxyControlRunnable final
|
||||
: public WorkerControlRunnable
|
||||
bool
|
||||
PromiseWorkerProxyControlRunnable::WorkerRun(JSContext* aCx,
|
||||
WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
nsRefPtr<PromiseWorkerProxy> mProxy;
|
||||
|
||||
public:
|
||||
PromiseWorkerProxyControlRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
PromiseWorkerProxy* aProxy)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
|
||||
, mProxy(aProxy)
|
||||
{
|
||||
MOZ_ASSERT(aProxy);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
mProxy->CleanUp(aCx);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
~PromiseWorkerProxyControlRunnable()
|
||||
{}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
mProxy->CleanUp(aCx);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PromiseWorkerProxy::RunCallback(JSContext* aCx,
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "mozilla/dom/workers/bindings/WorkerFeature.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
#include "WorkerRunnable.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@ -53,8 +55,12 @@ class WorkerPrivate;
|
||||
// dispatch a runnable to the worker. Use GetWorkerPrivate() to acquire the
|
||||
// worker. This might be null! In the WorkerRunnable's WorkerRun() use
|
||||
// GetWorkerPromise() to access the Promise and resolve/reject it. Then call
|
||||
// CleanUp() on the worker
|
||||
// thread.
|
||||
// CleanUp() on the worker thread.
|
||||
//
|
||||
// IMPORTANT: Dispatching the runnable to the worker thread may fail causing
|
||||
// the promise to leak. To successfully release the promise on the
|
||||
// worker thread in this case, use |PromiseWorkerProxyControlRunnable| to
|
||||
// dispatch a control runnable that will deref the object on the correct thread.
|
||||
|
||||
class PromiseWorkerProxy : public PromiseNativeHandler,
|
||||
public workers::WorkerFeature
|
||||
@ -78,6 +84,17 @@ public:
|
||||
|
||||
void CleanUp(JSContext* aCx);
|
||||
|
||||
Mutex& GetCleanUpLock()
|
||||
{
|
||||
return mCleanUpLock;
|
||||
}
|
||||
|
||||
bool IsClean() const
|
||||
{
|
||||
mCleanUpLock.AssertCurrentThreadOwns();
|
||||
return mCleanedUp;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void ResolvedCallback(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue) override;
|
||||
@ -119,6 +136,30 @@ private:
|
||||
Mutex mCleanUpLock;
|
||||
};
|
||||
|
||||
// Helper runnable used for releasing the proxied promise when the worker
|
||||
// is not accepting runnables and the promise object would leak.
|
||||
// See the instructions above.
|
||||
class PromiseWorkerProxyControlRunnable final : public workers::WorkerControlRunnable
|
||||
{
|
||||
nsRefPtr<PromiseWorkerProxy> mProxy;
|
||||
|
||||
public:
|
||||
PromiseWorkerProxyControlRunnable(workers::WorkerPrivate* aWorkerPrivate,
|
||||
PromiseWorkerProxy* aProxy)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
|
||||
, mProxy(aProxy)
|
||||
{
|
||||
MOZ_ASSERT(aProxy);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
WorkerRun(JSContext* aCx, workers::WorkerPrivate* aWorkerPrivate) override;
|
||||
|
||||
private:
|
||||
~PromiseWorkerProxyControlRunnable()
|
||||
{}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -22,6 +22,8 @@ interface WindowClient : Client {
|
||||
readonly attribute VisibilityState visibilityState;
|
||||
readonly attribute boolean focused;
|
||||
readonly attribute FrameType frameType;
|
||||
|
||||
[Throws]
|
||||
Promise<WindowClient> focus();
|
||||
};
|
||||
|
||||
|
@ -50,10 +50,10 @@ public:
|
||||
|
||||
ServiceWorkerClient(nsISupports* aOwner,
|
||||
const ServiceWorkerClientInfo& aClientInfo)
|
||||
: mOwner(aOwner),
|
||||
mId(aClientInfo.mClientId),
|
||||
mWindowId(aClientInfo.mWindowId),
|
||||
mUrl(aClientInfo.mUrl)
|
||||
: mOwner(aOwner)
|
||||
, mId(aClientInfo.mClientId)
|
||||
, mUrl(aClientInfo.mUrl)
|
||||
, mWindowId(aClientInfo.mWindowId)
|
||||
{
|
||||
MOZ_ASSERT(aOwner);
|
||||
}
|
||||
@ -89,8 +89,10 @@ protected:
|
||||
private:
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
nsString mId;
|
||||
uint64_t mWindowId;
|
||||
nsString mUrl;
|
||||
|
||||
protected:
|
||||
uint64_t mWindowId;
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
|
@ -4,6 +4,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseWorkerProxy.h"
|
||||
|
||||
#include "ServiceWorkerClient.h"
|
||||
#include "ServiceWorkerClients.h"
|
||||
@ -41,96 +42,17 @@ ServiceWorkerClients::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenPro
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper class used for passing the promise between threads while
|
||||
// keeping the worker alive.
|
||||
class PromiseHolder final : public WorkerFeature
|
||||
{
|
||||
friend class MatchAllRunnable;
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PromiseHolder)
|
||||
|
||||
public:
|
||||
PromiseHolder(WorkerPrivate* aWorkerPrivate,
|
||||
Promise* aPromise)
|
||||
: mWorkerPrivate(aWorkerPrivate),
|
||||
mPromise(aPromise),
|
||||
mCleanUpLock("promiseHolderCleanUpLock"),
|
||||
mClean(false)
|
||||
{
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(mPromise);
|
||||
|
||||
if (NS_WARN_IF(!mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(), this))) {
|
||||
// Worker has been canceled and will go away.
|
||||
// The ResolvePromiseWorkerRunnable won't run, so we can set mPromise to
|
||||
// nullptr.
|
||||
mPromise = nullptr;
|
||||
mClean = true;
|
||||
}
|
||||
}
|
||||
|
||||
Promise*
|
||||
GetPromise() const
|
||||
{
|
||||
return mPromise;
|
||||
}
|
||||
|
||||
void
|
||||
Clean()
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
MutexAutoLock lock(mCleanUpLock);
|
||||
if (mClean) {
|
||||
return;
|
||||
}
|
||||
|
||||
mPromise = nullptr;
|
||||
mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(), this);
|
||||
mClean = true;
|
||||
}
|
||||
|
||||
bool
|
||||
Notify(JSContext* aCx, Status aStatus)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (aStatus > Running) {
|
||||
Clean();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
~PromiseHolder()
|
||||
{
|
||||
MOZ_ASSERT(mClean);
|
||||
}
|
||||
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsRefPtr<Promise> mPromise;
|
||||
|
||||
// Used to prevent race conditions on |mClean| and to ensure that either a
|
||||
// Notify() call or a dispatch back to the worker thread occurs before
|
||||
// this object is released.
|
||||
Mutex mCleanUpLock;
|
||||
|
||||
bool mClean;
|
||||
};
|
||||
|
||||
class ResolvePromiseWorkerRunnable final : public WorkerRunnable
|
||||
{
|
||||
nsRefPtr<PromiseHolder> mPromiseHolder;
|
||||
nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
|
||||
nsTArray<ServiceWorkerClientInfo> mValue;
|
||||
|
||||
public:
|
||||
ResolvePromiseWorkerRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
PromiseHolder* aPromiseHolder,
|
||||
PromiseWorkerProxy* aPromiseProxy,
|
||||
nsTArray<ServiceWorkerClientInfo>& aValue)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
|
||||
mPromiseHolder(aPromiseHolder)
|
||||
mPromiseProxy(aPromiseProxy)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
mValue.SwapElements(aValue);
|
||||
@ -142,7 +64,7 @@ public:
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
Promise* promise = mPromiseHolder->GetPromise();
|
||||
Promise* promise = mPromiseProxy->GetWorkerPromise();
|
||||
MOZ_ASSERT(promise);
|
||||
|
||||
nsTArray<nsRefPtr<ServiceWorkerClient>> ret;
|
||||
@ -154,51 +76,23 @@ public:
|
||||
promise->MaybeResolve(ret);
|
||||
|
||||
// release the reference on the worker thread.
|
||||
mPromiseHolder->Clean();
|
||||
mPromiseProxy->CleanUp(aCx);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class ReleasePromiseRunnable final : public MainThreadWorkerControlRunnable
|
||||
{
|
||||
nsRefPtr<PromiseHolder> mPromiseHolder;
|
||||
|
||||
public:
|
||||
ReleasePromiseRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
PromiseHolder* aPromiseHolder)
|
||||
: MainThreadWorkerControlRunnable(aWorkerPrivate),
|
||||
mPromiseHolder(aPromiseHolder)
|
||||
{ }
|
||||
|
||||
private:
|
||||
~ReleasePromiseRunnable()
|
||||
{ }
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
mPromiseHolder->Clean();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class MatchAllRunnable final : public nsRunnable
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsRefPtr<PromiseHolder> mPromiseHolder;
|
||||
nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
|
||||
nsCString mScope;
|
||||
public:
|
||||
MatchAllRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
PromiseHolder* aPromiseHolder,
|
||||
PromiseWorkerProxy* aPromiseProxy,
|
||||
const nsCString& aScope)
|
||||
: mWorkerPrivate(aWorkerPrivate),
|
||||
mPromiseHolder(aPromiseHolder),
|
||||
mPromiseProxy(aPromiseProxy),
|
||||
mScope(aScope)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
@ -210,8 +104,8 @@ public:
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
MutexAutoLock lock(mPromiseHolder->mCleanUpLock);
|
||||
if (mPromiseHolder->mClean) {
|
||||
MutexAutoLock lock(mPromiseProxy->GetCleanUpLock());
|
||||
if (mPromiseProxy->IsClean()) {
|
||||
// Don't resolve the promise if it was already released.
|
||||
return NS_OK;
|
||||
}
|
||||
@ -221,7 +115,7 @@ public:
|
||||
|
||||
swm->GetAllClients(mScope, result);
|
||||
nsRefPtr<ResolvePromiseWorkerRunnable> r =
|
||||
new ResolvePromiseWorkerRunnable(mWorkerPrivate, mPromiseHolder, result);
|
||||
new ResolvePromiseWorkerRunnable(mWorkerPrivate, mPromiseProxy, result);
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
if (r->Dispatch(cx)) {
|
||||
@ -230,11 +124,11 @@ public:
|
||||
|
||||
// Dispatch to worker thread failed because the worker is shutting down.
|
||||
// Use a control runnable to release the runnable on the worker thread.
|
||||
nsRefPtr<ReleasePromiseRunnable> releaseRunnable =
|
||||
new ReleasePromiseRunnable(mWorkerPrivate, mPromiseHolder);
|
||||
nsRefPtr<PromiseWorkerProxyControlRunnable> releaseRunnable =
|
||||
new PromiseWorkerProxyControlRunnable(mWorkerPrivate, mPromiseProxy);
|
||||
|
||||
if (!releaseRunnable->Dispatch(cx)) {
|
||||
NS_RUNTIMEABORT("Failed to dispatch PromiseHolder control runnable.");
|
||||
NS_RUNTIMEABORT("Failed to dispatch MatchAll promise control runnable.");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -264,16 +158,16 @@ ServiceWorkerClients::MatchAll(const ClientQueryOptions& aOptions,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<PromiseHolder> promiseHolder = new PromiseHolder(workerPrivate,
|
||||
promise);
|
||||
if (!promiseHolder->GetPromise()) {
|
||||
nsRefPtr<PromiseWorkerProxy> promiseProxy =
|
||||
PromiseWorkerProxy::Create(workerPrivate, promise);
|
||||
if (!promiseProxy->GetWorkerPromise()) {
|
||||
// Don't dispatch if adding the worker feature failed.
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<MatchAllRunnable> r =
|
||||
new MatchAllRunnable(workerPrivate,
|
||||
promiseHolder,
|
||||
promiseProxy,
|
||||
NS_ConvertUTF16toUTF8(scope));
|
||||
nsresult rv = NS_DispatchToMainThread(r);
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "ServiceWorkerWindowClient.h"
|
||||
|
||||
#include "mozilla/dom/ClientBinding.h"
|
||||
#include "mozilla/dom/PromiseWorkerProxy.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::dom::workers;
|
||||
@ -17,18 +18,135 @@ ServiceWorkerWindowClient::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGiv
|
||||
return WindowClientBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ServiceWorkerWindowClient::Focus() const
|
||||
namespace {
|
||||
|
||||
// Passing a null clientInfo will reject the promise with InvalidAccessError.
|
||||
class ResolveOrRejectPromiseRunnable final : public WorkerRunnable
|
||||
{
|
||||
ErrorResult result;
|
||||
nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
|
||||
UniquePtr<ServiceWorkerClientInfo> mClientInfo;
|
||||
|
||||
public:
|
||||
ResolveOrRejectPromiseRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
PromiseWorkerProxy* aPromiseProxy,
|
||||
UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
|
||||
, mPromiseProxy(aPromiseProxy)
|
||||
, mClientInfo(Move(aClientInfo))
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
Promise* promise = mPromiseProxy->GetWorkerPromise();
|
||||
MOZ_ASSERT(promise);
|
||||
|
||||
if (mClientInfo) {
|
||||
nsRefPtr<ServiceWorkerWindowClient> client =
|
||||
new ServiceWorkerWindowClient(promise->GetParentObject(), *mClientInfo);
|
||||
promise->MaybeResolve(client);
|
||||
} else {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
}
|
||||
|
||||
// Release the reference on the worker thread.
|
||||
mPromiseProxy->CleanUp(aCx);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class ClientFocusRunnable final : public nsRunnable
|
||||
{
|
||||
uint64_t mWindowId;
|
||||
nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
|
||||
|
||||
public:
|
||||
ClientFocusRunnable(uint64_t aWindowId, PromiseWorkerProxy* aPromiseProxy)
|
||||
: mWindowId(aWindowId)
|
||||
, mPromiseProxy(aPromiseProxy)
|
||||
{
|
||||
MOZ_ASSERT(mPromiseProxy);
|
||||
MOZ_ASSERT(mPromiseProxy->GetWorkerPromise());
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
nsGlobalWindow* window = nsGlobalWindow::GetOuterWindowWithId(mWindowId);
|
||||
UniquePtr<ServiceWorkerClientInfo> clientInfo;
|
||||
|
||||
if (window) {
|
||||
ErrorResult result;
|
||||
//FIXME(catalinb): Bug 1144660 - check if we are allowed to focus here.
|
||||
window->Focus(result);
|
||||
clientInfo.reset(new ServiceWorkerClientInfo(window->GetDocument()));
|
||||
}
|
||||
|
||||
DispatchResult(Move(clientInfo));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
DispatchResult(UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
|
||||
{
|
||||
WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
nsRefPtr<ResolveOrRejectPromiseRunnable> resolveRunnable =
|
||||
new ResolveOrRejectPromiseRunnable(workerPrivate, mPromiseProxy,
|
||||
Move(aClientInfo));
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
JSContext* cx = jsapi.cx();
|
||||
if (!resolveRunnable->Dispatch(cx)) {
|
||||
nsRefPtr<PromiseWorkerProxyControlRunnable> controlRunnable =
|
||||
new PromiseWorkerProxyControlRunnable(workerPrivate, mPromiseProxy);
|
||||
if (!controlRunnable->Dispatch(cx)) {
|
||||
NS_RUNTIMEABORT("Failed to dispatch Focus promise control runnable.");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ServiceWorkerWindowClient::Focus(ErrorResult& aRv) const
|
||||
{
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
workerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
|
||||
MOZ_ASSERT(global);
|
||||
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, result);
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
|
||||
nsRefPtr<PromiseWorkerProxy> promiseProxy =
|
||||
PromiseWorkerProxy::Create(workerPrivate, promise);
|
||||
if (!promiseProxy->GetWorkerPromise()) {
|
||||
// Don't dispatch if adding the worker feature failed.
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<ClientFocusRunnable> r = new ClientFocusRunnable(mWindowId,
|
||||
promiseProxy);
|
||||
aRv = NS_DispatchToMainThread(r);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
promise->MaybeReject(aRv.ErrorCode());
|
||||
}
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Focus() const;
|
||||
Focus(ErrorResult& aRv) const;
|
||||
|
||||
private:
|
||||
~ServiceWorkerWindowClient()
|
||||
|
@ -5898,11 +5898,10 @@ WorkerPrivate::NotifyFeatures(JSContext* aCx, Status aStatus)
|
||||
CancelAllTimeouts(aCx);
|
||||
}
|
||||
|
||||
nsAutoTArray<WorkerFeature*, 30> features;
|
||||
features.AppendElements(mFeatures);
|
||||
|
||||
for (uint32_t index = 0; index < features.Length(); index++) {
|
||||
if (!features[index]->Notify(aCx, aStatus)) {
|
||||
nsTObserverArray<WorkerFeature*>::ForwardIterator iter(mFeatures);
|
||||
while (iter.HasMore()) {
|
||||
WorkerFeature* feature = iter.GetNext();
|
||||
if (!feature->Notify(aCx, aStatus)) {
|
||||
NS_WARNING("Failed to notify feature!");
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
|
||||
#include "Queue.h"
|
||||
@ -852,7 +853,7 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
nsRefPtr<WorkerGlobalScope> mScope;
|
||||
nsRefPtr<WorkerDebuggerGlobalScope> mDebuggerScope;
|
||||
nsTArray<ParentType*> mChildWorkers;
|
||||
nsTArray<WorkerFeature*> mFeatures;
|
||||
nsTObserverArray<WorkerFeature*> mFeatures;
|
||||
nsTArray<nsAutoPtr<TimeoutInfo>> mTimeouts;
|
||||
uint32_t mDebuggerEventLoopLevel;
|
||||
|
||||
|
15
dom/workers/test/serviceworkers/client_focus_worker.js
Normal file
15
dom/workers/test/serviceworkers/client_focus_worker.js
Normal file
@ -0,0 +1,15 @@
|
||||
onmessage = function(e) {
|
||||
if (!e.source) {
|
||||
dump("ERROR: message doesn't have a source.");
|
||||
}
|
||||
|
||||
// The client should be a window client
|
||||
if (e.source instanceof WindowClient) {
|
||||
// this will dispatch a focus event on the client
|
||||
e.source.focus().then(function(client) {
|
||||
client.postMessage(client.focused);
|
||||
});
|
||||
} else {
|
||||
dump("ERROR: client should be a WindowClient");
|
||||
}
|
||||
};
|
@ -17,6 +17,7 @@ support-files =
|
||||
workerUpdate/update.html
|
||||
sw_clients/simple.html
|
||||
sw_clients/service_worker_controlled.html
|
||||
sw_clients/focus_stealing_client.html
|
||||
match_all_worker.js
|
||||
match_all_advanced_worker.js
|
||||
worker_unregister.js
|
||||
@ -63,6 +64,7 @@ support-files =
|
||||
redirect_serviceworker.sjs
|
||||
importscript.sjs
|
||||
importscript_worker.js
|
||||
client_focus_worker.js
|
||||
|
||||
[test_unregister.html]
|
||||
[test_installation_simple.html]
|
||||
@ -89,3 +91,4 @@ skip-if = true # Bug 1136780
|
||||
[test_sandbox_intercept.html]
|
||||
[test_request_context.html]
|
||||
[test_importscript.html]
|
||||
[test_client_focus.html]
|
||||
|
@ -0,0 +1,33 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1130686 - Test service worker client.focus: client </title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<!--
|
||||
We load this as an iframe to blur the main test window.
|
||||
-->
|
||||
</head>
|
||||
<body>/
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
if (!parent) {
|
||||
info("error: sw_clients/focus_stealing_client.html shouldn't be launched directly!");
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
navigator.serviceWorker.ready.then(function() {
|
||||
parent.postMessage("READY", "*");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
94
dom/workers/test/serviceworkers/test_client_focus.html
Normal file
94
dom/workers/test/serviceworkers/test_client_focus.html
Normal file
@ -0,0 +1,94 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1130686 - Test service worker client.focus </title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<!--
|
||||
This test checks that client.focus is able to restore focus to the main window
|
||||
when an iframe is holding the focus.
|
||||
-->
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content"></div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
var registration;
|
||||
var worker;
|
||||
|
||||
function start() {
|
||||
return navigator.serviceWorker.register("client_focus_worker.js",
|
||||
{ scope: "./sw_clients/focus_stealing_client.html" })
|
||||
.then((swr) => registration = swr);
|
||||
}
|
||||
|
||||
function unregister() {
|
||||
return registration.unregister().then(function(result) {
|
||||
ok(result, "Unregister should return true.");
|
||||
});
|
||||
}
|
||||
|
||||
function loseFocus() {
|
||||
var p = new Promise(function(res, rej) {
|
||||
window.onmessage = function(e) {
|
||||
if (e.data == "READY") {
|
||||
ok(true, "iframe created.");
|
||||
iframe.contentWindow.focus();
|
||||
}
|
||||
}
|
||||
window.onblur = function() {
|
||||
ok(true, "blurred");
|
||||
res();
|
||||
}
|
||||
});
|
||||
|
||||
content = document.getElementById("content");
|
||||
ok(content, "parent exists.");
|
||||
|
||||
iframe = document.createElement("iframe");
|
||||
content.appendChild(iframe);
|
||||
|
||||
iframe.setAttribute('src', "sw_clients/focus_stealing_client.html");
|
||||
return p;
|
||||
}
|
||||
|
||||
function testFocus() {
|
||||
var p = new Promise(function(res, rej) {
|
||||
navigator.serviceWorker.onmessage = function(e) {
|
||||
ok(e.data, "client object is marked as focused.");
|
||||
ok(document.hasFocus(), "document has focus.");
|
||||
res();
|
||||
}
|
||||
});
|
||||
|
||||
ok(registration.active, "active worker exists.");
|
||||
registration.active.postMessage("go");
|
||||
return p;
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
start()
|
||||
.then(loseFocus)
|
||||
.then(testFocus)
|
||||
.then(unregister)
|
||||
.catch(function(e) {
|
||||
ok(false, "Some test failed with error " + e);
|
||||
}).then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
]}, runTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -296,7 +296,7 @@ GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size,
|
||||
bool requireCompatProfile)
|
||||
{
|
||||
nsRefPtr<GLContext> glContext = CreateHeadless(requireCompatProfile);
|
||||
if (!glContext->InitOffscreen(ToIntSize(size), caps))
|
||||
if (!glContext->InitOffscreen(size, caps))
|
||||
return nullptr;
|
||||
|
||||
return glContext.forget();
|
||||
|
@ -904,7 +904,7 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
|
||||
if (!glContext)
|
||||
return nullptr;
|
||||
|
||||
if (!glContext->InitOffscreen(ToIntSize(size), caps))
|
||||
if (!glContext->InitOffscreen(size, caps))
|
||||
return nullptr;
|
||||
|
||||
return glContext.forget();
|
||||
|
@ -1234,7 +1234,7 @@ GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size,
|
||||
if (!glContext)
|
||||
return nullptr;
|
||||
|
||||
if (!glContext->InitOffscreen(ToIntSize(size), caps))
|
||||
if (!glContext->InitOffscreen(size, caps))
|
||||
return nullptr;
|
||||
|
||||
return glContext.forget();
|
||||
|
@ -640,7 +640,7 @@ GLContextProviderWGL::CreateHeadless(bool)
|
||||
}
|
||||
|
||||
already_AddRefed<GLContext>
|
||||
GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size,
|
||||
GLContextProviderWGL::CreateOffscreen(const IntSize& size,
|
||||
const SurfaceCaps& caps,
|
||||
bool requireCompatProfile)
|
||||
{
|
||||
@ -648,7 +648,7 @@ GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size,
|
||||
if (!glContext)
|
||||
return nullptr;
|
||||
|
||||
if (!glContext->InitOffscreen(ToIntSize(size), caps))
|
||||
if (!glContext->InitOffscreen(size, caps))
|
||||
return nullptr;
|
||||
|
||||
return glContext.forget();
|
||||
|
@ -126,7 +126,7 @@ DIBTextureHost::DIBTextureHost(TextureFlags aFlags,
|
||||
dont_AddRef(reinterpret_cast<gfxWindowsSurface*>(aDescriptor.surface()));
|
||||
MOZ_ASSERT(mSurface);
|
||||
|
||||
mSize = ToIntSize(mSurface->GetSize());
|
||||
mSize = mSurface->GetSize();
|
||||
mFormat = ImageFormatToSurfaceFormat(
|
||||
gfxPlatform::GetPlatform()->OptimalFormatForContent(mSurface->GetContentType()));
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include <string.h> // for memcpy
|
||||
#include "gfx2DGlue.h" // for ToIntSize
|
||||
#include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory
|
||||
#include "mozilla/gfx/BaseSize.h" // for BaseSize
|
||||
#include "mozilla/gfx/Logging.h" // for gfxDebug
|
||||
|
@ -639,7 +639,7 @@ Transform(const gfxImageSurface* aDest,
|
||||
return;
|
||||
}
|
||||
|
||||
IntSize destSize = ToIntSize(aDest->GetSize());
|
||||
IntSize destSize = aDest->GetSize();
|
||||
SkImageInfo destInfo = SkImageInfo::Make(destSize.width,
|
||||
destSize.height,
|
||||
kBGRA_8888_SkColorType,
|
||||
@ -697,7 +697,7 @@ Transform(const gfxImageSurface* aDest,
|
||||
const gfx3DMatrix& aTransform,
|
||||
gfxPoint aDestOffset)
|
||||
{
|
||||
IntSize destSize = ToIntSize(aDest->GetSize());
|
||||
IntSize destSize = aDest->GetSize();
|
||||
pixman_image_t* dest = pixman_image_create_bits(aDest->Format() == gfxImageFormat::ARGB32 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
|
||||
destSize.width,
|
||||
destSize.height,
|
||||
|
@ -144,7 +144,7 @@ TextureClientX11::BorrowDrawTarget()
|
||||
}
|
||||
|
||||
if (!mDrawTarget) {
|
||||
IntSize size = ToIntSize(mSurface->GetSize());
|
||||
IntSize size = mSurface->GetSize();
|
||||
mDrawTarget = Factory::CreateDrawTargetForCairoSurface(mSurface->CairoSurface(), size);
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ X11TextureSourceBasic::X11TextureSourceBasic(BasicCompositor* aCompositor, gfxXl
|
||||
IntSize
|
||||
X11TextureSourceBasic::GetSize() const
|
||||
{
|
||||
return ToIntSize(mSurface->GetSize());
|
||||
return mSurface->GetSize();
|
||||
}
|
||||
|
||||
SurfaceFormat
|
||||
|
@ -258,17 +258,15 @@ ClientTiledPaintedLayer::UseProgressiveDraw() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXX We probably want to disable progressive drawing for non active APZ layers in the future
|
||||
// but we should wait for a proper test case before making this change.
|
||||
#if 0 //!defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ)
|
||||
LayerMetricsWrapper scrollAncestor;
|
||||
GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
|
||||
MOZ_ASSERT(scrollAncestor); // because mPaintData.mCriticalDisplayPort is non-empty
|
||||
const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
|
||||
if (!IsScrollingOnCompositor(parentMetrics)) {
|
||||
return false;
|
||||
if (gfxPrefs::AsyncPanZoomEnabled()) {
|
||||
LayerMetricsWrapper scrollAncestor;
|
||||
GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
|
||||
MOZ_ASSERT(scrollAncestor); // because mPaintData.mCriticalDisplayPort is non-empty
|
||||
const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
|
||||
if (!IsScrollingOnCompositor(parentMetrics)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -805,7 +805,7 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
|
||||
scrollbarTransform.PostTranslate(xTranslation, 0, 0);
|
||||
}
|
||||
|
||||
Matrix4x4 transform = scrollbarTransform * aScrollbar->GetTransform();
|
||||
Matrix4x4 transform = aScrollbar->GetLocalTransform() * scrollbarTransform;
|
||||
|
||||
if (aScrollbarIsDescendant) {
|
||||
// If the scrollbar layer is a child of the content it is a scrollbar for,
|
||||
|
@ -344,7 +344,8 @@ RenderLayers(ContainerT* aContainer,
|
||||
Layer* layer = layerToRender->GetLayer();
|
||||
|
||||
gfxRGBA color;
|
||||
if (LayerHasCheckerboardingAPZC(layer, &color)) {
|
||||
if ((layer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
|
||||
LayerHasCheckerboardingAPZC(layer, &color)) {
|
||||
// Ideally we would want to intersect the checkerboard region from the APZ with the layer bounds
|
||||
// and only fill in that area. However the layer bounds takes into account the base translation
|
||||
// for the painted layer whereas the checkerboard region does not. One does not simply
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
#include "CompositableHost.h" // for CompositableHost
|
||||
#include "LayersLogging.h" // for AppendToString
|
||||
#include "gfx2DGlue.h" // for ToIntSize
|
||||
#include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory
|
||||
#include "mozilla/ipc/Shmem.h" // for Shmem
|
||||
#include "mozilla/layers/CompositableTransactionParent.h" // for CompositableParentManager
|
||||
|
@ -83,7 +83,7 @@ X11TextureHost::GetFormat() const
|
||||
IntSize
|
||||
X11TextureHost::GetSize() const
|
||||
{
|
||||
return ToIntSize(mSurface->GetSize());
|
||||
return mSurface->GetSize();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1458,18 +1458,24 @@ CompositorD3D11::HandleError(HRESULT hr, Severity aSeverity)
|
||||
if (SUCCEEDED(hr)) {
|
||||
return;
|
||||
}
|
||||
// XXX - It would be nice to use gfxCriticalError, but it needs to
|
||||
// be made to work off the main thread first.
|
||||
//MOZ_ASSERT(aSeverity != DebugAssert);
|
||||
|
||||
if (aSeverity == Critical) {
|
||||
MOZ_CRASH("Unrecoverable D3D11 error");
|
||||
}
|
||||
|
||||
if (mDevice && hr == DXGI_ERROR_DEVICE_REMOVED) {
|
||||
bool deviceRemoved = hr == DXGI_ERROR_DEVICE_REMOVED;
|
||||
|
||||
if (deviceRemoved && mDevice) {
|
||||
hr = mDevice->GetDeviceRemovedReason();
|
||||
}
|
||||
|
||||
// Device reset may not be an error on our side, but can mess things up so
|
||||
// it's useful to see it in the reports.
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(!deviceRemoved))
|
||||
<< (deviceRemoved ? "[CompositorD3D11] device removed with error code: "
|
||||
: "[CompositorD3D11] error code: ")
|
||||
<< hexa(hr);
|
||||
|
||||
// Always crash if we are making invalid calls
|
||||
if (hr == DXGI_ERROR_INVALID_CALL) {
|
||||
MOZ_CRASH("Invalid D3D11 api call");
|
||||
|
@ -167,7 +167,7 @@ private:
|
||||
void SetPSForEffect(Effect *aEffect, MaskType aMaskType, gfx::SurfaceFormat aFormat);
|
||||
void PaintToTarget();
|
||||
|
||||
virtual gfx::IntSize GetWidgetSize() const override { return gfx::ToIntSize(mSize); }
|
||||
virtual gfx::IntSize GetWidgetSize() const override { return mSize; }
|
||||
|
||||
RefPtr<ID3D11DeviceContext> mContext;
|
||||
RefPtr<ID3D11Device> mDevice;
|
||||
@ -179,7 +179,7 @@ private:
|
||||
|
||||
nsIWidget* mWidget;
|
||||
|
||||
nsIntSize mSize;
|
||||
gfx::IntSize mSize;
|
||||
|
||||
HWND mHwnd;
|
||||
|
||||
|
@ -152,7 +152,7 @@ private:
|
||||
|
||||
virtual gfx::IntSize GetWidgetSize() const override
|
||||
{
|
||||
return gfx::ToIntSize(mSize);
|
||||
return mSize;
|
||||
}
|
||||
|
||||
/* Device manager instance for this compositor */
|
||||
|
@ -240,7 +240,7 @@ DeviceManagerD3D9::Init()
|
||||
mD3D9 = dont_AddRef(d3d9Create(D3D_SDK_VERSION));
|
||||
|
||||
if (!mD3D9) {
|
||||
gfxCriticalError() << "[D3D9] Failed to create the device";
|
||||
gfxCriticalError() << "[D3D9] Failed to create the IDirect3D9 object";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -249,7 +249,7 @@ DeviceManagerD3D9::Init()
|
||||
hr = mD3D9->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &ident);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << "[D3D9] Failed to create the environment";
|
||||
gfxCriticalError() << "[D3D9] Failed to create the environment code: " << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -331,13 +331,13 @@ DeviceManagerD3D9::Init()
|
||||
mNv3DVUtils->SetDeviceInfo(devUnknown);
|
||||
}
|
||||
|
||||
auto failCreateShaderMsg = "[D3D9] failed to create a critical resource (shader)";
|
||||
auto failCreateShaderMsg = "[D3D9] failed to create a critical resource (shader) code: ";
|
||||
|
||||
hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVS,
|
||||
getter_AddRefs(mLayerVS));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -345,7 +345,7 @@ DeviceManagerD3D9::Init()
|
||||
getter_AddRefs(mRGBPS));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -353,7 +353,7 @@ DeviceManagerD3D9::Init()
|
||||
getter_AddRefs(mRGBAPS));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -361,7 +361,7 @@ DeviceManagerD3D9::Init()
|
||||
getter_AddRefs(mComponentPass1PS));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -369,7 +369,7 @@ DeviceManagerD3D9::Init()
|
||||
getter_AddRefs(mComponentPass2PS));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -377,7 +377,7 @@ DeviceManagerD3D9::Init()
|
||||
getter_AddRefs(mYCbCrPS));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -393,14 +393,14 @@ DeviceManagerD3D9::Init()
|
||||
getter_AddRefs(mLayerVSMask));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
hr = mDevice->CreateVertexShader((DWORD*)LayerQuadVSMask3D,
|
||||
getter_AddRefs(mLayerVSMask3D));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -408,7 +408,7 @@ DeviceManagerD3D9::Init()
|
||||
getter_AddRefs(mRGBPSMask));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -416,7 +416,7 @@ DeviceManagerD3D9::Init()
|
||||
getter_AddRefs(mRGBAPSMask));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -424,7 +424,7 @@ DeviceManagerD3D9::Init()
|
||||
getter_AddRefs(mRGBAPSMask3D));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -432,7 +432,7 @@ DeviceManagerD3D9::Init()
|
||||
getter_AddRefs(mComponentPass1PSMask));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -448,7 +448,7 @@ DeviceManagerD3D9::Init()
|
||||
getter_AddRefs(mYCbCrPSMask));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -456,7 +456,7 @@ DeviceManagerD3D9::Init()
|
||||
getter_AddRefs(mSolidColorPSMask));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << failCreateShaderMsg;
|
||||
gfxCriticalError() << failCreateShaderMsg << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -467,7 +467,7 @@ DeviceManagerD3D9::Init()
|
||||
|
||||
hr = mDevice->SetStreamSource(0, mVB, 0, sizeof(vertex));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << "[D3D9] Failed to set the stream source";
|
||||
gfxCriticalError() << "[D3D9] Failed to set the stream source code: " << gfx::hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -447,7 +447,7 @@ DataTextureSourceD3D9::Update(gfxWindowsSurface* aSurface)
|
||||
NS_WARNING("No D3D device to update the texture.");
|
||||
return false;
|
||||
}
|
||||
mSize = ToIntSize(aSurface->GetSize());
|
||||
mSize = aSurface->GetSize();
|
||||
|
||||
uint32_t bpp = 0;
|
||||
|
||||
|
@ -49,8 +49,7 @@ CreateSharedRGBImage(ImageContainer *aImageContainer,
|
||||
}
|
||||
|
||||
nsRefPtr<SharedRGBImage> rgbImage = static_cast<SharedRGBImage*>(image.get());
|
||||
if (!rgbImage->Allocate(gfx::ToIntSize(aSize),
|
||||
gfx::ImageFormatToSurfaceFormat(aImageFormat))) {
|
||||
if (!rgbImage->Allocate(aSize, gfx::ImageFormatToSurfaceFormat(aImageFormat))) {
|
||||
NS_WARNING("Failed to allocate a shared image");
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -307,7 +307,7 @@ public:
|
||||
private:
|
||||
virtual gfx::IntSize GetWidgetSize() const override
|
||||
{
|
||||
return gfx::ToIntSize(mWidgetSize);
|
||||
return mWidgetSize;
|
||||
}
|
||||
|
||||
bool InitializeVR();
|
||||
@ -321,7 +321,7 @@ private:
|
||||
|
||||
/** Widget associated with this compositor */
|
||||
nsIWidget *mWidget;
|
||||
nsIntSize mWidgetSize;
|
||||
gfx::IntSize mWidgetSize;
|
||||
nsRefPtr<GLContext> mGLContext;
|
||||
UniquePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper;
|
||||
gfx::Matrix4x4 mProjMatrix;
|
||||
|
@ -60,7 +60,7 @@ X11TextureSourceOGL::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter)
|
||||
IntSize
|
||||
X11TextureSourceOGL::GetSize() const
|
||||
{
|
||||
return ToIntSize(mSurface->GetSize());
|
||||
return mSurface->GetSize();
|
||||
}
|
||||
|
||||
SurfaceFormat
|
||||
|
@ -69,6 +69,9 @@ TestIterator()
|
||||
EXPECT_TRUE(iter1.GetSkippedOffset() == 0) <<
|
||||
"[3] Check initial skipped offset";
|
||||
|
||||
EXPECT_TRUE(iter1.IsOriginalCharSkipped() == false) <<
|
||||
"[3a] Check IsOriginalCharSkipped for initial position";
|
||||
|
||||
uint32_t expectSkipped1[] =
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
@ -89,6 +92,18 @@ TestIterator()
|
||||
"[5] Check mapping of skipped to original for " << i;
|
||||
}
|
||||
|
||||
bool expectIsOriginalSkipped1[] =
|
||||
{ false, false, false, false, false, false, false, false, false, true,
|
||||
false, false, false, false, false, false, false, false, false, true,
|
||||
false, false, false, false, false, false, false, false, false
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < mozilla::ArrayLength(expectIsOriginalSkipped1); i++) {
|
||||
iter1.SetOriginalOffset(i);
|
||||
EXPECT_TRUE(iter1.IsOriginalCharSkipped() == expectIsOriginalSkipped1[i]) <<
|
||||
"[5.a] Check IsOriginalCharSkipped for " << i;
|
||||
}
|
||||
|
||||
// Test a gfxSkipChars that starts with skipped chars
|
||||
gfxSkipChars skipChars2;
|
||||
|
||||
@ -108,6 +123,9 @@ TestIterator()
|
||||
EXPECT_TRUE(iter2.GetSkippedOffset() == 0) <<
|
||||
"[8] Check initial skipped offset";
|
||||
|
||||
EXPECT_TRUE(iter2.IsOriginalCharSkipped() == true) <<
|
||||
"[8a] Check IsOriginalCharSkipped for initial position";
|
||||
|
||||
uint32_t expectSkipped2[] =
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
@ -125,6 +143,18 @@ TestIterator()
|
||||
"[10] Check mapping of skipped to original for " << i;
|
||||
}
|
||||
|
||||
bool expectIsOriginalSkipped2[] =
|
||||
{ true, true, true, true, true, true, true, true, true, false,
|
||||
true, true, true, true, true, true, true, true, true, false,
|
||||
true, true, true, true, true, true, true, true, true
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < mozilla::ArrayLength(expectIsOriginalSkipped2); i++) {
|
||||
iter2.SetOriginalOffset(i);
|
||||
EXPECT_TRUE(iter2.IsOriginalCharSkipped() == expectIsOriginalSkipped2[i]) <<
|
||||
"[10.a] Check IsOriginalCharSkipped for " << i;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,7 @@ void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface)
|
||||
|
||||
// client allocation
|
||||
ASSERT_TRUE(texture->CanExposeDrawTarget());
|
||||
texture->AllocateForSurface(ToIntSize(surface->GetSize()));
|
||||
texture->AllocateForSurface(surface->GetSize());
|
||||
ASSERT_TRUE(texture->IsAllocated());
|
||||
|
||||
ASSERT_TRUE(texture->Lock(OpenMode::OPEN_READ_WRITE));
|
||||
|
@ -81,11 +81,6 @@ inline Size ToSize(const gfxSize &aSize)
|
||||
return Size(Float(aSize.width), Float(aSize.height));
|
||||
}
|
||||
|
||||
inline IntSize ToIntSize(const gfxIntSize &aSize)
|
||||
{
|
||||
return IntSize(aSize.width, aSize.height);
|
||||
}
|
||||
|
||||
inline Filter ToFilter(GraphicsFilter aFilter)
|
||||
{
|
||||
switch (aFilter) {
|
||||
|
@ -837,7 +837,7 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
|
||||
surf.mFormat = format;
|
||||
surf.mType = NativeSurfaceType::CAIRO_SURFACE;
|
||||
surf.mSurface = aSurface->CairoSurface();
|
||||
surf.mSize = ToIntSize(aSurface->GetSize());
|
||||
surf.mSize = aSurface->GetSize();
|
||||
// We return here regardless of whether CreateSourceSurfaceFromNativeSurface
|
||||
// succeeds or not since we don't expect to be able to do any better below
|
||||
// if it fails.
|
||||
@ -862,7 +862,7 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
|
||||
surf.mFormat = format;
|
||||
surf.mType = NativeSurfaceType::D3D10_TEXTURE;
|
||||
surf.mSurface = static_cast<gfxD2DSurface*>(aSurface)->GetTexture();
|
||||
surf.mSize = ToIntSize(aSurface->GetSize());
|
||||
surf.mSize = aSurface->GetSize();
|
||||
mozilla::gfx::DrawTarget *dt = static_cast<mozilla::gfx::DrawTarget*>(aSurface->GetData(&kDrawTarget));
|
||||
if (dt) {
|
||||
dt->Flush();
|
||||
@ -910,7 +910,7 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
|
||||
surf.mFormat = format;
|
||||
surf.mType = NativeSurfaceType::CAIRO_SURFACE;
|
||||
surf.mSurface = aSurface->CairoSurface();
|
||||
surf.mSize = ToIntSize(aSurface->GetSize());
|
||||
surf.mSize = aSurface->GetSize();
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
Factory::CreateDrawTarget(BackendType::CAIRO, IntSize(1, 1), format);
|
||||
if (!drawTarget) {
|
||||
@ -956,7 +956,7 @@ gfxPlatform::GetWrappedDataSourceSurface(gfxASurface* aSurface)
|
||||
RefPtr<DataSourceSurface> result =
|
||||
Factory::CreateWrappingDataSourceSurface(image->Data(),
|
||||
image->Stride(),
|
||||
ToIntSize(image->GetSize()),
|
||||
image->GetSize(),
|
||||
ImageFormatToSurfaceFormat(image->Format()));
|
||||
|
||||
if (!result) {
|
||||
|
@ -177,7 +177,7 @@ public:
|
||||
mCurrentRangeIndex(-1),
|
||||
mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset)
|
||||
{
|
||||
SetOriginalOffset(aOriginalStringOffset);
|
||||
SetOriginalOffset(aOriginalStringOffset);
|
||||
}
|
||||
|
||||
explicit gfxSkipCharsIterator(const gfxSkipChars& aSkipChars,
|
||||
@ -185,9 +185,12 @@ public:
|
||||
: mSkipChars(&aSkipChars),
|
||||
mOriginalStringOffset(0),
|
||||
mSkippedStringOffset(0),
|
||||
mCurrentRangeIndex(-1),
|
||||
mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset)
|
||||
{ }
|
||||
{
|
||||
mCurrentRangeIndex =
|
||||
mSkipChars->mRanges.IsEmpty() ||
|
||||
mSkipChars->mRanges[0].Start() > 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
gfxSkipCharsIterator(const gfxSkipCharsIterator& aIterator)
|
||||
: mSkipChars(aIterator.mSkipChars),
|
||||
|
@ -441,8 +441,7 @@ CreateSamplingRestrictedDrawable(gfxDrawable* aDrawable,
|
||||
gfxIntSize size(int32_t(needed.Width()), int32_t(needed.Height()));
|
||||
|
||||
RefPtr<DrawTarget> target =
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(ToIntSize(size),
|
||||
aFormat);
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(size, aFormat);
|
||||
if (!target) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -869,7 +868,7 @@ gfxUtils::GetYCbCrToRGBDestFormatAndSize(const PlanarYCbCrData& aData,
|
||||
// 'prescale' is true if the scaling is to be done as part of the
|
||||
// YCbCr to RGB conversion rather than on the RGB data when rendered.
|
||||
bool prescale = aSuggestedSize.width > 0 && aSuggestedSize.height > 0 &&
|
||||
ToIntSize(aSuggestedSize) != aData.mPicSize;
|
||||
aSuggestedSize != aData.mPicSize;
|
||||
|
||||
if (aSuggestedFormat == gfxImageFormat::RGB16_565) {
|
||||
#if defined(HAVE_YCBCR_TO_RGB565)
|
||||
@ -905,7 +904,7 @@ gfxUtils::GetYCbCrToRGBDestFormatAndSize(const PlanarYCbCrData& aData,
|
||||
prescale = false;
|
||||
}
|
||||
if (!prescale) {
|
||||
ToIntSize(aSuggestedSize) = aData.mPicSize;
|
||||
aSuggestedSize = aData.mPicSize;
|
||||
}
|
||||
}
|
||||
|
||||
@ -929,7 +928,7 @@ gfxUtils::ConvertYCbCrToRGB(const PlanarYCbCrData& aData,
|
||||
aData.mCbCrSize.height);
|
||||
|
||||
// Convert from YCbCr to RGB now, scaling the image if needed.
|
||||
if (ToIntSize(aDestSize) != aData.mPicSize) {
|
||||
if (aDestSize != aData.mPicSize) {
|
||||
#if defined(HAVE_YCBCR_TO_RGB565)
|
||||
if (aDestFormat == gfxImageFormat::RGB16_565) {
|
||||
ScaleYCbCrToRGB565(aData.mYChannel,
|
||||
|
@ -272,7 +272,7 @@ gfxWindowsNativeDrawing::PaintToContext()
|
||||
RefPtr<DataSourceSurface> source =
|
||||
Factory::CreateWrappingDataSourceSurface(black->Data(),
|
||||
black->Stride(),
|
||||
ToIntSize(black->GetSize()),
|
||||
black->GetSize(),
|
||||
SurfaceFormat::B8G8R8A8);
|
||||
|
||||
mContext->Save();
|
||||
|
@ -573,7 +573,7 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
|
||||
native.mFormat = moz2DFormat;
|
||||
native.mType = NativeSurfaceType::CAIRO_SURFACE;
|
||||
native.mSurface = tempXlibSurface;
|
||||
native.mSize = ToIntSize(size);
|
||||
native.mSize = size;
|
||||
RefPtr<SourceSurface> sourceSurface =
|
||||
drawTarget->CreateSourceSurfaceFromNativeSurface(native);
|
||||
if (sourceSurface) {
|
||||
@ -615,7 +615,7 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
|
||||
native.mFormat = moz2DFormat;
|
||||
native.mType = NativeSurfaceType::CAIRO_SURFACE;
|
||||
native.mSurface = paintSurface->CairoSurface();
|
||||
native.mSize = ToIntSize(size);
|
||||
native.mSize = size;
|
||||
RefPtr<SourceSurface> sourceSurface =
|
||||
drawTarget->CreateSourceSurfaceFromNativeSurface(native);
|
||||
if (sourceSurface) {
|
||||
|
@ -281,7 +281,7 @@ nsPNGDecoder::InitInternal()
|
||||
(int)sizeof(unused_chunks)/5);
|
||||
#endif
|
||||
|
||||
#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
|
||||
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
|
||||
if (mCMSMode != eCMSMode_Off) {
|
||||
png_set_chunk_malloc_max(mPNG, 4000000L);
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ OrientedImage::GetFrame(uint32_t aWhichFrame,
|
||||
// Create a surface to draw into.
|
||||
RefPtr<DrawTarget> target =
|
||||
gfxPlatform::GetPlatform()->
|
||||
CreateOffscreenContentDrawTarget(ToIntSize(size), surfaceFormat);
|
||||
CreateOffscreenContentDrawTarget(size, surfaceFormat);
|
||||
if (!target) {
|
||||
NS_ERROR("Could not create a DrawTarget");
|
||||
return nullptr;
|
||||
|
@ -2622,6 +2622,9 @@ void imgCacheValidator::AddProxy(imgRequestProxy *aProxy)
|
||||
/* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
|
||||
NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt)
|
||||
{
|
||||
// We may be holding on to a document, so ensure that it's released.
|
||||
nsCOMPtr<nsISupports> context = mContext.forget();
|
||||
|
||||
// If for some reason we don't still have an existing request (probably
|
||||
// because OnStartRequest got delivered more than once), just bail.
|
||||
if (!mRequest) {
|
||||
@ -2670,7 +2673,7 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
|
||||
// We don't need to load this any more.
|
||||
aRequest->Cancel(NS_BINDING_ABORTED);
|
||||
|
||||
mRequest->SetLoadId(mContext);
|
||||
mRequest->SetLoadId(context);
|
||||
mRequest->SetValidator(nullptr);
|
||||
|
||||
mRequest = nullptr;
|
||||
@ -2711,7 +2714,7 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
|
||||
nsCOMPtr<nsIURI> originalURI;
|
||||
channel->GetOriginalURI(getter_AddRefs(originalURI));
|
||||
mNewRequest->Init(originalURI, uri, mHadInsecureRedirect, aRequest, channel,
|
||||
mNewEntry, mContext, loadingPrincipal, corsmode, refpol);
|
||||
mNewEntry, context, loadingPrincipal, corsmode, refpol);
|
||||
|
||||
mDestListener = new ProxyListener(mNewRequest);
|
||||
|
||||
@ -2740,6 +2743,9 @@ NS_IMETHODIMP imgCacheValidator::OnStartRequest(nsIRequest *aRequest, nsISupport
|
||||
/* void onStopRequest (in nsIRequest request, in nsISupports ctxt, in nsresult status); */
|
||||
NS_IMETHODIMP imgCacheValidator::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt, nsresult status)
|
||||
{
|
||||
// Be sure we've released the document that we may have been holding on to.
|
||||
mContext = nullptr;
|
||||
|
||||
if (!mDestListener)
|
||||
return NS_OK;
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DIRS += ['internal']
|
||||
DIRS += ['internal', 'standalone']
|
||||
|
||||
EXPORTS += [
|
||||
'GreekCasing.h',
|
||||
|
23
intl/unicharutil/util/standalone/moz.build
Normal file
23
intl/unicharutil/util/standalone/moz.build
Normal file
@ -0,0 +1,23 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if CONFIG['OS_TARGET'] != 'WINNT' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
|
||||
Library('unicharutil_standalone')
|
||||
|
||||
intl_unicharutil_util_lcppsrcs = [
|
||||
'nsUnicodeProperties.cpp',
|
||||
]
|
||||
|
||||
intl_unicharutil_util_cppsrcs = [
|
||||
'%s/intl/unicharutil/util/%s' % (TOPSRCDIR, s) \
|
||||
for s in intl_unicharutil_util_lcppsrcs
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += intl_unicharutil_util_cppsrcs
|
||||
|
||||
for var in ('MOZILLA_INTERNAL_API', 'MOZILLA_XPCOMRT_API', 'MOZILLA_EXTERNAL_LINKAGE',
|
||||
'NR_SOCKET_IS_VOID_PTR', 'HAVE_STRDUP'):
|
||||
DEFINES[var] = True
|
@ -682,6 +682,12 @@ BuiltinToName(AsmJSExit::BuiltinKind builtin)
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
case AsmJSExit::Builtin_IDivMod: return "software idivmod (in asm.js)";
|
||||
case AsmJSExit::Builtin_UDivMod: return "software uidivmod (in asm.js)";
|
||||
case AsmJSExit::Builtin_AtomicCmpXchg: return "Atomics.compareExchange (in asm.js)";
|
||||
case AsmJSExit::Builtin_AtomicFetchAdd: return "Atomics.add (in asm.js)";
|
||||
case AsmJSExit::Builtin_AtomicFetchSub: return "Atomics.sub (in asm.js)";
|
||||
case AsmJSExit::Builtin_AtomicFetchAnd: return "Atomics.and (in asm.js)";
|
||||
case AsmJSExit::Builtin_AtomicFetchOr: return "Atomics.or (in asm.js)";
|
||||
case AsmJSExit::Builtin_AtomicFetchXor: return "Atomics.xor (in asm.js)";
|
||||
#endif
|
||||
case AsmJSExit::Builtin_ModD: return "fmod (in asm.js)";
|
||||
case AsmJSExit::Builtin_SinD: return "Math.sin (in asm.js)";
|
||||
|
@ -80,6 +80,12 @@ namespace AsmJSExit
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
Builtin_IDivMod,
|
||||
Builtin_UDivMod,
|
||||
Builtin_AtomicCmpXchg,
|
||||
Builtin_AtomicFetchAdd,
|
||||
Builtin_AtomicFetchSub,
|
||||
Builtin_AtomicFetchAnd,
|
||||
Builtin_AtomicFetchOr,
|
||||
Builtin_AtomicFetchXor,
|
||||
#endif
|
||||
Builtin_ModD,
|
||||
Builtin_SinD,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user