Merge inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-12-18 17:59:14 -05:00
commit e74a8fc1d1
117 changed files with 2345 additions and 685 deletions

View File

@ -103,6 +103,12 @@ this.DOMApplicationRegistry = {
this.cpmm.addMessageListener(aMsgName, this);
}).bind(this));
this.resetList();
Services.obs.addObserver(this, "xpcom-shutdown", false);
},
resetList: function() {
this.cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
messages: APPS_IPC_MSG_NAMES
});
@ -110,6 +116,7 @@ this.DOMApplicationRegistry = {
// We need to prime the cache with the list of apps.
let list = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
this.webapps = list.webapps;
// We need a fast mapping from localId -> app, so we add an index.
// We also add the manifest to the app object.
this.localIdIndex = { };
@ -118,8 +125,6 @@ this.DOMApplicationRegistry = {
this.localIdIndex[app.localId] = app;
app.manifest = list.manifests[id];
}
Services.obs.addObserver(this, "xpcom-shutdown", false);
},
observe: function(aSubject, aTopic, aData) {

View File

@ -15,6 +15,7 @@
#include "mozilla/dom/DesktopNotification.h"
#include "mozilla/dom/File.h"
#include "nsGeolocation.h"
#include "nsIClassOfService.h"
#include "nsIHttpProtocolHandler.h"
#include "nsIContentPolicy.h"
#include "nsIContentSecurityPolicy.h"
@ -1190,6 +1191,11 @@ Navigator::SendBeacon(const nsAString& aUrl,
p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
}
nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
if (cos) {
cos->AddClassFlags(nsIClassOfService::Background);
}
nsRefPtr<nsCORSListenerProxy> cors = new nsCORSListenerProxy(new BeaconStreamListener(),
principal,
true);

View File

@ -27,7 +27,7 @@
#include "nsJSPrincipals.h"
#include "nsContentPolicyUtils.h"
#include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsIClassOfService.h"
#include "nsITimedChannel.h"
#include "nsIScriptElement.h"
#include "nsIDOMHTMLScriptElement.h"
@ -321,18 +321,17 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
NS_ENSURE_SUCCESS(rv, rv);
nsIScriptElement *script = aRequest->mElement;
nsCOMPtr<nsIHttpChannelInternal>
internalHttpChannel(do_QueryInterface(channel));
nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
if (internalHttpChannel) {
if (cos) {
if (aScriptFromHead &&
!(script && (script->GetScriptAsync() || script->GetScriptDeferred()))) {
// synchronous head scripts block lading of most other non js/css
// content such as images
internalHttpChannel->SetLoadAsBlocking(true);
cos->AddClassFlags(nsIClassOfService::Leader);
} else if (!(script && script->GetScriptDeferred())) {
// other scripts are neither blocked nor prioritized unless marked deferred
internalHttpChannel->SetLoadUnblocked(true);
cos->AddClassFlags(nsIClassOfService::Unblocked);
}
}

View File

@ -66,6 +66,7 @@
#include "nsIPermissionManager.h"
#include "nsMimeTypes.h"
#include "nsIHttpChannelInternal.h"
#include "nsIClassOfService.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsFormData.h"
#include "nsStreamListenerWrapper.h"
@ -2403,10 +2404,8 @@ GetRequestBody(nsIDOMDocument* aDoc, nsIInputStream** aResult,
aContentType.AssignLiteral("application/xml");
nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
NS_ENSURE_STATE(doc);
aCharset = doc->GetDocumentCharacterSet();
aCharset.AssignLiteral("UTF-8");
// Serialize to a stream so that the encoding used will
// match the document's.
nsresult rv;
nsCOMPtr<nsIDOMSerializer> serializer =
do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv);
@ -2891,14 +2890,17 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
// the channel slow by default for pipeline purposes
AddLoadFlags(mChannel, nsIRequest::INHIBIT_PIPELINE);
nsCOMPtr<nsIHttpChannelInternal>
internalHttpChannel(do_QueryInterface(mChannel));
if (internalHttpChannel) {
nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(mChannel));
if (cos) {
// we never let XHR be blocked by head CSS/JS loads to avoid
// potential deadlock where server generation of CSS/JS requires
// an XHR signal.
internalHttpChannel->SetLoadUnblocked(true);
cos->AddClassFlags(nsIClassOfService::Unblocked);
}
nsCOMPtr<nsIHttpChannelInternal>
internalHttpChannel(do_QueryInterface(mChannel));
if (internalHttpChannel) {
// Disable Necko-internal response timeouts.
internalHttpChannel->SetResponseTimeoutEnabled(false);
}

View File

@ -127,22 +127,22 @@ tests = [{ body: null,
},
{ body: testDoc1,
resBody: "<!-- comment -->\n<out>hi</out>",
resContentType: "application/xml; charset=windows-1252",
resContentType: "application/xml; charset=UTF-8",
},
{ body: testDoc1,
contentType: "foo/bar",
resBody: "<!-- comment -->\n<out>hi</out>",
resContentType: "foo/bar; charset=windows-1252",
resContentType: "foo/bar; charset=UTF-8",
},
{ body: testDoc1,
contentType: "foo/bar; charset=ascii; baz=bin",
resBody: "<!-- comment -->\n<out>hi</out>",
resContentType: "foo/bar; charset=windows-1252; baz=bin",
resContentType: "foo/bar; charset=UTF-8; baz=bin",
},
{ body: testDoc1,
contentType: "foo/bar; charset=wIndows-1252",
resBody: "<!-- comment -->\n<out>hi</out>",
resContentType: "foo/bar; charset=wIndows-1252",
resContentType: "foo/bar; charset=UTF-8",
},
{ body: testDoc2,
resBody: "<!-- doc 2 -->\n<res>text</res>",

View File

@ -903,6 +903,12 @@ nsGonkCameraControl::SetThumbnailSizeImpl(const Size& aSize)
return SetAndPush(CAMERA_PARAM_THUMBNAILSIZE, size);
}
android::sp<android::GonkCameraHardware>
nsGonkCameraControl::GetCameraHw()
{
return mCameraHw;
}
nsresult
nsGonkCameraControl::SetThumbnailSize(const Size& aSize)
{

View File

@ -32,6 +32,7 @@ namespace android {
class GonkCameraHardware;
class MediaProfiles;
class GonkRecorder;
class GonkCameraSource;
}
namespace mozilla {
@ -154,6 +155,9 @@ protected:
nsresult UpdateThumbnailSize();
nsresult SetThumbnailSizeImpl(const Size& aSize);
friend class android::GonkCameraSource;
android::sp<android::GonkCameraHardware> GetCameraHw();
int32_t RationalizeRotation(int32_t aRotation);
uint32_t mCameraId;

View File

@ -46,6 +46,7 @@
#include "GonkCameraSource.h"
#include "GonkCameraListener.h"
#include "GonkCameraHwMgr.h"
#include "ICameraControl.h"
using namespace mozilla;
@ -157,6 +158,16 @@ GonkCameraSource *GonkCameraSource::Create(
return source;
}
GonkCameraSource *GonkCameraSource::Create(
ICameraControl* aControl,
Size videoSize,
int32_t frameRate)
{
mozilla::nsGonkCameraControl* control =
static_cast<mozilla::nsGonkCameraControl*>(aControl);
return Create(control->GetCameraHw(), videoSize, frameRate, false);
}
GonkCameraSource::GonkCameraSource(
const sp<GonkCameraHardware>& aCameraHw,
Size videoSize,
@ -596,6 +607,10 @@ status_t GonkCameraSource::reset() {
}
releaseCamera();
if (mDirectBufferListener.get()) {
mDirectBufferListener = nullptr;
}
if (mCollectStats) {
CS_LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
@ -652,6 +667,14 @@ void GonkCameraSource::signalBufferReturned(MediaBuffer *buffer) {
CHECK(!"signalBufferReturned: bogus buffer");
}
status_t GonkCameraSource::AddDirectBufferListener(DirectBufferListener* aListener) {
if (mDirectBufferListener.get()) {
return UNKNOWN_ERROR;
}
mDirectBufferListener = aListener;
return OK;
}
status_t GonkCameraSource::read(
MediaBuffer **buffer, const ReadOptions *options) {
CS_LOGV("read");
@ -761,6 +784,15 @@ void GonkCameraSource::dataCallbackTimestamp(int64_t timestampUs,
if(prevRateLimit != rateLimit) {
mCameraHw->OnRateLimitPreview(rateLimit);
}
if (mDirectBufferListener.get()) {
MediaBuffer* mediaBuffer;
if (read(&mediaBuffer) == OK) {
mDirectBufferListener->BufferAvailable(mediaBuffer);
// read() calls MediaBuffer->add_ref() so it needs to be released here.
mediaBuffer->release();
}
}
}
bool GonkCameraSource::isMetaDataStoredInVideoBuffers() const {

View File

@ -27,6 +27,10 @@
#include "GonkCameraHwMgr.h"
namespace mozilla {
class ICameraControl;
}
namespace android {
class IMemory;
@ -39,6 +43,10 @@ public:
int32_t frameRate,
bool storeMetaDataInVideoBuffers = false);
static GonkCameraSource *Create(mozilla::ICameraControl* aControl,
Size videoSize,
int32_t frameRate);
virtual ~GonkCameraSource();
virtual status_t start(MetaData *params = NULL);
@ -75,6 +83,24 @@ public:
virtual void signalBufferReturned(MediaBuffer* buffer);
/**
* It sends recording frames to listener directly in the same thread.
* Because recording frame is critical resource and it should not be
* propagated to other thread as much as possible or there could be frame
* rate jitter due to camera HAL waiting for resource.
*/
class DirectBufferListener : public RefBase {
public:
DirectBufferListener() {};
virtual status_t BufferAvailable(MediaBuffer* aBuffer) = 0;
protected:
virtual ~DirectBufferListener() {}
};
status_t AddDirectBufferListener(DirectBufferListener* aListener);
protected:
enum CameraFlags {
@ -136,6 +162,7 @@ private:
bool mCollectStats;
bool mIsMetaDataStoredInVideoBuffers;
sp<GonkCameraHardware> mCameraHw;
sp<DirectBufferListener> mDirectBufferListener;
void releaseQueuedFrames();
void releaseOneRecordingFrame(const sp<IMemory>& frame);

View File

@ -3244,10 +3244,7 @@ void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatu
// autoplay elements for live streams will never play. Otherwise we
// move to HAVE_ENOUGH_DATA if we can play through the entire media
// without stopping to buffer.
MediaDecoder::Statistics stats = mDecoder->GetStatistics();
if (stats.mTotalBytes < 0 ? stats.mDownloadRateReliable
: stats.mTotalBytes == stats.mDownloadPosition ||
mDecoder->CanPlayThrough())
if (mDecoder->CanPlayThrough())
{
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
return;

View File

@ -19,6 +19,7 @@
#include "nsServiceManagerUtils.h"
#include "nsXPCOMCIDInternal.h"
#include "ProfilerHelpers.h"
#include "nsThread.h"
namespace mozilla {
namespace dom {
@ -176,6 +177,10 @@ private:
~TransactionQueue()
{ }
#ifdef MOZ_NUWA_PROCESS
nsThread* mThread;
#endif
NS_DECL_NSIRUNNABLE
};
@ -789,6 +794,9 @@ TransactionQueue::TransactionQueue(TransactionThreadPool* aThreadPool,
, mObjectStoreNames(aObjectStoreNames)
, mMode(aMode)
, mShouldFinish(false)
#ifdef MOZ_NUWA_PROCESS
, mThread(nullptr)
#endif
{
MOZ_ASSERT(aThreadPool);
aThreadPool->AssertIsOnOwningThread();
@ -814,6 +822,12 @@ TransactionThreadPool::TransactionQueue::Dispatch(nsIRunnable* aRunnable)
mQueue.AppendElement(aRunnable);
#ifdef MOZ_NUWA_PROCESS
if (mThread) {
mThread->SetWorking();
}
#endif
mMonitor.Notify();
}
@ -849,6 +863,12 @@ TransactionThreadPool::TransactionQueue::Run()
nsAutoTArray<nsCOMPtr<nsIRunnable>, 10> queue;
nsRefPtr<FinishCallback> finishCallback;
bool shouldFinish = false;
#ifdef MOZ_NUWA_PROCESS
mThread = static_cast<nsThread*>(NS_GetCurrentThread());
// Set ourself as working thread. We can reset later if we found
// our queue is empty.
mThread->SetWorking();
#endif
do {
NS_ASSERTION(queue.IsEmpty(), "Should have cleared this!");
@ -856,6 +876,9 @@ TransactionThreadPool::TransactionQueue::Run()
{
MonitorAutoLock lock(mMonitor);
while (!mShouldFinish && mQueue.IsEmpty()) {
#ifdef MOZ_NUWA_PROCESS
mThread->SetIdle();
#endif
if (NS_FAILED(mMonitor.Wait())) {
NS_ERROR("Failed to wait!");
}
@ -888,6 +911,10 @@ TransactionThreadPool::TransactionQueue::Run()
}
} while (!shouldFinish);
#ifdef MOZ_NUWA_PROCESS
mThread = nullptr;
#endif
#ifdef DEBUG
if (kDEBUGThreadSleepMS) {
MOZ_ALWAYS_TRUE(

View File

@ -510,6 +510,12 @@ NS_IMPL_ISUPPORTS(BackgroundChildPrimer, nsIIPCBackgroundChildCreateCallback)
ContentChild* ContentChild::sSingleton;
static void
PostForkPreload()
{
TabChild::PostForkPreload();
}
// Performs initialization that is not fork-safe, i.e. that must be done after
// forking from the Nuwa process.
static void
@ -520,6 +526,7 @@ InitOnContentProcessCreated()
if (IsNuwaProcess()) {
return;
}
PostForkPreload();
#endif
// This will register cross-process observer.
@ -1243,7 +1250,6 @@ ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
{
// This runs after AllocPBrowserChild() returns and the IPC machinery for this
// PBrowserChild has been set up.
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
nsITabChild* tc =
@ -1991,8 +1997,11 @@ bool
ContentChild::RecvFlushMemory(const nsString& reason)
{
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) {
if (IsNuwaProcess() || ManagedPBrowserChild().Length() == 0) {
// Don't flush memory in the nuwa process: the GC thread could be frozen.
// If there's no PBrowser child, don't flush memory, either. GC writes
// to copy-on-write pages and makes preallocated process take more memory
// before it actually becomes an app.
return true;
}
#endif
@ -2080,12 +2089,28 @@ ContentChild::RecvAppInfo(const nsCString& version, const nsCString& buildID,
// BrowserElementChild.js.
if ((mIsForApp || mIsForBrowser)
#ifdef MOZ_NUWA_PROCESS
&& !IsNuwaProcess()
&& IsNuwaProcess()
#endif
) {
PreloadSlowThings();
#ifndef MOZ_NUWA_PROCESS
PostForkPreload();
#endif
}
#ifdef MOZ_NUWA_PROCESS
// Some modules are initialized in preloading. We need to wait until the
// tasks they dispatched to chrome process are done.
if (IsNuwaProcess()) {
SendNuwaWaitForFreeze();
}
#endif
return true;
}
bool
ContentChild::RecvNuwaFreeze()
{
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) {
ContentChild::GetSingleton()->RecvGarbageCollect();
@ -2093,7 +2118,6 @@ ContentChild::RecvAppInfo(const nsCString& version, const nsCString& buildID,
FROM_HERE, NewRunnableFunction(OnFinishNuwaPreparation));
}
#endif
return true;
}
@ -2344,6 +2368,36 @@ RunNuwaFork()
DoNuwaFork();
}
}
class NuwaForkCaller: public nsRunnable
{
public:
NS_IMETHODIMP
Run() {
// We want to ensure that the PBackground actor gets cloned in the Nuwa
// process before we freeze. Also, we have to do this to avoid deadlock.
// Protocols that are "opened" (e.g. PBackground, PCompositor) block the
// main thread to wait for the IPC thread during the open operation.
// NuwaSpawnWait() blocks the IPC thread to wait for the main thread when
// the Nuwa process is forked. Unless we ensure that the two cannot happen
// at the same time then we risk deadlock. Spinning the event loop here
// guarantees the ordering is safe for PBackground.
if (!BackgroundChild::GetForCurrentThread()) {
// Dispatch ourself again.
NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
} else {
MessageLoop* ioloop = XRE_GetIOMessageLoop();
ioloop->PostTask(FROM_HERE, NewRunnableFunction(RunNuwaFork));
}
return NS_OK;
}
private:
virtual
~NuwaForkCaller()
{
}
};
#endif
bool
@ -2355,22 +2409,9 @@ ContentChild::RecvNuwaFork()
}
sNuwaForking = true;
// We want to ensure that the PBackground actor gets cloned in the Nuwa
// process before we freeze. Also, we have to do this to avoid deadlock.
// Protocols that are "opened" (e.g. PBackground, PCompositor) block the
// main thread to wait for the IPC thread during the open operation.
// NuwaSpawnWait() blocks the IPC thread to wait for the main thread when
// the Nuwa process is forked. Unless we ensure that the two cannot happen
// at the same time then we risk deadlock. Spinning the event loop here
// guarantees the ordering is safe for PBackground.
while (!BackgroundChild::GetForCurrentThread()) {
if (NS_WARN_IF(!NS_ProcessNextEvent())) {
return false;
}
}
nsRefPtr<NuwaForkCaller> runnable = new NuwaForkCaller();
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL);
MessageLoop* ioloop = XRE_GetIOMessageLoop();
ioloop->PostTask(FROM_HERE, NewRunnableFunction(RunNuwaFork));
return true;
#else
return false; // Makes the underlying IPC channel abort.

View File

@ -350,6 +350,8 @@ public:
virtual bool RecvNotifyPhoneStateChange(const nsString& state) MOZ_OVERRIDE;
virtual bool RecvNuwaFreeze() MOZ_OVERRIDE;
void AddIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS);
void RemoveIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS);
virtual bool RecvNotifyIdleObserver(const uint64_t& aObserver,

View File

@ -124,6 +124,7 @@
#include "nsServiceManagerUtils.h"
#include "nsStyleSheetService.h"
#include "nsThreadUtils.h"
#include "nsThreadManager.h"
#include "nsToolkitCompsCID.h"
#include "nsWidgetsCID.h"
#include "PreallocatedProcessManager.h"
@ -1372,6 +1373,28 @@ StaticAutoPtr<LinkedList<SystemMessageHandledListener> >
NS_IMPL_ISUPPORTS(SystemMessageHandledListener,
nsITimerCallback)
#ifdef MOZ_NUWA_PROCESS
class NuwaFreezeListener : public nsThreadManager::AllThreadsWereIdleListener
{
public:
NuwaFreezeListener(ContentParent* parent)
: mParent(parent)
{
}
void OnAllThreadsWereIdle()
{
unused << mParent->SendNuwaFreeze();
nsThreadManager::get()->RemoveAllThreadsWereIdleListener(this);
}
private:
nsRefPtr<ContentParent> mParent;
virtual ~NuwaFreezeListener()
{
}
};
#endif // MOZ_NUWA_PROCESS
} // anonymous namespace
void
@ -2062,6 +2085,8 @@ ContentParent::ContentParent(ContentParent* aTemplate,
priority = PROCESS_PRIORITY_FOREGROUND;
}
mSendPermissionUpdates = aTemplate->mSendPermissionUpdates;
InitInternal(priority,
false, /* Setup Off-main thread compositing */
false /* Send registered chrome */);
@ -2219,7 +2244,7 @@ ContentParent::IsForApp()
#ifdef MOZ_NUWA_PROCESS
bool
ContentParent::IsNuwaProcess()
ContentParent::IsNuwaProcess() const
{
return mIsNuwaProcess;
}
@ -2568,6 +2593,19 @@ ContentParent::RecvNuwaReady()
#endif
}
bool
ContentParent::RecvNuwaWaitForFreeze()
{
#ifdef MOZ_NUWA_PROCESS
nsRefPtr<NuwaFreezeListener> listener = new NuwaFreezeListener(this);
nsThreadManager::get()->AddAllThreadsWereIdleListener(listener);
return true;
#else // MOZ_NUWA_PROCESS
NS_ERROR("ContentParent::RecvNuwaWaitForFreeze() not implemented!");
return false;
#endif // MOZ_NUWA_PROCESS
}
bool
ContentParent::RecvAddNewProcess(const uint32_t& aPid,
const InfallibleTArray<ProtocolFdMapping>& aFds)

View File

@ -206,7 +206,7 @@ public:
return mIsForBrowser;
}
#ifdef MOZ_NUWA_PROCESS
bool IsNuwaProcess();
bool IsNuwaProcess() const;
#endif
GeckoChildProcessHost* Process() {
@ -220,7 +220,11 @@ public:
}
bool NeedsPermissionsUpdate() const {
#ifdef MOZ_NUWA_PROCESS
return !IsNuwaProcess() && mSendPermissionUpdates;
#else
return mSendPermissionUpdates;
#endif
}
bool NeedsDataStoreInfos() const {
@ -680,6 +684,8 @@ private:
virtual bool RecvNuwaReady() MOZ_OVERRIDE;
virtual bool RecvNuwaWaitForFreeze() MOZ_OVERRIDE;
virtual bool RecvAddNewProcess(const uint32_t& aPid,
const InfallibleTArray<ProtocolFdMapping>& aFds) MOZ_OVERRIDE;

View File

@ -524,6 +524,7 @@ child:
intr GetProfile()
returns (nsCString aProfile);
NuwaFreeze();
parent:
/**
* Tell the parent process a new accessible document has been created.
@ -735,6 +736,9 @@ parent:
async SystemMessageHandled();
NuwaReady();
// Sent when nuwa finished its initialization process and is waiting for
// parent's signal to make it freeze.
NuwaWaitForFreeze();
sync AddNewProcess(uint32_t pid, ProtocolFdMapping[] aFds);

View File

@ -834,6 +834,21 @@ TabChild::PreloadSlowThings()
ClearOnShutdown(&sPreallocatedTab);
}
/*static*/ void
TabChild::PostForkPreload()
{
// Preallocated Tab can be null if we are forked directly from b2g. In such
// case we don't need to preload anything, just return.
if (!sPreallocatedTab) {
return;
}
// Rebuild connections to parent.
sPreallocatedTab->RecvLoadRemoteScript(
NS_LITERAL_STRING("chrome://global/content/post-fork-preload.js"),
true);
}
/*static*/ already_AddRefed<TabChild>
TabChild::Create(nsIContentChild* aManager,
const TabId& aTabId,

View File

@ -268,6 +268,7 @@ public:
* on the critical path.
*/
static void PreloadSlowThings();
static void PostForkPreload();
/** Return a TabChild with the given attributes. */
static already_AddRefed<TabChild>

View File

@ -9,3 +9,4 @@ toolkit.jar:
content/global/BrowserElementChildPreload.js (../browser-element/BrowserElementChildPreload.js)
* content/global/BrowserElementPanning.js (../browser-element/BrowserElementPanning.js)
content/global/preload.js (preload.js)
content/global/post-fork-preload.js (post-fork-preload.js)

View File

@ -0,0 +1,20 @@
/* 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/. */
// Preload some things, in an attempt to make app startup faster.
//
// This script is run when the preallocated process starts. It is injected as
// a frame script.
// If Nuwa process is enabled, this script will run in preallocated process
// forked by Nuwa.
(function (global) {
"use strict";
Components.utils.import("resource://gre/modules/AppsServiceChild.jsm");
Components.classes["@mozilla.org/network/protocol-proxy-service;1"].
getService(Ci["nsIProtocolProxyService"]);
DOMApplicationRegistry.resetList();
})(this);

View File

@ -6,6 +6,7 @@
//
// This script is run when the preallocated process starts. It is injected as
// a frame script.
// If nuwa is enabled, this script will run in Nuwa process before frozen.
const BrowserElementIsPreloaded = true;
@ -58,7 +59,6 @@ const BrowserElementIsPreloaded = true;
Cc["@mozilla.org/network/idn-service;1"].getService(Ci["nsIIDNService"]);
Cc["@mozilla.org/network/io-service;1"].getService(Ci["nsIIOService2"]);
Cc["@mozilla.org/network/mime-hdrparam;1"].getService(Ci["nsIMIMEHeaderParam"]);
Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(Ci["nsIProtocolProxyService"]);
Cc["@mozilla.org/network/socket-transport-service;1"].getService(Ci["nsISocketTransportService"]);
Cc["@mozilla.org/network/stream-transport-service;1"].getService(Ci["nsIStreamTransportService"]);
Cc["@mozilla.org/network/url-parser;1?auth=maybe"].getService(Ci["nsIURLParser"]);

View File

@ -77,7 +77,7 @@ function runTest()
let timeout = setTimeout(function() {
ok(false, "Nuwa process is not launched");
testEnd();
}, 60000);
}, 240000);
function testEnd() {
cpmm.removeMessageListener("TEST-ONLY:nuwa-ready", msgHandler);

View File

@ -78,7 +78,7 @@ function runTest()
let timeout = setTimeout(function() {
ok(false, "Nuwa process is not launched");
testEnd();
}, 90000);
}, 240000);
function testEnd() {
cpmm.removeMessageListener("TEST-ONLY:nuwa-ready", msgHandler);

View File

@ -1562,6 +1562,10 @@ void MediaDecoder::UnpinForSeek()
bool MediaDecoder::CanPlayThrough()
{
Statistics stats = GetStatistics();
if ((stats.mTotalBytes < 0 && stats.mDownloadRateReliable) ||
(stats.mTotalBytes >= 0 && stats.mTotalBytes == stats.mDownloadPosition)) {
return true;
}
if (!stats.mDownloadRateReliable || !stats.mPlaybackRateReliable) {
return false;
}
@ -1585,8 +1589,7 @@ bool MediaDecoder::CanPlayThrough()
// required near the start of the media, when not much data is downloaded.
int64_t readAheadMargin =
static_cast<int64_t>(stats.mPlaybackRate * CAN_PLAY_THROUGH_MARGIN);
return stats.mTotalBytes == stats.mDownloadPosition ||
stats.mDownloadPosition > stats.mPlaybackPosition + readAheadMargin;
return stats.mDownloadPosition > stats.mPlaybackPosition + readAheadMargin;
}
#ifdef MOZ_EME

View File

@ -0,0 +1,81 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GonkCameraImage.h"
#include "stagefright/MediaBuffer.h"
namespace mozilla {
GonkCameraImage::GonkCameraImage()
: GrallocImage()
, mMonitor("GonkCameraImage.Monitor")
, mMediaBuffer(nullptr)
, mThread(nullptr)
{
mFormat = ImageFormat::GONK_CAMERA_IMAGE;
}
GonkCameraImage::~GonkCameraImage()
{
ReentrantMonitorAutoEnter mon(mMonitor);
// mMediaBuffer must be cleared before destructor.
MOZ_ASSERT(mMediaBuffer == nullptr);
}
nsresult
GonkCameraImage::GetBuffer(android::MediaBuffer** aBuffer)
{
ReentrantMonitorAutoEnter mon(mMonitor);
if (!mMediaBuffer) {
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(NS_GetCurrentThread() == mThread);
*aBuffer = mMediaBuffer;
mMediaBuffer->add_ref();
return NS_OK;
}
bool
GonkCameraImage::HasMediaBuffer()
{
ReentrantMonitorAutoEnter mon(mMonitor);
return mMediaBuffer != nullptr;
}
nsresult
GonkCameraImage::SetBuffer(android::MediaBuffer* aBuffer)
{
ReentrantMonitorAutoEnter mon(mMonitor);
MOZ_ASSERT(!mMediaBuffer);
mMediaBuffer = aBuffer;
mMediaBuffer->add_ref();
mThread = NS_GetCurrentThread();
return NS_OK;
}
nsresult
GonkCameraImage::ClearBuffer()
{
ReentrantMonitorAutoEnter mon(mMonitor);
if (mMediaBuffer) {
MOZ_ASSERT(NS_GetCurrentThread() == mThread);
mMediaBuffer->release();
mMediaBuffer = nullptr;
mThread = nullptr;
}
return NS_OK;
}
} // namespace mozilla

View File

@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GONKCAMERAIMAGE_H
#define GONKCAMERAIMAGE_H
#include "mozilla/ReentrantMonitor.h"
#include "ImageLayers.h"
#include "ImageContainer.h"
#include "GrallocImages.h"
namespace android {
class MOZ_EXPORT MediaBuffer;
}
namespace mozilla {
/**
* GonkCameraImage has two parts. One is preview image which will be saved in
* GrallocImage, another kind is the MediaBuffer keeps in mMediaBuffer
* which is from gonk camera recording callback. The data in MediaBuffer is Gonk
* shared memory based on android binder (IMemory), the actual format in IMemory
* is platform dependent.
* This instance is created in MediaEngine when the preview image arrives.
* The MediaBuffer is attached to the current created GonkCameraImage via SetBuffer().
* After sending this image to MediaStreamGraph by AppendToTrack(), ClearBuffer()
* must be called to clear MediaBuffer to avoid MediaBuffer be kept in MSG thread.
* The reason to keep MediaBuffer be accessed from MSG thread is MediaBuffer is
* limited resource and it could cause frame rate jitter if MediaBuffer stay too
* long in other threads.
* So there will be 3 threads to accessed this class. First is camera preview
* thread which creates an instance of this class and initialize the preview
* image in the base class GrallocImage. Second is the camera recording
* thread which attaches MediaBuffer and sends this image to MediaStreamDirectListener.
* Third is the MSG thread via NotifyPull, the image should have preview image
* only in NotifyPull.
*
* Note: SetBuffer() and GetBuffer() should be called from the same thread. It
* is forbidden to call GetBuffer() from other threads.
*/
class GonkCameraImage : public layers::GrallocImage
{
public:
GonkCameraImage();
// The returned aBuffer has called aBuffer->add_ref() already, so it is caller's
// duty to release aBuffer. It should be called from the same thread which
// called SetBuffer().
nsresult GetBuffer(android::MediaBuffer** aBuffer);
// Set MediaBuffer to image. It is caller's responsibility to call ClearBuffer()
// after the MediaBuffer is sent via MediaStreamGraph.
nsresult SetBuffer(android::MediaBuffer* aBuffer);
// It should be called from the same thread which called SetBuffer().
nsresult ClearBuffer();
bool HasMediaBuffer();
protected:
virtual ~GonkCameraImage();
// mMonitor protects mMediaBuffer and mThread.
ReentrantMonitor mMonitor;
android::MediaBuffer* mMediaBuffer;
// Check if current thread is the same one which called SetBuffer().
// It doesn't need to hold reference count.
DebugOnly<nsIThread*> mThread;
};
} // namespace mozilla
#endif /* GONKCAMERAIMAGE_H */

View File

@ -15,11 +15,13 @@
#include "libyuv.h"
#include "mtransport/runnable_utils.h"
#include "GonkCameraImage.h"
namespace mozilla {
using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace android;
#ifdef PR_LOGGING
extern PRLogModuleInfo* GetMediaManagerLog();
@ -30,6 +32,29 @@ extern PRLogModuleInfo* GetMediaManagerLog();
#define LOGFRAME(msg)
#endif
class MediaBufferListener : public GonkCameraSource::DirectBufferListener {
public:
MediaBufferListener(MediaEngineGonkVideoSource* aMediaEngine)
: mMediaEngine(aMediaEngine)
{
}
status_t BufferAvailable(MediaBuffer* aBuffer)
{
nsresult rv = mMediaEngine->OnNewMediaBufferFrame(aBuffer);
if (NS_SUCCEEDED(rv)) {
return OK;
}
return UNKNOWN_ERROR;
}
~MediaBufferListener()
{
}
nsRefPtr<MediaEngineGonkVideoSource> mMediaEngine;
};
#define WEBRTC_GONK_VIDEO_SOURCE_POOL_BUFFERS 10
// We are subclassed from CameraControlListener, which implements a
@ -168,6 +193,46 @@ MediaEngineGonkVideoSource::Start(SourceMediaStream* aStream, TrackID aID)
return NS_ERROR_FAILURE;
}
if (NS_FAILED(InitDirectMediaBuffer())) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
MediaEngineGonkVideoSource::InitDirectMediaBuffer()
{
// Check available buffer resolution.
nsTArray<ICameraControl::Size> videoSizes;
mCameraControl->Get(CAMERA_PARAM_SUPPORTED_VIDEOSIZES, videoSizes);
if (!videoSizes.Length()) {
return NS_ERROR_FAILURE;
}
// TODO: MediaEgnine should use supported recording frame sizes as the size
// range in MediaTrackConstraintSet and find the best match.
// Here we use the first one as the default size (largest supported size).
android::Size videoSize;
videoSize.width = videoSizes[0].width;
videoSize.height = videoSizes[0].height;
LOG(("Intial size, width: %d, height: %d", videoSize.width, videoSize.height));
mCameraSource = GonkCameraSource::Create(mCameraControl,
videoSize,
MediaEngine::DEFAULT_VIDEO_FPS);
status_t rv;
rv = mCameraSource->AddDirectBufferListener(new MediaBufferListener(this));
if (rv != OK) {
return NS_ERROR_FAILURE;
}
rv = mCameraSource->start(nullptr);
if (rv != OK) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
@ -353,6 +418,9 @@ void
MediaEngineGonkVideoSource::StopImpl() {
MOZ_ASSERT(NS_IsMainThread());
mCameraSource->stop();
mCameraSource = nullptr;
hal::UnregisterScreenConfigurationObserver(this);
mCameraControl->Stop();
}
@ -589,17 +657,17 @@ MediaEngineGonkVideoSource::ConvertPixelFormatToFOURCC(int aFormat)
void
MediaEngineGonkVideoSource::RotateImage(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) {
layers::GrallocImage *nativeImage = static_cast<layers::GrallocImage*>(aImage);
android::sp<android::GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer();
android::sp<GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer();
void *pMem = nullptr;
// Bug 1109957 size will be wrong if width or height are odd
uint32_t size = aWidth * aHeight * 3 / 2;
MOZ_ASSERT(!(aWidth & 1) && !(aHeight & 1));
graphicBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_MASK, &pMem);
graphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_MASK, &pMem);
uint8_t* srcPtr = static_cast<uint8_t*>(pMem);
// Create a video frame and append it to the track.
ImageFormat format = ImageFormat::GRALLOC_PLANAR_YCBCR;
ImageFormat format = ImageFormat::GONK_CAMERA_IMAGE;
nsRefPtr<layers::Image> image = mImageContainer->CreateImage(format);
uint32_t dstWidth;
@ -657,23 +725,8 @@ MediaEngineGonkVideoSource::RotateImage(layers::Image* aImage, uint32_t aWidth,
data.mGraphicBuffer = textureClient;
videoImage->SetData(data);
// implicitly releases last image
// Implicitly releases last preview image.
mImage = image.forget();
// Push the frame into the MSG with a minimal duration. This will likely
// mean we'll still get NotifyPull calls which will then return the same
// frame again with a longer duration. However, this means we won't
// fail to get the frame in and drop frames.
// XXX The timestamp for the frame should be base on the Capture time,
// not the MSG time, and MSG should never, ever block on a (realtime)
// video frame (or even really for streaming - audio yes, video probably no).
uint32_t len = mSources.Length();
for (uint32_t i = 0; i < len; i++) {
if (mSources[i]) {
AppendToTrack(mSources[i], mImage, mTrackID, 1); // shortest possible duration
}
}
}
bool
@ -702,4 +755,40 @@ MediaEngineGonkVideoSource::OnNewPreviewFrame(layers::Image* aImage, uint32_t aW
return true; // return true because we're accepting the frame
}
nsresult
MediaEngineGonkVideoSource::OnNewMediaBufferFrame(MediaBuffer* aBuffer)
{
{
ReentrantMonitorAutoEnter sync(mCallbackMonitor);
if (mState == kStopped) {
return NS_OK;
}
}
MonitorAutoLock enter(mMonitor);
if (mImage) {
GonkCameraImage* cameraImage = static_cast<GonkCameraImage*>(mImage.get());
cameraImage->SetBuffer(aBuffer);
uint32_t len = mSources.Length();
for (uint32_t i = 0; i < len; i++) {
if (mSources[i]) {
// Duration is 1 here.
// Ideally, it should be camera timestamp here and the MSG will have
// enough sample duration without calling NotifyPull() anymore.
// Unfortunately, clock in gonk camera looks like is a different one
// comparing to MSG. As result, it causes time inaccurate. (frames be
// queued in MSG longer and longer as time going by in device like Frame)
AppendToTrack(mSources[i], cameraImage, mTrackID, 1);
}
}
// Clear MediaBuffer immediately, it prevents MediaBuffer is kept in
// MediaStreamGraph thread.
cameraImage->ClearBuffer();
}
return NS_OK;
}
} // namespace mozilla

View File

@ -16,6 +16,11 @@
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/dom/File.h"
#include "mozilla/layers/TextureClientRecycleAllocator.h"
#include "GonkCameraSource.h"
namespace android {
class MOZ_EXPORT MediaBuffer;
}
namespace mozilla {
@ -91,6 +96,12 @@ public:
// current screen orientation.
nsresult UpdatePhotoOrientation();
// It adds aBuffer to current preview image and sends this image to MediaStreamDirectListener
// via AppendToTrack(). Due to MediaBuffer is limited resource, it will clear
// image's MediaBuffer by calling GonkCameraImage::ClearBuffer() before leaving
// this function.
nsresult OnNewMediaBufferFrame(android::MediaBuffer* aBuffer);
protected:
~MediaEngineGonkVideoSource()
{
@ -101,12 +112,17 @@ protected:
void Shutdown();
void ChooseCapability(const VideoTrackConstraintsN& aConstraints,
const MediaEnginePrefs& aPrefs);
// Initialize the recording frame (MediaBuffer) callback and Gonk camera.
// MediaBuffer will transfers to MediaStreamGraph via AppendToTrack.
nsresult InitDirectMediaBuffer();
mozilla::ReentrantMonitor mCallbackMonitor; // Monitor for camera callback handling
// This is only modified on MainThread (AllocImpl and DeallocImpl)
nsRefPtr<ICameraControl> mCameraControl;
nsCOMPtr<nsIDOMFile> mLastCapture;
android::sp<android::GonkCameraSource> mCameraSource;
// These are protected by mMonitor in parent class
nsTArray<nsRefPtr<PhotoCallback>> mPhotoCallbacks;
int mRotation;

View File

@ -36,8 +36,12 @@ if CONFIG['MOZ_WEBRTC']:
]
# Gonk camera source.
if CONFIG['MOZ_B2G_CAMERA']:
EXPORTS += ['MediaEngineGonkVideoSource.h']
EXPORTS += [
'GonkCameraImage.h',
'MediaEngineGonkVideoSource.h',
]
UNIFIED_SOURCES += [
'GonkCameraImage.cpp',
'MediaEngineGonkVideoSource.cpp',
]

View File

@ -17,12 +17,15 @@ Cu.import("resource://gre/modules/PermissionsTable.jsm");
let DEBUG = false;
let VERBOSE = false;
let TRACK = false;
try {
DEBUG =
Services.prefs.getBoolPref("dom.mozSettings.SettingsRequestManager.debug.enabled");
VERBOSE =
Services.prefs.getBoolPref("dom.mozSettings.SettingsRequestManager.verbose.enabled");
TRACK =
Services.prefs.getBoolPref("dom.mozSettings.trackTasksUsage");
} catch (ex) { }
let allowForceReadOnly = false;
@ -207,7 +210,12 @@ let SettingsRequestManager = {
// for message managers and check permissions on them before we send
// settings notifications to child processes.
observerPrincipalCache: new Map(),
tasksConsumed: 0,
totalProcessed: 0,
tasksConsumed: {},
totalSetProcessed: 0,
tasksSetConsumed: {},
totalGetProcessed: 0,
tasksGetConsumed: {},
init: function() {
if (VERBOSE) debug("init");
@ -650,6 +658,13 @@ let SettingsRequestManager = {
}
let currentTask = lock.tasks.shift();
let promises = [];
if (TRACK) {
if (this.tasksConsumed[aLockID] === undefined) {
this.tasksConsumed[aLockID] = 0;
this.tasksGetConsumed[aLockID] = 0;
this.tasksSetConsumed[aLockID] = 0;
}
}
while (currentTask) {
if (VERBOSE) debug("Running Operation " + currentTask.operation);
if (lock.finalizing) {
@ -659,12 +674,23 @@ let SettingsRequestManager = {
currentTask.defer.reject("Cannot call new task after finalizing");
} else {
let p;
this.tasksConsumed++;
this.totalProcessed++;
if (TRACK) {
this.tasksConsumed[aLockID]++;
}
switch (currentTask.operation) {
case "get":
this.totalGetProcessed++;
if (TRACK) {
this.tasksGetConsumed[aLockID]++;
}
p = this.taskGet(currentTask);
break;
case "set":
this.totalSetProcessed++;
if (TRACK) {
this.tasksSetConsumed[aLockID]++;
}
p = this.taskSet(currentTask);
break;
case "clear":
@ -753,23 +779,75 @@ let SettingsRequestManager = {
continue;
}
let path = "settings-locks/tasks/queue-length(id=" + lockId + ")";
let path = "settings-locks/tasks/lock(id=" + lockId + ")/";
aCallback.callback("", path,
aCallback.callback("", path + "alive",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
length,
"Tasks queue length for this lock",
"Alive tasks for this lock",
aData);
}
aCallback.callback("",
"settings-locks/tasks/processed",
"settings-locks/tasks-total/processed",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this.tasksConsumed,
"The number of tasks that were executed.",
this.totalProcessed,
"The total number of tasks that were executed.",
aData);
aCallback.callback("",
"settings-locks/tasks-total/set",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this.totalSetProcessed,
"The total number of set tasks that were executed.",
aData);
aCallback.callback("",
"settings-locks/tasks-total/get",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this.totalGetProcessed,
"The total number of get tasks that were executed.",
aData);
// if TRACK is not enabled, then, no details are available
if (!TRACK) {
return;
}
for (let lockId of Object.keys(this.tasksConsumed)) {
let lock = this.lockInfo[lockId];
let length = 0;
if (lock) {
length = lock.tasks.length;
}
let path = "settings-locks/tasks/lock(id=" + lockId + ")/";
aCallback.callback("", path + "set",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this.tasksSetConsumed[lockId],
"Set tasks for this lock.",
aData);
aCallback.callback("", path + "get",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this.tasksGetConsumed[lockId],
"Get tasks for this lock.",
aData);
aCallback.callback("", path + "processed",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this.tasksConsumed[lockId],
"Number of tasks that were executed.",
aData);
}
},
sendSettingsChange: function(aKey, aValue, aIsServiceLock) {

View File

@ -32,8 +32,12 @@ XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
XPCOMUtils.defineLazyServiceGetter(this, "mrm",
"@mozilla.org/memory-reporter-manager;1",
"nsIMemoryReporterManager");
const nsIClassInfo = Ci.nsIClassInfo;
const nsIClassInfo = Ci.nsIClassInfo;
const kXpcomShutdownObserverTopic = "xpcom-shutdown";
const SETTINGSSERVICELOCK_CONTRACTID = "@mozilla.org/settingsServiceLock;1";
const SETTINGSSERVICELOCK_CID = Components.ID("{d7a395a0-e292-11e1-834e-1761d57f5f99}");
@ -85,6 +89,7 @@ SettingsServiceLock.prototype = {
runOrFinalizeQueries: function() {
if (!this._requests || Object.keys(this._requests).length == 0) {
this._settingsService.unregisterLock(this._id);
cpmm.sendAsyncMessage("Settings:Finalize", {lockID: this._id}, undefined, Services.scriptSecurityManager.getSystemPrincipal());
} else {
cpmm.sendAsyncMessage("Settings:Run", {lockID: this._id}, undefined, Services.scriptSecurityManager.getSystemPrincipal());
@ -229,17 +234,81 @@ const SETTINGSSERVICE_CID = Components.ID("{f656f0c0-f776-11e1-a21f-08002
function SettingsService()
{
if (VERBOSE) debug("settingsService Constructor");
this._locks = [];
this._createdLocks = 0;
this._unregisteredLocks = 0;
this.init();
}
SettingsService.prototype = {
init: function() {
Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false);
mrm.registerStrongReporter(this);
},
uninit: function() {
Services.obs.removeObserver(this, kXpcomShutdownObserverTopic);
mrm.unregisterStrongReporter(this);
},
observe: function(aSubject, aTopic, aData) {
if (VERBOSE) debug("observe: " + aTopic);
if (aTopic === kXpcomShutdownObserverTopic) {
this.uninit();
}
},
createLock: function createLock(aCallback) {
var lock = new SettingsServiceLock(this, aCallback);
this.registerLock(lock._id);
return lock;
},
registerLock: function(aLockID) {
this._locks.push(aLockID);
this._createdLocks++;
},
unregisterLock: function(aLockID) {
let lock_index = this._locks.indexOf(aLockID);
if (lock_index != -1) {
if (VERBOSE) debug("Unregistering lock " + aLockID);
this._locks.splice(lock_index, 1);
this._unregisteredLocks++;
}
},
collectReports: function(aCallback, aData, aAnonymize) {
aCallback.callback("",
"settings-service-locks/alive",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this._locks.length,
"The number of service locks that are currently alives.",
aData);
aCallback.callback("",
"settings-service-locks/created",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this._createdLocks,
"The number of service locks that were created.",
aData);
aCallback.callback("",
"settings-service-locks/deleted",
Ci.nsIMemoryReporter.KIND_OTHER,
Ci.nsIMemoryReporter.UNITS_COUNT,
this._unregisteredLocks,
"The number of service locks that were deleted.",
aData);
},
classID : SETTINGSSERVICE_CID,
QueryInterface : XPCOMUtils.generateQI([Ci.nsISettingsService])
QueryInterface : XPCOMUtils.generateQI([Ci.nsISettingsService,
Ci.nsIObserver,
Ci.nsIMemoryReporter])
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsService, SettingsServiceLock]);

View File

@ -65,6 +65,9 @@ public:
NS_IMETHOD Run()
{
MOZ_ASSERT(!NS_IsMainThread());
#ifdef MOZ_NUWA_PROCESS
NS_SetIgnoreStatusOfCurrentThread();
#endif
nsAutoString event;
gWpaSupplicant->WaitForEvent(event, mInterface);
if (!event.IsEmpty()) {

View File

@ -73,6 +73,7 @@
#include "nsProxyRelease.h"
#include "nsSandboxFlags.h"
#include "prthread.h"
#include "nsThread.h"
#include "xpcpublic.h"
#ifdef ANDROID
@ -4332,6 +4333,17 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
{
MutexAutoLock lock(mMutex);
#ifdef MOZ_NUWA_PROCESS
{
nsThread *thr = static_cast<nsThread*>(NS_GetCurrentThread());
ReentrantMonitorAutoEnter mon(thr->ThreadStatusMonitor());
if (mControlQueue.IsEmpty() &&
!(normalRunnablesPending = NS_HasPendingEvents(mThread))) {
thr->SetIdle();
}
}
#endif // MOZ_NUWA_PROCESS
while (mControlQueue.IsEmpty() &&
!(normalRunnablesPending = NS_HasPendingEvents(mThread))) {
WaitForWorkerEvents();

View File

@ -97,6 +97,11 @@ public:
virtual TextureClient* GetTextureClient(CompositableClient* aClient) MOZ_OVERRIDE;
virtual GrallocImage* AsGrallocImage() MOZ_OVERRIDE
{
return this;
}
virtual uint8_t* GetBuffer()
{
return static_cast<uint8_t*>(GetNativeBuffer());

View File

@ -19,6 +19,7 @@
#include "YCbCrUtils.h" // for YCbCr conversions
#ifdef MOZ_WIDGET_GONK
#include "GrallocImages.h"
#include "GonkCameraImage.h"
#endif
#include "gfx2DGlue.h"
#include "mozilla/gfx/2D.h"
@ -60,6 +61,10 @@ ImageFactory::CreateImage(ImageFormat aFormat,
img = new OverlayImage();
return img.forget();
}
if (aFormat == ImageFormat::GONK_CAMERA_IMAGE) {
img = new GonkCameraImage();
return img.forget();
}
#endif
if (aFormat == ImageFormat::PLANAR_YCBCR) {
img = new PlanarYCbCrImage(aRecycleBin);

View File

@ -105,6 +105,7 @@ class TextureClient;
class CompositableClient;
class CompositableForwarder;
class SurfaceDescriptor;
class GrallocImage;
struct ImageBackendData
{
@ -167,6 +168,11 @@ public:
virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() = 0;
virtual GrallocImage* AsGrallocImage()
{
return nullptr;
}
protected:
Image(void* aImplData, ImageFormat aFormat) :
mImplData(aImplData),

View File

@ -25,6 +25,16 @@ MOZ_BEGIN_ENUM_CLASS(ImageFormat)
*/
GRALLOC_PLANAR_YCBCR,
/**
* The GONK_CAMERA_IMAGE format creates a GonkCameraImage, which contains two
* parts. One is GrallocImage image for preview image. Another one is
* MediaBuffer from Gonk recording image. The preview image can be rendered in
* a layer for display. And the MediaBuffer will be used in component like OMX
* encoder. It is for GUM to support preview and recording image on Gonk
* camera.
*/
GONK_CAMERA_IMAGE,
/**
* The SHARED_RGB format creates a SharedRGBImage, which stores RGB data in
* shared memory. Some Android hardware video decoders require this format.

View File

@ -373,6 +373,11 @@ CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
newTex = TexClientFromReadback(surf, forwarder, flags, layersBackend);
}
MOZ_ASSERT(newTex);
if (!newTex) {
// May happen in a release build in case of memory pressure.
gfxCriticalError() << "Failed to allocate a TextureClient for SharedSurface Canvas. size: " << aSize;
return;
}
// Add the new TexClient.
MOZ_ALWAYS_TRUE( AddTextureClient(newTex) );

View File

@ -196,23 +196,30 @@ static void SetThreadPriority()
hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
}
CompositorVsyncObserver::CompositorVsyncObserver(CompositorParent* aCompositorParent)
CompositorVsyncObserver::CompositorVsyncObserver(CompositorParent* aCompositorParent, nsIWidget* aWidget)
: mNeedsComposite(false)
, mIsObservingVsync(false)
, mCompositorParent(aCompositorParent)
, mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
, mCurrentCompositeTask(nullptr)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aWidget != nullptr);
mVsyncDispatcher = aWidget->GetVsyncDispatcher();
#ifdef MOZ_WIDGET_GONK
GeckoTouchDispatcher::SetCompositorVsyncObserver(this);
#endif
}
CompositorVsyncObserver::~CompositorVsyncObserver()
{
MOZ_ASSERT(NS_IsMainThread());
UnobserveVsync();
mCompositorParent = nullptr;
mNeedsComposite = false;
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
MOZ_ASSERT(!mIsObservingVsync);
// The VsyncDispatcher is cleaned up before this in the nsBaseWidget, which stops vsync listeners
CancelCurrentCompositeTask();
mCompositorParent = nullptr;
mVsyncDispatcher = nullptr;
mNeedsComposite = false;
}
/**
@ -225,9 +232,14 @@ CompositorVsyncObserver::~CompositorVsyncObserver()
void
CompositorVsyncObserver::SetNeedsComposite(bool aNeedsComposite)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
mNeedsComposite = aNeedsComposite;
if (aNeedsComposite && !CompositorParent::IsInCompositorThread()) {
CompositorParent::CompositorLoop()->PostTask(FROM_HERE,
NewRunnableMethod(this,
&CompositorVsyncObserver::SetNeedsComposite,
aNeedsComposite));
}
mNeedsComposite = aNeedsComposite;
if (!mIsObservingVsync && mNeedsComposite) {
ObserveVsync();
}
@ -273,10 +285,6 @@ CompositorVsyncObserver::Composite(TimeStamp aVsyncTimestamp)
if (mNeedsComposite && mCompositorParent) {
mNeedsComposite = false;
mCompositorParent->CompositeCallback(aVsyncTimestamp);
} else {
// We're getting vsync notifications but we don't need to composite so
// unregister the vsync.
UnobserveVsync();
}
DispatchTouchEvents(aVsyncTimestamp);
@ -289,15 +297,11 @@ CompositorVsyncObserver::NeedsComposite()
return mNeedsComposite;
}
/**
* Since the vsync thread has its own locks before notifying us of vsync
* we can't register/unregister from the vsync thread. Any other thread is fine
*/
void
CompositorVsyncObserver::ObserveVsync()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
VsyncDispatcher::GetInstance()->AddCompositorVsyncObserver(this);
mVsyncDispatcher->SetCompositorVsyncObserver(this);
mIsObservingVsync = true;
}
@ -305,7 +309,7 @@ void
CompositorVsyncObserver::UnobserveVsync()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread() || NS_IsMainThread());
VsyncDispatcher::GetInstance()->RemoveCompositorVsyncObserver(this);
mVsyncDispatcher->SetCompositorVsyncObserver(nullptr);
mIsObservingVsync = false;
}
@ -313,9 +317,7 @@ void
CompositorVsyncObserver::DispatchTouchEvents(TimeStamp aVsyncTimestamp)
{
#ifdef MOZ_WIDGET_GONK
if (gfxPrefs::TouchResampling()) {
GeckoTouchDispatcher::NotifyVsync(aVsyncTimestamp);
}
GeckoTouchDispatcher::NotifyVsync(aVsyncTimestamp);
#endif
}
@ -385,7 +387,7 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
}
if (gfxPrefs::VsyncAlignedCompositor()) {
mCompositorVsyncObserver = new CompositorVsyncObserver(this);
mCompositorVsyncObserver = new CompositorVsyncObserver(this, aWidget);
}
gfxPlatform::GetPlatform()->ComputeTileSize();
@ -428,7 +430,10 @@ CompositorParent::Destroy()
mApzcTreeManager = nullptr;
}
sIndirectLayerTrees.erase(mRootLayerTreeID);
mCompositorVsyncObserver = nullptr;
if (mCompositorVsyncObserver) {
mCompositorVsyncObserver->UnobserveVsync();
mCompositorVsyncObserver = nullptr;
}
}
void

View File

@ -100,12 +100,12 @@ class CompositorVsyncObserver MOZ_FINAL : public VsyncObserver
friend class CompositorParent;
public:
explicit CompositorVsyncObserver(CompositorParent* aCompositorParent);
explicit CompositorVsyncObserver(CompositorParent* aCompositorParent, nsIWidget* aWidget);
virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) MOZ_OVERRIDE;
void SetNeedsComposite(bool aSchedule);
bool NeedsComposite();
void CancelCurrentCompositeTask();
private:
virtual ~CompositorVsyncObserver();
@ -118,6 +118,7 @@ private:
bool mNeedsComposite;
bool mIsObservingVsync;
nsRefPtr<CompositorParent> mCompositorParent;
nsRefPtr<VsyncDispatcher> mVsyncDispatcher;
mozilla::Monitor mCurrentCompositeTaskMonitor;
CancelableTask* mCurrentCompositeTask;

View File

@ -0,0 +1,66 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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 "VsyncSource.h"
#include "gfxPlatform.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/VsyncDispatcher.h"
using namespace mozilla;
using namespace mozilla::gfx;
void
VsyncSource::AddVsyncDispatcher(VsyncDispatcher* aVsyncDispatcher)
{
MOZ_ASSERT(NS_IsMainThread());
GetGlobalDisplay().AddVsyncDispatcher(aVsyncDispatcher);
}
void
VsyncSource::RemoveVsyncDispatcher(VsyncDispatcher* aVsyncDispatcher)
{
MOZ_ASSERT(NS_IsMainThread());
GetGlobalDisplay().RemoveVsyncDispatcher(aVsyncDispatcher);
}
VsyncSource::Display&
VsyncSource::FindDisplay(VsyncDispatcher* aVsyncDispatcher)
{
return GetGlobalDisplay();
}
void
VsyncSource::Display::NotifyVsync(TimeStamp aVsyncTimestamp)
{
// Called on the hardware vsync thread
for (size_t i = 0; i < mVsyncDispatchers.Length(); i++) {
mVsyncDispatchers[i]->NotifyVsync(aVsyncTimestamp);
}
}
VsyncSource::Display::Display()
{
MOZ_ASSERT(NS_IsMainThread());
}
VsyncSource::Display::~Display()
{
MOZ_ASSERT(NS_IsMainThread());
mVsyncDispatchers.Clear();
}
void
VsyncSource::Display::AddVsyncDispatcher(VsyncDispatcher* aVsyncDispatcher)
{
MOZ_ASSERT(NS_IsMainThread());
mVsyncDispatchers.AppendElement(aVsyncDispatcher);
}
void
VsyncSource::Display::RemoveVsyncDispatcher(VsyncDispatcher* aVsyncDispatcher)
{
MOZ_ASSERT(NS_IsMainThread());
mVsyncDispatchers.RemoveElement(aVsyncDispatcher);
}

50
gfx/thebes/VsyncSource.h Normal file
View File

@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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 "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"
#include "nsISupportsImpl.h"
#include "nsTArray.h"
namespace mozilla {
class VsyncDispatcher;
namespace gfx {
// Controls how and when to enable/disable vsync. Lives as long as the
// gfxPlatform does on the parent process
class VsyncSource
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncSource)
public:
// Controls vsync unique to each display and unique on each platform
class Display {
public:
Display();
virtual ~Display();
void AddVsyncDispatcher(mozilla::VsyncDispatcher* aVsyncDispatcher);
void RemoveVsyncDispatcher(mozilla::VsyncDispatcher* aVsyncDispatcher);
// Notified when this display's vsync occurs, on the hardware vsync thread
void NotifyVsync(mozilla::TimeStamp aVsyncTimestamp);
// These should all only be called on the main thread
virtual void EnableVsync() = 0;
virtual void DisableVsync() = 0;
virtual bool IsVsyncEnabled() = 0;
private:
nsTArray<nsRefPtr<mozilla::VsyncDispatcher>> mVsyncDispatchers;
}; // end Display
void AddVsyncDispatcher(mozilla::VsyncDispatcher* aVsyncDispatcher);
void RemoveVsyncDispatcher(mozilla::VsyncDispatcher* aVsyncDispatcher);
protected:
virtual Display& GetGlobalDisplay() = 0; // Works across all displays
virtual Display& FindDisplay(mozilla::VsyncDispatcher* aVsyncDispatcher);
virtual ~VsyncSource() {}
}; // VsyncSource
} // gfx
} // mozilla

View File

@ -23,6 +23,7 @@
#include "nsServiceManagerUtils.h"
#include "gfxPrefs.h"
#include "cairo.h"
#include "VsyncSource.h"
#ifdef MOZ_WIDGET_ANDROID
#include "AndroidBridge.h"
@ -30,6 +31,8 @@
#ifdef MOZ_WIDGET_GONK
#include <cutils/properties.h>
#include "mozilla/layers/CompositorParent.h"
#include "HwcComposer2D.h"
#endif
#include "ft2build.h"
@ -420,3 +423,72 @@ bool gfxAndroidPlatform::HaveChoiceOfHWAndSWCanvas()
#endif
return gfxPlatform::HaveChoiceOfHWAndSWCanvas();
}
#ifdef MOZ_WIDGET_GONK
class GonkVsyncSource MOZ_FINAL : public VsyncSource
{
public:
GonkVsyncSource()
{
}
virtual Display& GetGlobalDisplay() MOZ_OVERRIDE
{
return mGlobalDisplay;
}
protected:
class GonkDisplay MOZ_FINAL : public VsyncSource::Display
{
public:
GonkDisplay() : mVsyncEnabled(false)
{
EnableVsync();
}
~GonkDisplay()
{
DisableVsync();
}
virtual void EnableVsync() MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
mVsyncEnabled = HwcComposer2D::GetInstance()->EnableVsync(true);
}
virtual void DisableVsync() MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
mVsyncEnabled = HwcComposer2D::GetInstance()->EnableVsync(false);
}
virtual bool IsVsyncEnabled() MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
return mVsyncEnabled;
}
private:
bool mVsyncEnabled;
}; // GonkDisplay
private:
virtual ~GonkVsyncSource()
{
}
GonkDisplay mGlobalDisplay;
}; // GonkVsyncSource
#endif
already_AddRefed<mozilla::gfx::VsyncSource>
gfxAndroidPlatform::CreateHardwareVsyncSource()
{
#ifdef MOZ_WIDGET_GONK
nsRefPtr<VsyncSource> vsyncSource = new GonkVsyncSource();
return vsyncSource.forget();
#else
NS_WARNING("Hardware vsync not supported on android yet");
return nullptr;
#endif
}

View File

@ -89,6 +89,8 @@ public:
virtual bool HaveChoiceOfHWAndSWCanvas() MOZ_OVERRIDE;
virtual bool UseAcceleratedSkiaCanvas() MOZ_OVERRIDE;
virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() MOZ_OVERRIDE;
#ifdef MOZ_WIDGET_GONK
virtual bool IsInGonkEmulator() const { return mIsInGonkEmulator; }

View File

@ -104,6 +104,7 @@ class mozilla::gl::SkiaGLGlue : public GenericAtomicRefCounted {
#include "nsIGfxInfo.h"
#include "nsIXULRuntime.h"
#include "VsyncSource.h"
namespace mozilla {
namespace layers {
@ -548,8 +549,8 @@ gfxPlatform::Init()
RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
if (gfxPrefs::HardwareVsyncEnabled() && gfxPrefs::VsyncAlignedCompositor()) {
gPlatform->InitHardwareVsync();
if (XRE_IsParentProcess() && gfxPrefs::HardwareVsyncEnabled()) {
gPlatform->mVsyncSource = gPlatform->CreateHardwareVsyncSource();
}
}
@ -597,6 +598,7 @@ gfxPlatform::Shutdown()
gPlatform->mMemoryPressureObserver = nullptr;
gPlatform->mSkiaGlue = nullptr;
gPlatform->mVsyncSource = nullptr;
}
#ifdef MOZ_WIDGET_ANDROID

View File

@ -50,6 +50,7 @@ class SourceSurface;
class DataSourceSurface;
class ScaledFont;
class DrawEventRecorder;
class VsyncSource;
inline uint32_t
BackendTypeBit(BackendType b)
@ -583,6 +584,17 @@ public:
static bool UsesOffMainThreadCompositing();
bool HasEnoughTotalSystemMemoryForSkiaGL();
/**
* Get the hardware vsync source for each platform.
* Should only exist and be valid on the parent process
*/
virtual mozilla::gfx::VsyncSource* GetHardwareVsync() {
MOZ_ASSERT(mVsyncSource != nullptr);
MOZ_ASSERT(XRE_IsParentProcess());
return mVsyncSource;
}
protected:
gfxPlatform();
virtual ~gfxPlatform();
@ -593,7 +605,10 @@ protected:
/**
* Initialized hardware vsync based on each platform.
*/
virtual void InitHardwareVsync() {}
virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() {
NS_WARNING("Hardware vsync not supported on platform yet");
return nullptr;
}
/**
* Helper method, creates a draw target for a specific Azure backend.
@ -659,6 +674,9 @@ protected:
uint32_t mTotalSystemMemory;
// Hardware vsync source. Only valid on parent process
nsRefPtr<mozilla::gfx::VsyncSource> mVsyncSource;
private:
/**
* Start up Thebes.

View File

@ -26,6 +26,8 @@
#include <CoreVideo/CoreVideo.h>
#include "nsCocoaFeatures.h"
#include "mozilla/layers/CompositorParent.h"
#include "VsyncSource.h"
using namespace mozilla;
using namespace mozilla::gfx;
@ -38,7 +40,7 @@ typedef uint32_t AutoActivationSetting;
// bug 567552 - disable auto-activation of fonts
static void
static void
DisableFontActivation()
{
// get the main bundle identifier
@ -429,81 +431,98 @@ static CVReturn VsyncCallback(CVDisplayLinkRef aDisplayLink,
CVOptionFlags* aFlagsOut,
void* aDisplayLinkContext)
{
mozilla::VsyncSource* vsyncSource = (mozilla::VsyncSource*) aDisplayLinkContext;
if (vsyncSource->IsVsyncEnabled()) {
// Now refers to "Now" as in when this callback is called or when the current frame
// is displayed. aOutputTime is when the next frame should be displayed.
// Now is VERY VERY noisy, aOutputTime is in the future though.
int64_t timestamp = aOutputTime->hostTime;
mozilla::TimeStamp vsyncTime = mozilla::TimeStamp::FromSystemTime(timestamp);
mozilla::VsyncDispatcher::GetInstance()->NotifyVsync(vsyncTime);
return kCVReturnSuccess;
} else {
return kCVReturnDisplayLinkNotRunning;
}
VsyncSource::Display* display = (VsyncSource::Display*) aDisplayLinkContext;
int64_t timestamp = aOutputTime->hostTime;
mozilla::TimeStamp vsyncTime = mozilla::TimeStamp::FromSystemTime(timestamp);
display->NotifyVsync(vsyncTime);
return kCVReturnSuccess;
}
class OSXVsyncSource MOZ_FINAL : public mozilla::VsyncSource
class OSXVsyncSource MOZ_FINAL : public VsyncSource
{
public:
OSXVsyncSource()
{
EnableVsync();
}
virtual void EnableVsync() MOZ_OVERRIDE
virtual Display& GetGlobalDisplay() MOZ_OVERRIDE
{
// Create a display link capable of being used with all active displays
// TODO: See if we need to create an active DisplayLink for each monitor in multi-monitor
// situations. According to the docs, it is compatible with all displays running on the computer
// But if we have different monitors at different display rates, we may hit issues.
if (CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink) != kCVReturnSuccess) {
NS_WARNING("Could not create a display link, returning");
return;
}
// Set the renderer output callback function
if (CVDisplayLinkSetOutputCallback(mDisplayLink, &VsyncCallback, this) != kCVReturnSuccess) {
NS_WARNING("Could not set displaylink output callback");
return;
}
// Activate the display link
if (CVDisplayLinkStart(mDisplayLink) != kCVReturnSuccess) {
NS_WARNING("Could not activate the display link");
mDisplayLink = nullptr;
}
return mGlobalDisplay;
}
virtual void DisableVsync() MOZ_OVERRIDE
protected:
class OSXDisplay MOZ_FINAL : public VsyncSource::Display
{
// Release the display link
if (mDisplayLink) {
CVDisplayLinkRelease(mDisplayLink);
mDisplayLink = nullptr;
public:
OSXDisplay()
{
EnableVsync();
}
}
virtual bool IsVsyncEnabled() MOZ_OVERRIDE
{
return mDisplayLink != nullptr;
}
~OSXDisplay()
{
DisableVsync();
}
virtual void EnableVsync() MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
// Create a display link capable of being used with all active displays
// TODO: See if we need to create an active DisplayLink for each monitor in multi-monitor
// situations. According to the docs, it is compatible with all displays running on the computer
// But if we have different monitors at different display rates, we may hit issues.
if (CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink) != kCVReturnSuccess) {
NS_WARNING("Could not create a display link, returning");
return;
}
if (CVDisplayLinkSetOutputCallback(mDisplayLink, &VsyncCallback, this) != kCVReturnSuccess) {
NS_WARNING("Could not set displaylink output callback");
return;
}
if (CVDisplayLinkStart(mDisplayLink) != kCVReturnSuccess) {
NS_WARNING("Could not activate the display link");
mDisplayLink = nullptr;
}
}
virtual void DisableVsync() MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
// Release the display link
if (mDisplayLink) {
CVDisplayLinkRelease(mDisplayLink);
mDisplayLink = nullptr;
}
}
virtual bool IsVsyncEnabled() MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
return mDisplayLink != nullptr;
}
private:
// Manages the display link render thread
CVDisplayLinkRef mDisplayLink;
}; // OSXDisplay
private:
virtual ~OSXVsyncSource()
{
DisableVsync();
}
// Manages the display link render thread
CVDisplayLinkRef mDisplayLink;
OSXDisplay mGlobalDisplay;
}; // OSXVsyncSource
void
gfxPlatformMac::InitHardwareVsync()
already_AddRefed<mozilla::gfx::VsyncSource>
gfxPlatformMac::CreateHardwareVsyncSource()
{
nsRefPtr<VsyncSource> osxVsyncSource = new OSXVsyncSource();
mozilla::VsyncDispatcher::GetInstance()->SetVsyncSource(osxVsyncSource);
return osxVsyncSource.forget();
}
void

View File

@ -9,7 +9,12 @@
#include "nsTArrayForwardDeclare.h"
#include "gfxPlatform.h"
namespace mozilla { namespace gfx { class DrawTarget; }}
namespace mozilla {
namespace gfx {
class DrawTarget;
class VsyncSource;
} // gfx
} // mozilla
class gfxPlatformMac : public gfxPlatform {
public:
@ -67,7 +72,7 @@ public:
virtual bool UseTiling() MOZ_OVERRIDE;
virtual bool UseProgressivePaint() MOZ_OVERRIDE;
virtual void InitHardwareVsync() MOZ_OVERRIDE;
virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() MOZ_OVERRIDE;
// lower threshold on font anti-aliasing
uint32_t GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }

View File

@ -52,6 +52,7 @@ EXPORTS += [
'gfxVR.h',
'GraphicsFilter.h',
'RoundedRect.h',
'VsyncSource.h',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
@ -246,6 +247,7 @@ UNIFIED_SOURCES += [
'gfxUtils.cpp',
'gfxVR.cpp',
'nsUnicodeRange.cpp',
'VsyncSource.cpp',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
@ -269,6 +271,9 @@ LOCAL_INCLUDES += [
'/dom/xml',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
LOCAL_INCLUDES += ['/widget/gonk']
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gtk3', 'gonk', 'qt'):
DEFINES['MOZ_ENABLE_FREETYPE'] = True

View File

@ -1,5 +1,6 @@
gczeal(14);
b = {};
b.__proto__ = evalcx("lazy");
(function m(b) {})(b.Intl.Collator(0))
if (this.hasOwnProperty("Intl")) {
gczeal(14);
b = {};
b.__proto__ = evalcx("lazy");
(function m(b) {})(b.Intl.Collator(0))
}

View File

@ -422,10 +422,7 @@ else:
'perf/pm_stub.cpp'
]
# Disable PGO for MSVC 2010 due to unpredictable performance, see
# bug 1030706.
if CONFIG['_MSC_VER'] != '1600':
MSVC_ENABLE_PGO = True
MSVC_ENABLE_PGO = True
HostSimplePrograms([
'host_jskwgen',

View File

@ -36,7 +36,7 @@
#include "nsIScriptSecurityManager.h"
#include "nsContentPolicyUtils.h"
#include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h"
#include "nsIClassOfService.h"
#include "nsIScriptError.h"
#include "nsMimeTypes.h"
#include "nsIStyleSheetLinkingElement.h"
@ -1623,10 +1623,12 @@ Loader::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState)
return rv;
}
nsCOMPtr<nsIHttpChannelInternal>
internalHttpChannel(do_QueryInterface(channel));
if (internalHttpChannel)
internalHttpChannel->SetLoadAsBlocking(!aLoadData->mWasAlternate);
if (!aLoadData->mWasAlternate) {
nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
if (cos) {
cos->AddClassFlags(nsIClassOfService::Leader);
}
}
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if (httpChannel) {

View File

@ -92,7 +92,7 @@ if CONFIG['OS_TARGET'] == 'Android':
'%s/sources/android/cpufeatures/cpu-features.c' % CONFIG['ANDROID_NDK'],
]
if not CONFIG['_MSC_VER']:
if CONFIG['CLANG_CL'] or not CONFIG['_MSC_VER']:
for f in SOURCES:
if f.endswith('.c'):
if 'sse2' in f:

View File

@ -1172,8 +1172,8 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk(
ImageFormat format = img->GetFormat();
#ifdef WEBRTC_GONK
if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) {
layers::GrallocImage *nativeImage = static_cast<layers::GrallocImage*>(img);
layers::GrallocImage* nativeImage = img->AsGrallocImage();
if (nativeImage) {
android::sp<android::GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer();
int pixelFormat = graphicBuffer->getPixelFormat(); /* PixelFormat is an enum == int */
mozilla::VideoType destFormat;

View File

@ -1284,6 +1284,7 @@ pref("network.http.spdy.enabled", true);
pref("network.http.spdy.enabled.v3-1", true);
pref("network.http.spdy.enabled.http2draft", true);
pref("network.http.spdy.enabled.http2", true);
pref("network.http.spdy.enabled.deps", true);
pref("network.http.spdy.enforce-tls-profile", true);
pref("network.http.spdy.chunk-size", 16000);
pref("network.http.spdy.timeout", 180);

View File

@ -30,6 +30,7 @@ XPIDL_SOURCES += [
'nsIChannel.idl',
'nsIChannelEventSink.idl',
'nsIChildChannel.idl',
'nsIClassOfService.idl',
'nsIContentSniffer.idl',
'nsICryptoFIPSInfo.idl',
'nsICryptoHash.idl',

View File

@ -0,0 +1,45 @@
/* 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 "nsISupports.idl"
/**
* nsIClassOfService.idl
*
* Used to express class dependencies and characteristics - complimentary to
* nsISupportsPriority which is used to express weight
*
* Channels that implement this interface may make use of this
* information in different ways.
*
* The default gecko HTTP/1 stack makes Followers wait for Leaders to
* complete before dispatching followers. Other classes run in
* parallel - neither being blocked nor blocking. All grouping is done
* based on the Load Group - separate load groups proceed
* independently.
*
* HTTP/2 does not use the load group, but prioritization is done per
* HTTP/2 session. HTTP/2 dispatches all the requests as soon as
* possible.
* The various classes are assigned logical priority
* dependency groups and then transactions of that class depend on the
* group. In this model Followers block on Leaders and Speculative
* depends on Background. See Http2Stream.cpp for weighting details.
*
*/
[scriptable, uuid(1ccb58ec-5e07-4cf9-a30d-ac5490d23b41)]
interface nsIClassOfService : nsISupports
{
attribute unsigned long classFlags;
void clearClassFlags(in unsigned long flags);
void addClassFlags(in unsigned long flags);
const unsigned long Leader = 1 << 0;
const unsigned long Follower = 1 << 1;
const unsigned long Speculative = 1 << 2;
const unsigned long Background = 1 << 3;
const unsigned long Unblocked = 1 << 4;
};

View File

@ -780,9 +780,10 @@ HttpConnInfo::SetHTTP2ProtocolVersion(uint8_t pv)
{
if (pv == SPDY_VERSION_31) {
protocolVersion.AssignLiteral(MOZ_UTF16("spdy/3.1"));
} else if (pv == NS_HTTP2_DRAFT_VERSION) {
MOZ_ASSERT (pv == NS_HTTP2_DRAFT_VERSION);
protocolVersion.Assign(NS_LITERAL_STRING(NS_HTTP2_DRAFT_TOKEN));
} else if (pv == HTTP_VERSION_2_DRAFT_15) {
protocolVersion.AssignLiteral(MOZ_UTF16("h2-14/15"));
} else if (pv == HTTP_VERSION_2_DRAFT_LATEST) {
protocolVersion.Assign(NS_LITERAL_STRING(HTTP2_DRAFT_LATEST_TOKEN));
} else {
MOZ_ASSERT (pv == HTTP_VERSION_2);
protocolVersion.Assign(MOZ_UTF16("h2"));

View File

@ -699,6 +699,7 @@ nsSocketTransportService::Run()
if (IsNuwaProcess()) {
NuwaMarkCurrentThread(nullptr, nullptr);
}
NS_SetIgnoreStatusOfCurrentThread();
#endif
SOCKET_LOG(("STS thread init\n"));

View File

@ -41,6 +41,7 @@ struct HttpChannelOpenArgs
OptionalInputStreamParams uploadStream;
bool uploadStreamHasHeaders;
uint16_t priority;
uint32_t classOfService;
uint8_t redirectionLimit;
bool allowPipelining;
bool allowSTS;

View File

@ -42,7 +42,8 @@ ASpdySession::NewSpdySession(uint32_t version,
// requests as a precondition
MOZ_ASSERT(version == SPDY_VERSION_31 ||
version == HTTP_VERSION_2 ||
version == NS_HTTP2_DRAFT_VERSION,
version == HTTP_VERSION_2_DRAFT_LATEST ||
version == HTTP_VERSION_2_DRAFT_15,
"Unsupported spdy version");
// Don't do a runtime check of IsSpdyV?Enabled() here because pref value
@ -54,8 +55,9 @@ ASpdySession::NewSpdySession(uint32_t version,
if (version == SPDY_VERSION_31) {
return new SpdySession31(aTransport);
} else if (version == NS_HTTP2_DRAFT_VERSION || version == HTTP_VERSION_2) {
return new Http2Session(aTransport);
} else if (version == HTTP_VERSION_2_DRAFT_LATEST || version == HTTP_VERSION_2 ||
version == HTTP_VERSION_2_DRAFT_15) {
return new Http2Session(aTransport, version);
}
return nullptr;
@ -77,16 +79,16 @@ SpdyInformation::SpdyInformation()
VersionString[1] = NS_LITERAL_CSTRING("h2");
ALPNCallbacks[1] = Http2Session::ALPNCallback;
Version[2] = NS_HTTP2_DRAFT_VERSION;
Version[2] = HTTP_VERSION_2_DRAFT_15; // 14 and 15 are aliased
VersionString[2] = NS_LITERAL_CSTRING("h2-14");
ALPNCallbacks[2] = Http2Session::ALPNCallback;
Version[3] = NS_HTTP2_DRAFT_VERSION;
Version[3] = HTTP_VERSION_2_DRAFT_15; // 14 and 15 are aliased
VersionString[3] = NS_LITERAL_CSTRING("h2-15");
ALPNCallbacks[3] = Http2Session::ALPNCallback;
Version[4] = NS_HTTP2_DRAFT_VERSION;
VersionString[4] = NS_LITERAL_CSTRING(NS_HTTP2_DRAFT_TOKEN);
Version[4] = HTTP_VERSION_2_DRAFT_LATEST;
VersionString[4] = NS_LITERAL_CSTRING(HTTP2_DRAFT_LATEST_TOKEN);
ALPNCallbacks[4] = Http2Session::ALPNCallback;
}

View File

@ -66,7 +66,7 @@ do { \
return NS_ERROR_ILLEGAL_VALUE; \
} while (0)
Http2Session::Http2Session(nsISocketTransport *aSocketTransport)
Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t version)
: mSocketTransport(aSocketTransport)
, mSegmentReader(nullptr)
, mSegmentWriter(nullptr)
@ -103,6 +103,8 @@ Http2Session::Http2Session(nsISocketTransport *aSocketTransport)
, mPreviousUsed(false)
, mWaitingForSettingsAck(false)
, mGoAwayOnPush(false)
, mUseH2Deps(false)
, mVersion(version)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
@ -125,7 +127,7 @@ Http2Session::Http2Session(nsISocketTransport *aSocketTransport)
mPingThreshold = gHttpHandler->SpdyPingThreshold();
mNegotiatedToken.AssignLiteral(NS_HTTP2_DRAFT_TOKEN);
mNegotiatedToken.AssignLiteral(HTTP2_DRAFT_LATEST_TOKEN);
}
// Copy the 32 bit number into the destination, using network byte order
@ -789,20 +791,26 @@ Http2Session::GenerateGoAway(uint32_t aStatusCode)
FlushOutputQueue();
}
// The Hello is comprised of 24 octets of magic, which are designed to
// flush out silent but broken intermediaries, followed by a settings
// frame which sets a small flow control window for pushes and a
// window update frame which creates a large session flow control window
// The Hello is comprised of
// 1] 24 octets of magic, which are designed to
// flush out silent but broken intermediaries
// 2] a settings frame which sets a small flow control window for pushes
// 3] a window update frame which creates a large session flow control window
// 4] 5 priority frames for streams which will never be opened with headers
// these streams (3, 5, 7, 9, b) build a dependency tree that all other
// streams will be direct leaves of.
void
Http2Session::SendHello()
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG3(("Http2Session::SendHello %p\n", this));
// sized for magic + 4 settings and a session window update to follow
// 24 magic, 33 for settings (9 header + 4 settings @6), 13 for window update
// sized for magic + 4 settings and a session window update and 5 priority frames
// 24 magic, 33 for settings (9 header + 4 settings @6), 13 for window update,
// 5 priority frames at 14 (9 + 5) each
static const uint32_t maxSettings = 4;
static const uint32_t maxDataLen = 24 + kFrameHeaderBytes + maxSettings * 6 + 13;
static const uint32_t prioritySize = 5 * (kFrameHeaderBytes + 5);
static const uint32_t maxDataLen = 24 + kFrameHeaderBytes + maxSettings * 6 + 13 + prioritySize;
char *packet = EnsureOutputBuffer(maxDataLen);
memcpy(packet, kMagicHello, 24);
mOutputQueueUsed += 24;
@ -855,25 +863,61 @@ Http2Session::SendHello()
// now bump the local session window from 64KB
uint32_t sessionWindowBump = ASpdySession::kInitialRwin - kDefaultRwin;
if (kDefaultRwin >= ASpdySession::kInitialRwin)
goto sendHello_complete;
if (kDefaultRwin < ASpdySession::kInitialRwin) {
// send a window update for the session (Stream 0) for something large
mLocalSessionWindow = ASpdySession::kInitialRwin;
// send a window update for the session (Stream 0) for something large
mLocalSessionWindow = ASpdySession::kInitialRwin;
packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
CreateFrameHeader(packet, 4, FRAME_TYPE_WINDOW_UPDATE, 0, 0);
mOutputQueueUsed += kFrameHeaderBytes + 4;
CopyAsNetwork32(packet + kFrameHeaderBytes, sessionWindowBump);
packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
CreateFrameHeader(packet, 4, FRAME_TYPE_WINDOW_UPDATE, 0, 0);
mOutputQueueUsed += kFrameHeaderBytes + 4;
CopyAsNetwork32(packet + kFrameHeaderBytes, sessionWindowBump);
LOG3(("Session Window increase at start of session %p %u\n",
this, sessionWindowBump));
LogIO(this, nullptr, "Session Window Bump ", packet, kFrameHeaderBytes + 4);
}
LOG3(("Session Window increase at start of session %p %u\n",
this, sessionWindowBump));
LogIO(this, nullptr, "Session Window Bump ", packet, kFrameHeaderBytes + 4);
// draft-14 and draft-15 are the only versions we support that do not
// allow our priority scheme. Blacklist them here - they are aliased
// as draft-15
if ((mVersion != HTTP_VERSION_2_DRAFT_15) &&
gHttpHandler->UseH2Deps() && gHttpHandler->CriticalRequestPrioritization()) {
mUseH2Deps = true;
MOZ_ASSERT(mNextStreamID == kLeaderGroupID);
CreatePriorityNode(kLeaderGroupID, 0, 200, "leader");
mNextStreamID += 2;
MOZ_ASSERT(mNextStreamID == kOtherGroupID);
CreatePriorityNode(kOtherGroupID, 0, 100, "other");
mNextStreamID += 2;
MOZ_ASSERT(mNextStreamID == kBackgroundGroupID);
CreatePriorityNode(kBackgroundGroupID, 0, 0, "background");
mNextStreamID += 2;
MOZ_ASSERT(mNextStreamID == kSpeculativeGroupID);
CreatePriorityNode(kSpeculativeGroupID, kBackgroundGroupID, 0, "speculative");
mNextStreamID += 2;
MOZ_ASSERT(mNextStreamID == kFollowerGroupID);
CreatePriorityNode(kFollowerGroupID, kLeaderGroupID, 0, "follower");
mNextStreamID += 2;
}
sendHello_complete:
FlushOutputQueue();
}
void
Http2Session::CreatePriorityNode(uint32_t streamID, uint32_t dependsOn, uint8_t weight,
const char *label)
{
char *packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
CreateFrameHeader(packet, 5, FRAME_TYPE_PRIORITY, 0, streamID);
mOutputQueueUsed += kFrameHeaderBytes + 5;
CopyAsNetwork32(packet + kFrameHeaderBytes, dependsOn); // depends on
packet[kFrameHeaderBytes + 4] = weight; // weight
LOG3(("Http2Session %p generate Priority Frame 0x%X depends on 0x%X "
"weight %d for %s class\n", this, streamID, dependsOn, weight, label));
LogIO(this, nullptr, "Priority dep node", packet, kFrameHeaderBytes + 5);
}
// perform a bunch of integrity checks on the stream.
// returns true if passed, false (plus LOG and ABORT) if failed.
bool
@ -3322,7 +3366,7 @@ Http2Session::ConfirmTLSProfile()
// Fallback to showing the draft version, just in case
LOG3(("Http2Session::ConfirmTLSProfile %p could not get negotiated token. "
"Falling back to draft token.", this));
mNegotiatedToken.AssignLiteral(NS_HTTP2_DRAFT_TOKEN);
mNegotiatedToken.AssignLiteral(HTTP2_DRAFT_LATEST_TOKEN);
}
mTLSProfileConfirmed = true;

View File

@ -41,7 +41,7 @@ public:
NS_DECL_NSAHTTPSEGMENTREADER
NS_DECL_NSAHTTPSEGMENTWRITER
explicit Http2Session(nsISocketTransport *);
Http2Session(nsISocketTransport *, uint32_t version);
bool AddStream(nsAHttpTransaction *, int32_t,
bool, nsIInterfaceRequestor *);
@ -161,6 +161,14 @@ public:
const static uint8_t kFrameHeaderBytes = kFrameLengthBytes + kFrameFlagBytes +
kFrameTypeBytes + kFrameStreamIDBytes;
enum {
kLeaderGroupID = 0x3,
kOtherGroupID = 0x5,
kBackgroundGroupID = 0x7,
kSpeculativeGroupID = 0x9,
kFollowerGroupID = 0xB
};
static nsresult RecvHeaders(Http2Session *);
static nsresult RecvPriority(Http2Session *);
static nsresult RecvRstStream(Http2Session *);
@ -218,6 +226,8 @@ public:
void SendPing() MOZ_OVERRIDE;
bool UseH2Deps() { return mUseH2Deps; }
private:
// These internal states do not correspond to the states of the HTTP/2 specification
@ -260,6 +270,7 @@ private:
void ActivateStream(Http2Stream *);
void ProcessPending();
nsresult SetInputFrameDataStream(uint32_t);
void CreatePriorityNode(uint32_t, uint32_t, uint8_t, const char *);
bool VerifyStream(Http2Stream *, uint32_t);
void SetNeedsCleanup();
@ -469,6 +480,9 @@ private:
// For caching whether we negotiated "h2" or "h2-<draft>"
nsCString mNegotiatedToken;
bool mUseH2Deps;
uint32_t mVersion; // HTTP2_VERSION_ from nsHttp.h remove when draft support removed
private:
/// connect tunnels
void DispatchOnTunnel(nsAHttpTransaction *, nsIInterfaceRequestor *);

View File

@ -26,6 +26,7 @@
#include "nsHttp.h"
#include "nsHttpHandler.h"
#include "nsHttpRequestHead.h"
#include "nsIClassOfService.h"
#include "nsISocketTransport.h"
#include "nsStandardURL.h"
#include "prnetdb.h"
@ -504,8 +505,11 @@ Http2Stream::ParseHttpRequestHeaders(const char *buf,
mTxInlineFrameUsed, mTxInlineFrameSize);
mTxInlineFrameUsed += messageSize;
LOG3(("%p Generating %d bytes of HEADERS for stream 0x%X with priority weight %u frames %u\n",
this, mTxInlineFrameUsed, mStreamID, mPriorityWeight, numFrames));
UpdatePriorityDependency();
LOG3(("Http2Stream %p Generating %d bytes of HEADERS for stream 0x%X with "
"priority weight %u dep 0x%X frames %u uri=%s\n",
this, mTxInlineFrameUsed, mStreamID, mPriorityWeight,
mPriorityDependency, numFrames, nsCString(head->RequestURI()).get()));
uint32_t outputOffset = 0;
uint32_t compressedDataOffset = 0;
@ -534,9 +538,7 @@ Http2Stream::ParseHttpRequestHeaders(const char *buf,
outputOffset += Http2Session::kFrameHeaderBytes;
if (!idx) {
// Priority - Dependency is 0, weight is our gecko-calculated weight,
// non-exclusive dependency
memset(mTxInlineFrame.get() + outputOffset, 0, 4);
memcpy(mTxInlineFrame.get() + outputOffset, &mPriorityDependency, 4);
memcpy(mTxInlineFrame.get() + outputOffset + 4, &mPriorityWeight, 1);
outputOffset += 5;
}
@ -1063,18 +1065,67 @@ Http2Stream::SetPriority(uint32_t newPriority)
mPriority = static_cast<uint32_t>(httpPriority);
mPriorityWeight = (nsISupportsPriority::PRIORITY_LOWEST + 1) -
(httpPriority - kNormalPriority);
mPriorityDependency = 0; // maybe adjusted later
}
void
Http2Stream::SetPriorityDependency(uint32_t newDependency, uint8_t newWeight,
bool exclusive)
{
// XXX - we ignore this for now... why is the server sending priority frames?!
// undefined what it means when the server sends a priority frame. ignore it.
LOG3(("Http2Stream::SetPriorityDependency %p 0x%X received dependency=0x%X "
"weight=%u exclusive=%d", this, mStreamID, newDependency, newWeight,
exclusive));
}
void
Http2Stream::UpdatePriorityDependency()
{
if (!mSession->UseH2Deps()) {
return;
}
nsHttpTransaction *trans = mTransaction->QueryHttpTransaction();
if (!trans) {
return;
}
// we create 5 fake dependency streams per session,
// these streams are never opened with HEADERS. our first opened stream is 0xd
// 3 depends 0, weight 200, leader class (kLeaderGroupID)
// 5 depends 0, weight 100, other (kOtherGroupID)
// 7 depends 0, weight 0, background (kBackgroundGroupID)
// 9 depends 7, weight 0, speculative (kSpeculativeGroupID)
// b depends 3, weight 0, follower class (kFollowerGroupID)
//
// streams for leaders (html, js, css) depend on 3
// streams for folowers (images) depend on b
// default streams (xhr, async js) depend on 5
// explicit bg streams (beacon, etc..) depend on 7
// spculative bg streams depend on 9
uint32_t classFlags = trans->ClassOfService();
if (classFlags & nsIClassOfService::Leader) {
mPriorityDependency = Http2Session::kLeaderGroupID;
} else if (classFlags & nsIClassOfService::Follower) {
mPriorityDependency = Http2Session::kFollowerGroupID;
} else if (classFlags & nsIClassOfService::Speculative) {
mPriorityDependency = Http2Session::kSpeculativeGroupID;
} else if (classFlags & nsIClassOfService::Background) {
mPriorityDependency = Http2Session::kBackgroundGroupID;
} else if (classFlags & nsIClassOfService::Unblocked) {
mPriorityDependency = Http2Session::kOtherGroupID;
} else {
mPriorityDependency = Http2Session::kFollowerGroupID; // unmarked followers
}
LOG3(("Http2Stream::UpdatePriorityDependency %p "
"classFlags %X depends on stream 0x%X\n",
this, classFlags, mPriorityDependency));
}
void
Http2Stream::SetRecvdFin(bool aStatus)
{

View File

@ -126,6 +126,7 @@ public:
uint32_t Priority() { return mPriority; }
void SetPriority(uint32_t);
void SetPriorityDependency(uint32_t, uint8_t, bool);
void UpdatePriorityDependency();
// A pull stream has an implicit sink, a pushed stream has a sink
// once it is matched to a pull stream.
@ -264,8 +265,9 @@ private:
// close by setting this to the max value.
int64_t mRequestBodyLenRemaining;
uint32_t mPriority;
uint8_t mPriorityWeight;
uint32_t mPriority; // geckoish weight
uint8_t mPriorityWeight; // h2 weight
uint8_t mPriorityDependency; // h2 stream id 3 - 0xb
// mClientReceiveWindow, mServerReceiveWindow, and mLocalUnacked are for flow control.
// *window are signed because the race conditions in asynchronous SETTINGS

View File

@ -47,6 +47,7 @@ HttpBaseChannel::HttpBaseChannel()
, mStatus(NS_OK)
, mLoadFlags(LOAD_NORMAL)
, mCaps(0)
, mClassOfService(0)
, mPriority(PRIORITY_NORMAL)
, mRedirectionLimit(gHttpHandler->RedirectionLimit())
, mApplyConversion(true)
@ -66,8 +67,6 @@ HttpBaseChannel::HttpBaseChannel()
, mTracingEnabled(true)
, mTimingEnabled(false)
, mAllowSpdy(true)
, mLoadAsBlocking(false)
, mLoadUnblocked(false)
, mResponseTimeoutEnabled(true)
, mAllRedirectsSameOrigin(true)
, mAllRedirectsPassTimingAllowCheck(true)
@ -1713,36 +1712,6 @@ HttpBaseChannel::SetAllowSpdy(bool aAllowSpdy)
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetLoadAsBlocking(bool *aLoadAsBlocking)
{
NS_ENSURE_ARG_POINTER(aLoadAsBlocking);
*aLoadAsBlocking = mLoadAsBlocking;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::SetLoadAsBlocking(bool aLoadAsBlocking)
{
mLoadAsBlocking = aLoadAsBlocking;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetLoadUnblocked(bool *aLoadUnblocked)
{
NS_ENSURE_ARG_POINTER(aLoadUnblocked);
*aLoadUnblocked = mLoadUnblocked;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::SetLoadUnblocked(bool aLoadUnblocked)
{
mLoadUnblocked = aLoadUnblocked;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetApiRedirectToURI(nsIURI ** aResult)
{

View File

@ -28,6 +28,7 @@
#include "nsIEffectiveTLDService.h"
#include "nsIStringEnumerator.h"
#include "nsISupportsPriority.h"
#include "nsIClassOfService.h"
#include "nsIApplicationCache.h"
#include "nsIResumableChannel.h"
#include "nsITraceableChannel.h"
@ -65,6 +66,7 @@ class HttpBaseChannel : public nsHashPropertyBag
, public nsIUploadChannel
, public nsIUploadChannel2
, public nsISupportsPriority
, public nsIClassOfService
, public nsIResumableChannel
, public nsITraceableChannel
, public PrivateBrowsingChannel<HttpBaseChannel>
@ -176,10 +178,6 @@ public:
NS_IMETHOD GetRemotePort(int32_t* port);
NS_IMETHOD GetAllowSpdy(bool *aAllowSpdy);
NS_IMETHOD SetAllowSpdy(bool aAllowSpdy);
NS_IMETHOD GetLoadAsBlocking(bool *aLoadAsBlocking);
NS_IMETHOD SetLoadAsBlocking(bool aLoadAsBlocking);
NS_IMETHOD GetLoadUnblocked(bool *aLoadUnblocked);
NS_IMETHOD SetLoadUnblocked(bool aLoadUnblocked);
NS_IMETHOD GetApiRedirectToURI(nsIURI * *aApiRedirectToURI);
NS_IMETHOD AddSecurityMessage(const nsAString &aMessageTag, const nsAString &aMessageCategory);
NS_IMETHOD TakeAllSecurityMessages(nsCOMArray<nsISecurityConsoleMessage> &aMessages);
@ -202,6 +200,9 @@ public:
NS_IMETHOD GetPriority(int32_t *value);
NS_IMETHOD AdjustPriority(int32_t delta);
// nsIClassOfService
NS_IMETHOD GetClassFlags(uint32_t *outFlags) { *outFlags = mClassOfService; return NS_OK; }
// nsIResumableChannel
NS_IMETHOD GetEntityID(nsACString& aEntityID);
@ -334,6 +335,7 @@ protected:
nsresult mStatus;
uint32_t mLoadFlags;
uint32_t mCaps;
uint32_t mClassOfService;
int16_t mPriority;
uint8_t mRedirectionLimit;
@ -356,8 +358,6 @@ protected:
// True if timing collection is enabled
uint32_t mTimingEnabled : 1;
uint32_t mAllowSpdy : 1;
uint32_t mLoadAsBlocking : 1;
uint32_t mLoadUnblocked : 1;
uint32_t mResponseTimeoutEnabled : 1;
// A flag that should be false only if a cross-domain redirect occurred
uint32_t mAllRedirectsSameOrigin : 1;

View File

@ -127,6 +127,7 @@ NS_INTERFACE_MAP_BEGIN(HttpChannelChild)
NS_INTERFACE_MAP_ENTRY(nsICacheInfoChannel)
NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
NS_INTERFACE_MAP_ENTRY(nsIClassOfService)
NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
@ -1541,6 +1542,7 @@ HttpChannelChild::ContinueAsyncOpen()
openArgs.uploadStreamHasHeaders() = mUploadStreamHasHeaders;
openArgs.priority() = mPriority;
openArgs.classOfService() = mClassOfService;
openArgs.redirectionLimit() = mRedirectionLimit;
openArgs.allowPipelining() = mAllowPipelining;
openArgs.allowSTS() = mAllowSTS;
@ -1725,6 +1727,43 @@ HttpChannelChild::SetPriority(int32_t aPriority)
return NS_OK;
}
//-----------------------------------------------------------------------------
// HttpChannelChild::nsIClassOfService
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelChild::SetClassFlags(uint32_t inFlags)
{
if (mClassOfService == inFlags) {
return NS_OK;
}
mClassOfService = inFlags;
if (RemoteChannelExists()) {
SendSetClassOfService(mClassOfService);
}
return NS_OK;
}
NS_IMETHODIMP
HttpChannelChild::AddClassFlags(uint32_t inFlags)
{
mClassOfService |= inFlags;
if (RemoteChannelExists()) {
SendSetClassOfService(mClassOfService);
}
return NS_OK;
}
NS_IMETHODIMP
HttpChannelChild::ClearClassFlags(uint32_t inFlags)
{
mClassOfService &= ~inFlags;
if (RemoteChannelExists()) {
SendSetClassOfService(mClassOfService);
}
return NS_OK;
}
//-----------------------------------------------------------------------------
// HttpChannelChild::nsIProxiedChannel
//-----------------------------------------------------------------------------

View File

@ -87,6 +87,10 @@ public:
NS_IMETHOD GetRemotePort(int32_t* port);
// nsISupportsPriority
NS_IMETHOD SetPriority(int32_t value);
// nsIClassOfService
NS_IMETHOD SetClassFlags(uint32_t inFlags);
NS_IMETHOD AddClassFlags(uint32_t inFlags);
NS_IMETHOD ClearClassFlags(uint32_t inFlags);
// nsIResumableChannel
NS_IMETHOD ResumeAt(uint64_t startPos, const nsACString& entityID);

View File

@ -100,7 +100,7 @@ HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs)
a.referrerPolicy(), a.apiRedirectTo(), a.topWindowURI(),
a.loadFlags(), a.requestHeaders(),
a.requestMethod(), a.uploadStream(),
a.uploadStreamHasHeaders(), a.priority(),
a.uploadStreamHasHeaders(), a.priority(), a.classOfService(),
a.redirectionLimit(), a.allowPipelining(), a.allowSTS(),
a.thirdPartyFlags(), a.resumeAt(), a.startPos(),
a.entityID(), a.chooseApplicationCache(),
@ -181,6 +181,7 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
const OptionalInputStreamParams& uploadStream,
const bool& uploadStreamHasHeaders,
const uint16_t& priority,
const uint32_t& classOfService,
const uint8_t& redirectionLimit,
const bool& allowPipelining,
const bool& allowSTS,
@ -315,8 +316,12 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
mChannel->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
}
if (priority != nsISupportsPriority::PRIORITY_NORMAL)
if (priority != nsISupportsPriority::PRIORITY_NORMAL) {
mChannel->SetPriority(priority);
}
if (classOfService) {
mChannel->SetClassFlags(classOfService);
}
mChannel->SetRedirectionLimit(redirectionLimit);
mChannel->SetAllowPipelining(allowPipelining);
mChannel->SetAllowSTS(allowSTS);
@ -426,6 +431,15 @@ HttpChannelParent::RecvSetPriority(const uint16_t& priority)
return true;
}
bool
HttpChannelParent::RecvSetClassOfService(const uint32_t& cos)
{
if (mChannel) {
mChannel->SetClassFlags(cos);
}
return true;
}
bool
HttpChannelParent::RecvSuspend()
{

View File

@ -99,6 +99,7 @@ protected:
const OptionalInputStreamParams& uploadStream,
const bool& uploadStreamHasHeaders,
const uint16_t& priority,
const uint32_t& classOfService,
const uint8_t& redirectionLimit,
const bool& allowPipelining,
const bool& allowSTS,
@ -116,6 +117,7 @@ protected:
const uint32_t& aContentPolicyType);
virtual bool RecvSetPriority(const uint16_t& priority) MOZ_OVERRIDE;
virtual bool RecvSetClassOfService(const uint32_t& cos) MOZ_OVERRIDE;
virtual bool RecvSetCacheTokenCachedCharset(const nsCString& charset) MOZ_OVERRIDE;
virtual bool RecvSuspend() MOZ_OVERRIDE;
virtual bool RecvResume() MOZ_OVERRIDE;

View File

@ -33,6 +33,7 @@ parent:
// see PNecko.ipdl
SetPriority(uint16_t priority);
SetClassOfService(uint32_t cos);
SetCacheTokenCachedCharset(nsCString charset);

View File

@ -39,15 +39,16 @@ namespace net {
// 27 was http/2-draft09, h2-10, and h2-11
// 28 was http/2-draft12
// 29 was http/2-draft13
// 30 was also h2-14 and -15. They're effectively the same, -15 added an
// 30 was also h2-14. They're effectively the same, -15 added an
// error code. So, we advertise all, but our "default position" is -16.
HTTP2_VERSION_DRAFT16 = 30
HTTP_VERSION_2_DRAFT_15 = 30,
HTTP_VERSION_2_DRAFT_16 = 31
};
typedef uint8_t nsHttpVersion;
#define NS_HTTP2_DRAFT_VERSION HTTP2_VERSION_DRAFT16
#define NS_HTTP2_DRAFT_TOKEN "h2-16"
#define HTTP_VERSION_2_DRAFT_LATEST HTTP_VERSION_2_DRAFT_16
#define HTTP2_DRAFT_LATEST_TOKEN "h2-16"
//-----------------------------------------------------------------------------
// http connection capabilities

View File

@ -43,6 +43,7 @@
#include "nsISSLSocketControl.h"
#include "sslt.h"
#include "nsContentUtils.h"
#include "nsIClassOfService.h"
#include "nsIPermissionManager.h"
#include "nsIPrincipal.h"
#include "nsIScriptSecurityManager.h"
@ -835,6 +836,7 @@ nsHttpChannel::SetupTransaction()
return rv;
}
mTransaction->SetClassOfService(mClassOfService);
SetupTransactionLoadGroupInfo();
rv = nsInputStreamPump::Create(getter_AddRefs(mTransactionPump),
@ -2784,10 +2786,8 @@ nsHttpChannel::OpenCacheEntry(bool isHttps)
}
NS_ENSURE_SUCCESS(rv, rv);
// Don't consider mLoadUnblocked here, since it's not indication of a demand
// to load prioritly. It's mostly used to load XHR requests, but those should
// not be considered as influencing the page load performance.
if (mLoadAsBlocking || (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI))
if ((mClassOfService & nsIClassOfService::Leader) ||
(mLoadFlags & LOAD_INITIAL_DOCUMENT_URI))
cacheEntryOpenFlags |= nsICacheStorage::OPEN_PRIORITY;
// Only for backward compatibility with the old cache back end.
@ -4594,6 +4594,7 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
NS_INTERFACE_MAP_ENTRY(nsICacheInfoChannel)
NS_INTERFACE_MAP_ENTRY(nsICachingChannel)
NS_INTERFACE_MAP_ENTRY(nsIClassOfService)
NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
NS_INTERFACE_MAP_ENTRY(nsICacheEntryOpenCallback)
@ -4912,10 +4913,12 @@ nsHttpChannel::BeginConnect()
mCaps &= ~(NS_HTTP_ALLOW_KEEPALIVE | NS_HTTP_ALLOW_PIPELINING);
if (gHttpHandler->CriticalRequestPrioritization()) {
if (mLoadAsBlocking)
if (mClassOfService & nsIClassOfService::Leader) {
mCaps |= NS_HTTP_LOAD_AS_BLOCKING;
if (mLoadUnblocked)
}
if (mClassOfService & nsIClassOfService::Unblocked) {
mCaps |= NS_HTTP_LOAD_UNBLOCKED;
}
}
// Force-Reload should reset the persistent connection pool for this host
@ -4983,6 +4986,30 @@ nsHttpChannel::SetPriority(int32_t value)
return NS_OK;
}
//-----------------------------------------------------------------------------
// HttpChannel::nsIClassOfService
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsHttpChannel::SetClassFlags(uint32_t inFlags)
{
mClassOfService = inFlags;
return NS_OK;
}
NS_IMETHODIMP
nsHttpChannel::AddClassFlags(uint32_t inFlags)
{
mClassOfService |= inFlags;
return NS_OK;
}
NS_IMETHODIMP
nsHttpChannel::ClearClassFlags(uint32_t inFlags)
{
mClassOfService &= ~inFlags;
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsHttpChannel::nsIProtocolProxyCallback
//-----------------------------------------------------------------------------

View File

@ -121,6 +121,11 @@ public:
NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey);
// nsISupportsPriority
NS_IMETHOD SetPriority(int32_t value);
// nsIClassOfService
NS_IMETHOD SetClassFlags(uint32_t inFlags);
NS_IMETHOD AddClassFlags(uint32_t inFlags);
NS_IMETHOD ClearClassFlags(uint32_t inFlags);
// nsIResumableChannel
NS_IMETHOD ResumeAt(uint64_t startPos, const nsACString& entityID);

View File

@ -1753,8 +1753,7 @@ nsHttpConnectionMgr::TryDispatchTransaction(nsConnectionEntry *ent,
}
}
}
}
else {
} else {
// Mark the transaction and its load group as blocking right now to prevent
// other transactions from being reordered in the queue due to slow syns.
trans->DispatchedAsBlocking();

View File

@ -182,6 +182,7 @@ nsHttpHandler::nsHttpHandler()
, mSpdyV31(true)
, mHttp2DraftEnabled(true)
, mHttp2Enabled(true)
, mUseH2Deps(true)
, mEnforceHttp2TlsProfile(true)
, mCoalesceSpdy(true)
, mSpdyPersistentSettings(false)
@ -1194,6 +1195,12 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
mHttp2Enabled = cVar;
}
if (PREF_CHANGED(HTTP_PREF("spdy.enabled.deps"))) {
rv = prefs->GetBoolPref(HTTP_PREF("spdy.enabled.deps"), &cVar);
if (NS_SUCCEEDED(rv))
mUseH2Deps = cVar;
}
if (PREF_CHANGED(HTTP_PREF("spdy.enforce-tls-profile"))) {
rv = prefs->GetBoolPref(HTTP_PREF("spdy.enforce-tls-profile"), &cVar);
if (NS_SUCCEEDED(rv))

View File

@ -113,6 +113,7 @@ public:
uint32_t ConnectTimeout() { return mConnectTimeout; }
uint32_t ParallelSpeculativeConnectLimit() { return mParallelSpeculativeConnectLimit; }
bool CriticalRequestPrioritization() { return mCriticalRequestPrioritization; }
bool UseH2Deps() { return mUseH2Deps; }
uint32_t MaxConnectionsPerOrigin() { return mMaxPersistentConnectionsPerServer; }
bool UseRequestTokenBucket() { return mRequestTokenBucketEnabled; }
@ -470,6 +471,7 @@ private:
uint32_t mSpdyV31 : 1;
uint32_t mHttp2DraftEnabled : 1;
uint32_t mHttp2Enabled : 1;
uint32_t mUseH2Deps : 1;
uint32_t mEnforceHttp2TlsProfile : 1;
uint32_t mCoalesceSpdy : 1;
uint32_t mSpdyPersistentSettings : 1;

View File

@ -136,6 +136,7 @@ nsHttpTransaction::nsHttpTransaction()
, mCountRecv(0)
, mCountSent(0)
, mAppId(NECKO_NO_APP_ID)
, mClassOfService(0)
{
LOG(("Creating nsHttpTransaction @%p\n", this));
gHttpHandler->GetMaxPipelineObjectSize(&mMaxPipelineObjectSize);
@ -1749,7 +1750,7 @@ nsHttpTransaction::CancelPipeline(uint32_t reason)
}
// Called when the transaction marked for blocking is associated with a connection
// (i.e. added to a spdy session, an idle http connection, or placed into
// (i.e. added to a new h1 conn, an idle http connection, or placed into
// a http pipeline). It is safe to call this multiple times with it only
// having an effect once.
void

View File

@ -405,6 +405,11 @@ private:
mCountSent += sentBytes;
SaveNetworkStats(false);
}
public:
void SetClassOfService(uint32_t cos) { mClassOfService = cos; }
uint32_t ClassOfService() { return mClassOfService; }
private:
uint32_t mClassOfService;
};
}} // namespace mozilla::net

View File

@ -38,7 +38,7 @@ interface nsIHttpUpgradeListener : nsISupports
* using any feature exposed by this interface, be aware that this interface
* will change and you will be broken. You have been warned.
*/
[scriptable, uuid(62a8d6e2-3418-4c6f-9d90-88573838f6dd)]
[scriptable, uuid(bbf9d5bb-8daf-4909-88bc-f3b2f6a886d0)]
interface nsIHttpChannelInternal : nsISupports
{
/**
@ -194,22 +194,6 @@ interface nsIHttpChannelInternal : nsISupports
*/
attribute boolean allowSpdy;
/**
* Set (e.g., by the docshell) to indicate whether or not the channel
* corresponds to content that should be given a degree of network exclusivity
* with respect to other members of its load group.
* Examples are js from the HTML head and css which are latency
* sensitive and should not compete with images for bandwidth. Default false.
*/
attribute boolean loadAsBlocking;
/**
* If set, this channel will load in parallel with the rest of the load
* group even if a blocking subset of the group would normally be given
* exclusivity. Default false.
*/
attribute boolean loadUnblocked;
/**
* This attribute en/disables the timeout for the first byte of an HTTP
* response. Enabled by default.

View File

@ -19,6 +19,7 @@
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "nsICancelable.h"
#include "nsIClassOfService.h"
#include "nsIDNSRecord.h"
#include "nsIDNSService.h"
#include "nsIStreamConverterService.h"
@ -2293,8 +2294,10 @@ WebSocketChannel::SetupRequest()
// we never let websockets be blocked by head CSS/JS loads to avoid
// potential deadlock where server generation of CSS/JS requires
// an XHR signal.
rv = mChannel->SetLoadUnblocked(true);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(mChannel));
if (cos) {
cos->AddClassFlags(nsIClassOfService::Unblocked);
}
// draft-ietf-hybi-thewebsocketprotocol-07 illustrates Upgrade: websocket
// in lower case, so go with that. It is technically case insensitive.

View File

@ -203,6 +203,14 @@ function test_http2_basic() {
chan.asyncOpen(listener, null);
}
function test_http2_basic_unblocked_dep() {
var chan = makeChan("https://localhost:6944/basic_unblocked_dep");
var cos = chan.QueryInterface(Ci.nsIClassOfService);
cos.addClassFlags(Ci.nsIClassOfService.Unblocked);
var listener = new Http2CheckListener();
chan.asyncOpen(listener, null);
}
// make sure we don't use h2 when disallowed
function test_http2_nospdy() {
var chan = makeChan("https://localhost:6944/");
@ -521,6 +529,7 @@ function test_complete() {
// a stalled stream when a SETTINGS frame arrives
var tests = [ test_http2_post_big
, test_http2_basic
, test_http2_basic_unblocked_dep
, test_http2_nospdy
, test_http2_push1
, test_http2_push2

View File

@ -1021,6 +1021,7 @@ public final class AttributeName
public static final AttributeName ONDRAGEND = new AttributeName(ALL_NO_NS, SAME_LOCAL("ondragend"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
public static final AttributeName ONMOVEEND = new AttributeName(ALL_NO_NS, SAME_LOCAL("onmoveend"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
public static final AttributeName ONINVALID = new AttributeName(ALL_NO_NS, SAME_LOCAL("oninvalid"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
public static final AttributeName INTEGRITY = new AttributeName(ALL_NO_NS, SAME_LOCAL("integrity"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
public static final AttributeName ONKEYDOWN = new AttributeName(ALL_NO_NS, SAME_LOCAL("onkeydown"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
public static final AttributeName ONFOCUSIN = new AttributeName(ALL_NO_NS, SAME_LOCAL("onfocusin"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
public static final AttributeName ONMOUSEUP = new AttributeName(ALL_NO_NS, SAME_LOCAL("onmouseup"), ALL_NO_PREFIX, NCNAME_HTML | NCNAME_FOREIGN | NCNAME_LANG);
@ -1602,6 +1603,7 @@ public final class AttributeName
ONDRAGEND,
ONMOVEEND,
ONINVALID,
INTEGRITY,
ONKEYDOWN,
ONFOCUSIN,
ONMOUSEUP,
@ -2184,6 +2186,7 @@ public final class AttributeName
313706996,
313707317,
313710350,
313795700,
314027746,
314038181,
314091299,

View File

@ -381,6 +381,7 @@ HTML5_ATOM(intercept, "intercept")
HTML5_ATOM(ondragend, "ondragend")
HTML5_ATOM(onmoveend, "onmoveend")
HTML5_ATOM(oninvalid, "oninvalid")
HTML5_ATOM(integrity, "integrity")
HTML5_ATOM(onkeydown, "onkeydown")
HTML5_ATOM(onfocusin, "onfocusin")
HTML5_ATOM(onmouseup, "onmouseup")

File diff suppressed because one or more lines are too long

View File

@ -396,6 +396,7 @@ class nsHtml5AttributeName
static nsHtml5AttributeName* ATTR_ONDRAGEND;
static nsHtml5AttributeName* ATTR_ONMOVEEND;
static nsHtml5AttributeName* ATTR_ONINVALID;
static nsHtml5AttributeName* ATTR_INTEGRITY;
static nsHtml5AttributeName* ATTR_ONKEYDOWN;
static nsHtml5AttributeName* ATTR_ONFOCUSIN;
static nsHtml5AttributeName* ATTR_ONMOUSEUP;

View File

@ -3212,15 +3212,11 @@ nsHtml5TreeBuilder::documentModeInternal(nsHtml5DocumentMode m, nsString* public
{
if (isSrcdocDocument) {
quirks = false;
if (this) {
this->documentMode(STANDARDS_MODE);
}
this->documentMode(STANDARDS_MODE);
return;
}
quirks = (m == QUIRKS_MODE);
if (this) {
this->documentMode(m);
}
this->documentMode(m);
}
bool

View File

@ -338,9 +338,10 @@ function AbstractHealthReporter(branch, policy, sessionRecorder) {
this._initHistogram = hasFirstRun ? TELEMETRY_INIT : TELEMETRY_INIT_FIRSTRUN;
this._dbOpenHistogram = hasFirstRun ? TELEMETRY_DB_OPEN : TELEMETRY_DB_OPEN_FIRSTRUN;
// This is set to the name of the provider that we are currently shutting down, if any.
// It is used for AsyncShutdownTimeout diagnostics.
// This is set to the name for the provider that we are currently initializing
// or shutting down, if any. This is used for AsyncShutdownTimeout diagnostics.
this._currentProviderInShutdown = null;
this._currentProviderInInit = null;
}
AbstractHealthReporter.prototype = Object.freeze({
@ -413,6 +414,7 @@ AbstractHealthReporter.prototype = Object.freeze({
hasStorage: !!this._storage,
shutdownComplete: this._shutdownComplete,
currentProviderInShutdown: this._currentProviderInShutdown,
currentProviderInInit: this._currentProviderInInit,
}));
try {
@ -500,8 +502,10 @@ AbstractHealthReporter.prototype = Object.freeze({
let catString = this._prefs.get("service.providerCategories") || "";
if (catString.length) {
for (let category of catString.split(",")) {
yield this._providerManager.registerProvidersFromCategoryManager(category);
yield this._providerManager.registerProvidersFromCategoryManager(category,
providerName => this._currentProviderInInit = providerName);
}
this._currentProviderInInit = null;
}
}),

View File

@ -101,14 +101,16 @@ this.ProviderManager.prototype = Object.freeze({
*
* @param category
* (string) Name of category from which to query and load.
* @param providerDiagnostic
* (function) Optional, called with the name of the provider currently being initialized.
* @return a newly spawned Task.
*/
registerProvidersFromCategoryManager: function (category) {
registerProvidersFromCategoryManager: function (category, providerDiagnostic) {
this._log.info("Registering providers from category: " + category);
let cm = Cc["@mozilla.org/categorymanager;1"]
.getService(Ci.nsICategoryManager);
let promises = [];
let promiseList = [];
let enumerator = cm.enumerateCategory(category);
while (enumerator.hasMoreElements()) {
let entry = enumerator.getNext()
@ -125,7 +127,7 @@ this.ProviderManager.prototype = Object.freeze({
let promise = this.registerProviderFromType(ns[entry]);
if (promise) {
promises.push(promise);
promiseList.push({name: entry, promise: promise});
}
} catch (ex) {
this._recordProviderError(entry,
@ -135,9 +137,12 @@ this.ProviderManager.prototype = Object.freeze({
}
}
return Task.spawn(function wait() {
for (let promise of promises) {
yield promise;
return Task.spawn(function* wait() {
for (let entry of promiseList) {
if (providerDiagnostic) {
providerDiagnostic(entry.name);
}
yield entry.promise;
}
});
},

View File

@ -52,6 +52,15 @@ class GeckoInstance(object):
profile_args["preferences"]["marionette.defaultPrefs.port"] = self.marionette_port
if self.prefs:
profile_args["preferences"].update(self.prefs)
if '-jsdebugger' in self.app_args:
profile_args["preferences"].update({
"devtools.browsertoolbox.panel": "jsdebugger",
"devtools.debugger.remote-enabled": True,
"devtools.debugger.chrome-enabled": True,
"devtools.chrome.enabled": True,
"devtools.debugger.prompt-connection": False,
"marionette.debugging.clicktostart": True,
})
if hasattr(self, "profile_path") and self.profile is None:
if not self.profile_path:

View File

@ -390,7 +390,11 @@ class BaseMarionetteOptions(OptionParser):
action='store',
default='Marionette-based Tests',
help='Define the name to associate with the logger used')
self.add_option('--jsdebugger',
dest='jsdebugger',
action='store_true',
default=False,
help='Enable the jsdebugger for marionette javascript.')
def parse_args(self, args=None, values=None):
options, tests = OptionParser.parse_args(self, args, values)
@ -440,6 +444,9 @@ class BaseMarionetteOptions(OptionParser):
if not 1 <= options.this_chunk <= options.total_chunks:
self.error('Chunk to run must be between 1 and %s.' % options.total_chunks)
if options.jsdebugger:
options.app_args.append('-jsdebugger')
for handler in self.verify_usage_handlers:
handler(options, tests)

View File

@ -130,6 +130,8 @@ class MachCommands(MachCommandBase):
help='Path to gecko profile to use.')
@CommandArgument('--gecko-log',
help='Path to gecko log file, or "-" for stdout.')
@CommandArgument('--jsdebugger', action='store_true',
help='Enable the jsdebugger for marionette javascript.')
@CommandArgument('tests', nargs='*', metavar='TESTS',
help='Path to test(s) to run.')
def run_marionette_test(self, tests, **kwargs):

View File

@ -611,7 +611,24 @@ MarionetteServerConnection.prototype = {
win.addEventListener("load", listener, true);
}
else {
this.startBrowser(win, true);
let clickToStart;
try {
clickToStart = Services.prefs.getBoolPref('marionette.debugging.clicktostart');
Services.prefs.setBoolPref('marionette.debugging.clicktostart', false);
} catch (e) { }
if (clickToStart && (appName != "B2G")) {
let nbox = win.gBrowser.getNotificationBox();
let message = "Starting marionette tests with chrome debugging enabled...";
let buttons = [{
label: "Start execution of marionette tests",
accessKey: 'S',
callback: () => this.startBrowser(win, true)
}];
nbox.appendNotification(message, null, null,
nbox.PRIORITY_WARNING_MEDIUM, buttons);
} else {
this.startBrowser(win, true);
}
}
}

View File

@ -809,7 +809,7 @@ class B2GOptions(MochitestOptions):
defaults["testPath"] = ""
defaults["extensionsToExclude"] = ["specialpowers"]
# See dependencies of bug 1038943.
defaults["defaultLeakThreshold"] = 5180
defaults["defaultLeakThreshold"] = 5308
self.set_defaults(**defaults)
def verifyRemoteOptions(self, options):

View File

@ -443,6 +443,8 @@ Stream.prototype._transition = function transition(sending, frame) {
this._initiated = sending;
} else if (sending && RST_STREAM) {
this._setState('CLOSED');
} else if (PRIORITY) {
/* No state change */
} else {
connectionError = 'PROTOCOL_ERROR';
}

View File

@ -7,6 +7,8 @@
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/layers/CompositorParent.h"
#include "gfxPrefs.h"
#include "gfxPlatform.h"
#include "VsyncSource.h"
#ifdef MOZ_ENABLE_PROFILER_SPS
#include "GeckoProfiler.h"
@ -21,97 +23,51 @@ using namespace mozilla::layers;
namespace mozilla {
StaticRefPtr<VsyncDispatcher> sVsyncDispatcher;
/*static*/ VsyncDispatcher*
VsyncDispatcher::GetInstance()
{
if (!sVsyncDispatcher) {
sVsyncDispatcher = new VsyncDispatcher();
ClearOnShutdown(&sVsyncDispatcher);
}
return sVsyncDispatcher;
}
VsyncDispatcher::VsyncDispatcher()
: mCompositorObserverLock("CompositorObserverLock")
{
MOZ_ASSERT(XRE_IsParentProcess());
gfxPlatform::GetPlatform()->GetHardwareVsync()->AddVsyncDispatcher(this);
}
VsyncDispatcher::~VsyncDispatcher()
{
MutexAutoLock lock(mCompositorObserverLock);
mCompositorObservers.Clear();
}
void
VsyncDispatcher::SetVsyncSource(VsyncSource* aVsyncSource)
{
mVsyncSource = aVsyncSource;
}
void
VsyncDispatcher::DispatchTouchEvents(bool aNotifiedCompositors, TimeStamp aVsyncTime)
{
// Touch events can sometimes start a composite, so make sure we dispatch touches
// even if we don't composite
#ifdef MOZ_WIDGET_GONK
if (!aNotifiedCompositors && gfxPrefs::TouchResampling()) {
GeckoTouchDispatcher::NotifyVsync(aVsyncTime);
}
#endif
// We auto remove this vsync dispatcher from the vsync source in the nsBaseWidget
MOZ_ASSERT(NS_IsMainThread());
}
void
VsyncDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
{
bool notifiedCompositors = false;
// In hardware vsync thread
#ifdef MOZ_ENABLE_PROFILER_SPS
if (profiler_is_active()) {
CompositorParent::PostInsertVsyncProfilerMarker(aVsyncTimestamp);
}
#endif
if (gfxPrefs::VsyncAlignedCompositor()) {
MutexAutoLock lock(mCompositorObserverLock);
notifiedCompositors = NotifyVsyncObservers(aVsyncTimestamp, mCompositorObservers);
MutexAutoLock lock(mCompositorObserverLock);
if (gfxPrefs::VsyncAlignedCompositor() && mCompositorVsyncObserver) {
mCompositorVsyncObserver->NotifyVsync(aVsyncTimestamp);
}
DispatchTouchEvents(notifiedCompositors, aVsyncTimestamp);
}
bool
VsyncDispatcher::NotifyVsyncObservers(TimeStamp aVsyncTimestamp, nsTArray<nsRefPtr<VsyncObserver>>& aObservers)
{
// Callers should lock the respective lock for the aObservers before calling this function
for (size_t i = 0; i < aObservers.Length(); i++) {
aObservers[i]->NotifyVsync(aVsyncTimestamp);
}
return !aObservers.IsEmpty();
}
void
VsyncDispatcher::AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
VsyncDispatcher::SetCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
MutexAutoLock lock(mCompositorObserverLock);
if (!mCompositorObservers.Contains(aVsyncObserver)) {
mCompositorObservers.AppendElement(aVsyncObserver);
}
mCompositorVsyncObserver = aVsyncObserver;
}
void
VsyncDispatcher::RemoveCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
VsyncDispatcher::Shutdown()
{
MOZ_ASSERT(CompositorParent::IsInCompositorThread() || NS_IsMainThread());
MutexAutoLock lock(mCompositorObserverLock);
if (mCompositorObservers.Contains(aVsyncObserver)) {
mCompositorObservers.RemoveElement(aVsyncObserver);
} else {
NS_WARNING("Could not delete a compositor vsync observer\n");
}
// Need to explicitly remove VsyncDispatcher when the nsBaseWidget shuts down.
// Otherwise, we would get dead vsync notifications between when the nsBaseWidget
// shuts down and the CompositorParent shuts down.
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
gfxPlatform::GetPlatform()->GetHardwareVsync()->RemoveVsyncDispatcher(this);
}
} // namespace mozilla

View File

@ -12,8 +12,6 @@
#include "nsTArray.h"
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
class MessageLoop;
namespace mozilla {
class TimeStamp;
@ -21,23 +19,10 @@ namespace layers {
class CompositorVsyncObserver;
}
// Controls how and when to enable/disable vsync.
class VsyncSource
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncSource)
virtual void EnableVsync() = 0;
virtual void DisableVsync() = 0;
virtual bool IsVsyncEnabled() = 0;
protected:
virtual ~VsyncSource() {}
}; // VsyncSource
class VsyncObserver
{
// Must be destroyed on main thread since the compositor is as well
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(VsyncObserver)
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncObserver)
public:
// The method called when a vsync occurs. Return true if some work was done.
@ -55,7 +40,8 @@ class VsyncDispatcher
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncDispatcher)
public:
static VsyncDispatcher* GetInstance();
VsyncDispatcher();
// Called on the vsync thread when a hardware vsync occurs
// The aVsyncTimestamp can mean different things depending on the platform:
// b2g - The vsync timestamp of the previous frame that was just displayed
@ -63,24 +49,15 @@ public:
// TODO: Windows / Linux. DOCUMENT THIS WHEN IMPLEMENTING ON THOSE PLATFORMS
// Android: TODO
void NotifyVsync(TimeStamp aVsyncTimestamp);
void SetVsyncSource(VsyncSource* aVsyncSource);
// Compositor vsync observers must be added/removed on the compositor thread
void AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
void RemoveCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
void SetCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
void Shutdown();
private:
VsyncDispatcher();
virtual ~VsyncDispatcher();
void DispatchTouchEvents(bool aNotifiedCompositors, TimeStamp aVsyncTime);
// Called on the vsync thread. Returns true if observers were notified
bool NotifyVsyncObservers(TimeStamp aVsyncTimestamp, nsTArray<nsRefPtr<VsyncObserver>>& aObservers);
// Can have multiple compositors. On desktop, this is 1 compositor per window
Mutex mCompositorObserverLock;
nsTArray<nsRefPtr<VsyncObserver>> mCompositorObservers;
nsRefPtr<VsyncSource> mVsyncSource;
nsRefPtr<VsyncObserver> mCompositorVsyncObserver;
}; // VsyncDispatcher
} // namespace mozilla

View File

@ -29,6 +29,7 @@
#include "mozilla/TimeStamp.h"
#include "mozilla/TouchEvents.h"
#include "mozilla/dom/Touch.h"
#include "mozilla/layers/CompositorParent.h"
#include "nsAppShell.h"
#include "nsDebug.h"
#include "nsThreadUtils.h"
@ -115,11 +116,23 @@ private:
MultiTouchInput mTouch;
};
/* static */ void
GeckoTouchDispatcher::SetCompositorVsyncObserver(mozilla::layers::CompositorVsyncObserver *aObserver)
{
MOZ_ASSERT(sTouchDispatcher != nullptr);
MOZ_ASSERT(NS_IsMainThread());
// We assume on b2g that there is only 1 CompositorParent
MOZ_ASSERT(sTouchDispatcher->mCompositorVsyncObserver == nullptr);
if (gfxPrefs::TouchResampling()) {
sTouchDispatcher->mCompositorVsyncObserver = aObserver;
}
}
// Timestamp is in nanoseconds
/* static */ bool
GeckoTouchDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
{
if (sTouchDispatcher == nullptr) {
if ((sTouchDispatcher == nullptr) || !gfxPrefs::TouchResampling()) {
return false;
}
@ -141,6 +154,10 @@ GeckoTouchDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
void
GeckoTouchDispatcher::NotifyTouch(MultiTouchInput& aTouch, TimeStamp aEventTime)
{
if (aTouch.mType == MultiTouchInput::MULTITOUCH_START && mCompositorVsyncObserver) {
mCompositorVsyncObserver->SetNeedsComposite(true);
}
if (aTouch.mType == MultiTouchInput::MULTITOUCH_MOVE) {
MutexAutoLock lock(mTouchQueueLock);
if (mResamplingEnabled) {

View File

@ -22,12 +22,17 @@
#include "Units.h"
#include "mozilla/Mutex.h"
#include <vector>
#include "nsRefPtr.h"
class nsIWidget;
namespace mozilla {
class WidgetMouseEvent;
namespace layers {
class CompositorVsyncObserver;
}
// Used to resample touch events whenever a vsync event occurs. It batches
// touch moves and on every vsync, resamples the touch position to create smooth
// scrolls. We use the Android touch resample algorithm. It uses a combination of
@ -48,6 +53,7 @@ public:
void DispatchTouchEvent(MultiTouchInput& aMultiTouch);
void DispatchTouchMoveEvents(TimeStamp aVsyncTime);
static bool NotifyVsync(TimeStamp aVsyncTimestamp);
static void SetCompositorVsyncObserver(layers::CompositorVsyncObserver* aObserver);
private:
void ResampleTouchMoves(MultiTouchInput& aOutTouch, TimeStamp vsyncTime);
@ -78,6 +84,8 @@ private:
// How far ahead can vsync events get ahead of touch events.
TimeDuration mOldTouchThreshold;
nsRefPtr<layers::CompositorVsyncObserver> mCompositorVsyncObserver;
};
} // namespace mozilla

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