Merge b-i to m-c.

This commit is contained in:
Ryan VanderMeulen 2013-11-22 15:35:31 -05:00
commit d7e49cc136
40 changed files with 788 additions and 368 deletions

View File

@ -821,8 +821,10 @@ pref("devtools.debugger.unix-domain-socket", "/data/local/debugger-socket");
// enable Skia/GL (OpenGL-accelerated 2D drawing) for large enough 2d canvases,
// falling back to Skia/software for smaller canvases
#ifdef MOZ_WIDGET_GONK
pref("gfx.canvas.azure.backends", "skia");
pref("gfx.canvas.azure.accelerated", true);
#endif
// Turn on dynamic cache size for Skia
pref("gfx.canvas.skiagl.dynamic-cache", true);

View File

@ -1,4 +1,4 @@
{
"revision": "514b47fbaae1c65d566c557a4c2c99d40de4cf3e",
"revision": "5cc15d1e291050f4e46c91b87a1af1353d1c5e46",
"repo_path": "/integration/gaia-central"
}

View File

@ -1895,6 +1895,12 @@ public:
*/
static bool IsUserFocusIgnored(nsINode* aNode);
/**
* Returns if aContent has the 'scrollgrab' property.
* aContent may be null (in this case false is returned).
*/
static bool HasScrollgrab(nsIContent* aContent);
/**
* Flushes the layout tree (recursively)
*

View File

@ -5919,6 +5919,13 @@ nsContentUtils::IsUserFocusIgnored(nsINode* aNode)
return false;
}
bool
nsContentUtils::HasScrollgrab(nsIContent* aContent)
{
nsGenericHTMLElement* element = nsGenericHTMLElement::FromContentOrNull(aContent);
return element && element->Scrollgrab();
}
void
nsContentUtils::FlushLayoutForTree(nsIDOMWindow* aWindow)
{

View File

@ -20,7 +20,14 @@ function IsD2DEnabled() {
}
function IsLinux() {
return navigator.platform.indexOf("Linux") == 0 &&
var os = "";
try {
os = Cc["@mozilla.org/xre/app-info;1"]
.getService(SpecialPowers.Ci.nsIXULRuntime).OS;
} catch (e) {}
return os.indexOf("Linux") == 0 &&
navigator.appVersion.indexOf("Android") == -1;
}

View File

@ -48,6 +48,7 @@
#include "nsError.h"
#include "nsScriptLoader.h"
#include "nsRuleData.h"
#include "nsIPrincipal.h"
#include "nsPresState.h"
#include "nsILayoutHistoryState.h"
@ -1815,6 +1816,15 @@ nsGenericHTMLElement::GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsIURI** aU
return true;
}
/* static */ bool
nsGenericHTMLElement::IsScrollGrabAllowed(JSContext*, JSObject*)
{
// Only allow scroll grabbing in chrome and certified apps.
nsIPrincipal* prin = nsContentUtils::GetSubjectPrincipal();
return nsContentUtils::IsSystemPrincipal(prin) ||
prin->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED;
}
nsresult
nsGenericHTMLElement::GetURIListAttr(nsIAtom* aAttr, nsAString& aResult)
{

View File

@ -57,7 +57,8 @@ class nsGenericHTMLElement : public nsGenericHTMLElementBase,
{
public:
nsGenericHTMLElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsGenericHTMLElementBase(aNodeInfo)
: nsGenericHTMLElementBase(aNodeInfo),
mScrollgrab(false)
{
NS_ASSERTION(mNodeInfo->NamespaceID() == kNameSpaceID_XHTML,
"Unexpected namespace");
@ -226,6 +227,14 @@ public:
: NS_LITERAL_STRING("false"),
aError);
}
bool Scrollgrab() const
{
return mScrollgrab;
}
void SetScrollgrab(bool aValue)
{
mScrollgrab = aValue;
}
/**
* Determine whether an attribute is an event (onclick, etc.)
@ -930,6 +939,9 @@ public:
tag == nsGkAtoms::object;
}
static bool
IsScrollGrabAllowed(JSContext*, JSObject*);
protected:
/**
* Add/remove this element to the documents name cache
@ -1226,6 +1238,8 @@ protected:
private:
void ChangeEditableState(int32_t aChange);
bool mScrollgrab;
};
namespace mozilla {

View File

@ -962,24 +962,24 @@ this.DOMApplicationRegistry = {
mm: aMm,
refCount: 1
});
}
// If it wasn't registered before, let's update its state
if ((aMsgName === 'Webapps:FireEvent') ||
(aMsgName === 'Webapps:UpdateState')) {
if (man) {
let app = this.getAppByManifestURL(aApp.manifestURL);
if (app && ((aApp.installState !== app.installState) ||
(aApp.downloading !== app.downloading))) {
debug("Got a registration from an outdated app: " +
aApp.manifestURL);
let aEvent ={
type: app.installState,
app: app,
manifestURL: app.manifestURL,
manifest: app.manifest
};
aMm.sendAsyncMessage(aMsgName, aEvent);
}
// If the state reported by the registration is outdated, update it now.
if ((aMsgName === 'Webapps:FireEvent') ||
(aMsgName === 'Webapps:UpdateState')) {
if (man) {
let app = this.getAppByManifestURL(aApp.manifestURL);
if (app && ((aApp.installState !== app.installState) ||
(aApp.downloading !== app.downloading))) {
debug("Got a registration from an outdated app: " +
aApp.manifestURL);
let aEvent ={
type: app.installState,
app: app,
manifestURL: app.manifestURL,
manifest: app.manifest
};
aMm.sendAsyncMessage(aMsgName, aEvent);
}
}
}

View File

@ -10070,7 +10070,19 @@ class CGJSImplClass(CGBindingImplClass):
descriptor.name)
constructorBody = "SetIsDOMBinding();"
extradefinitions= string.Template(
"NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(${ifaceName}, mImpl, mParent)\n"
"NS_IMPL_CYCLE_COLLECTION_CLASS(${ifaceName})\n"
"NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(${ifaceName})\n"
" NS_IMPL_CYCLE_COLLECTION_UNLINK(mImpl)\n"
" NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)\n"
" NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER\n"
" tmp->ClearWeakReferences();\n"
"NS_IMPL_CYCLE_COLLECTION_UNLINK_END\n"
"NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(${ifaceName})\n"
" NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImpl)\n"
" NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)\n"
" NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS\n"
"NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END\n"
"NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(${ifaceName})\n"
"NS_IMPL_CYCLE_COLLECTING_ADDREF(${ifaceName})\n"
"NS_IMPL_CYCLE_COLLECTING_RELEASE(${ifaceName})\n"
"NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${ifaceName})\n"

View File

@ -25,14 +25,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=717103
devicestorage_setup();
var oldFiles = ["a.png", "b.png", "c.png"];
var timeFile = "t.png";
var newFiles = ["d.png", "e.png", "f.png"];
var storage = navigator.getDeviceStorage('pictures');
var prefix = "devicestorage/" + randomFilename(12);
var callback;
var files;
var i;
var timestamp;
var lastFileAddedTimestamp;
function verifyAndDelete(prefix, files, e) {
if (e.target.result == null) {
@ -62,31 +62,56 @@ function verifyAndDelete(prefix, files, e) {
if (index == -1)
return;
files.remove(index);
files.splice(index, 1);
// clean up
var cleanup = storage.delete(e.target.result.name);
cleanup.onsuccess = function(e) {}
}
function addSuccess(e) {
i = i + 1;
if (i == files.length) {
callback();
return;
function addFile(filename, callback) {
var addReq = storage.addNamed(createRandomBlob('image/png'), prefix + '/' + filename);
addReq.onsuccess = function(e) {
// After adding the file, we go ahead and grab the timestamp of the file
// that we just added
var getReq = storage.get(prefix + '/' + filename);
getReq.onsuccess = function(e) {
lastFileAddedTimestamp = e.target.result.lastModifiedDate;
callback();
}
getReq.onerror = function(e) {
ok(false, "getError was called : " + e.target.error.name);
devicestorage_cleanup();
};
}
addReq.onerror = function(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
}
addFile(files[i]);
}
function addError(e) {
ok(false, "addError was called : " + e.target.error.name);
devicestorage_cleanup();
function addFileArray(fileArray, callback) {
var i = 0;
function addNextFile() {
i = i + 1;
if (i == fileArray.length) {
callback();
return;
}
addFile(fileArray[i], addNextFile);
}
addFile(fileArray[0], addNextFile);
}
function addFile(filename){
var req = storage.addNamed(createRandomBlob('image/png'), prefix + '/' + files[i]);
req.onsuccess = addSuccess;
req.onerror = addError;
function delFile(filename, callback) {
var req = storage.delete(prefix + '/' + filename);
req.onsuccess = function(e) {
callback();
};
req.onerror = function(e) {
ok(false, "delError was called : " + e.target.error.name);
devicestorage_cleanup();
};
}
function afterNewFiles() {
@ -103,27 +128,36 @@ function afterNewFiles() {
};
}
function addNewFiles() {
i = 0;
files = newFiles;
callback = afterNewFiles;
addFile(files[0]);
}
function beforeNewFiles() {
timestamp = new Date();
setTimeout(addNewFiles, 1000);
function waitForTimestampChange() {
// We've added a new file. See if the timestamp differs from
// oldFileAddedTimestamp, and if it's the same wait for a bit
// and try again.
if (lastFileAddedTimestamp.valueOf() === timestamp.valueOf()) {
delFile(timeFile, function() {
setTimeout(function() {
addFile(timeFile, waitForTimestampChange);
}, 1000);
});
} else {
timestamp = lastFileAddedTimestamp;
// The timestamp has changed. Go ahead and add the rest of the new files
delFile(timeFile, function() {
addFileArray(newFiles, afterNewFiles);
});
}
}
function afterOldFiles() {
setTimeout(beforeNewFiles, 1000);
timestamp = lastFileAddedTimestamp;
setTimeout(function() {
// We've added our old files and waited for a second.
// Add a new file until the timestamp changes
addFile(timeFile, waitForTimestampChange);
}, 1000);
}
function addOldFiles() {
i = 0;
files = oldFiles;
callback = afterOldFiles;
addFile(files[0]);
addFileArray(oldFiles, afterOldFiles);
}
addOldFiles();

View File

@ -121,10 +121,6 @@ using namespace mozilla::system;
#include "BluetoothService.h"
#endif
#ifdef MOZ_NUWA_PROCESS
#include "ipc/Nuwa.h"
#endif
#include "JavaScriptParent.h"
#ifdef MOZ_B2G_FM
@ -140,8 +136,6 @@ using namespace mozilla::system;
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
static const char* sClipboardTextFlavors[] = { kUnicodeMime };
#define NUWA_FORK_WAIT_DURATION_MS 2000 // 2 seconds.
using base::ChildPrivileges;
using base::KillProcess;
using namespace mozilla::dom::bluetooth;
@ -273,32 +267,16 @@ static bool sCanLaunchSubprocesses;
// The first content child has ID 1, so the chrome process can have ID 0.
static uint64_t gContentChildID = 1;
// sNuwaProcess points to the Nuwa process which is used for forking new
// processes later.
static StaticRefPtr<ContentParent> sNuwaProcess;
// Nuwa process is ready for creating new process.
static bool sNuwaReady = false;
// The array containing the preallocated processes. 4 as the inline storage size
// should be enough so we don't need to grow the nsAutoTArray.
static StaticAutoPtr<nsAutoTArray<nsRefPtr<ContentParent>, 4> > sSpareProcesses;
static StaticAutoPtr<nsTArray<CancelableTask*> > sNuwaForkWaitTasks;
// We want the prelaunched process to know that it's for apps, but not
// actually for any app in particular. Use a magic manifest URL.
// Can't be a static constant.
#define MAGIC_PREALLOCATED_APP_MANIFEST_URL NS_LITERAL_STRING("{{template}}")
void
/* static */ already_AddRefed<ContentParent>
ContentParent::RunNuwaProcess()
{
MOZ_ASSERT(NS_IsMainThread());
if (sNuwaProcess) {
NS_RUNTIMEABORT("sNuwaProcess is created twice.");
}
sNuwaProcess =
nsRefPtr<ContentParent> nuwaProcess =
new ContentParent(/* aApp = */ nullptr,
/* aIsForBrowser = */ false,
/* aIsForPreallocated = */ true,
@ -307,109 +285,10 @@ ContentParent::RunNuwaProcess()
base::PRIVILEGES_INHERIT,
PROCESS_PRIORITY_BACKGROUND,
/* aIsNuwaProcess = */ true);
sNuwaProcess->Init();
nuwaProcess->Init();
return nuwaProcess.forget();
}
#ifdef MOZ_NUWA_PROCESS
// initialization off the critical path of app startup.
static CancelableTask* sPreallocateAppProcessTask;
// This number is fairly arbitrary ... the intention is to put off
// launching another app process until the last one has finished
// loading its content, to reduce CPU/memory/IO contention.
static int sPreallocateDelayMs = 1000;
static void
DelayedNuwaFork()
{
MOZ_ASSERT(NS_IsMainThread());
sPreallocateAppProcessTask = nullptr;
if (!sNuwaReady) {
if (!sNuwaProcess) {
ContentParent::RunNuwaProcess();
}
// else sNuwaProcess is starting. It will SendNuwaFork() when ready.
} else if (sSpareProcesses->IsEmpty()) {
sNuwaProcess->SendNuwaFork();
}
}
static void
ScheduleDelayedNuwaFork()
{
MOZ_ASSERT(NS_IsMainThread());
if (sPreallocateAppProcessTask) {
// Make sure there is only one request running.
return;
}
sPreallocateAppProcessTask = NewRunnableFunction(DelayedNuwaFork);
MessageLoop::current()->
PostDelayedTask(FROM_HERE,
sPreallocateAppProcessTask,
sPreallocateDelayMs);
}
/**
* Get a spare ContentParent from sSpareProcesses list.
*/
static already_AddRefed<ContentParent>
GetSpareProcess()
{
MOZ_ASSERT(NS_IsMainThread());
if (sSpareProcesses->IsEmpty()) {
return nullptr;
}
nsRefPtr<ContentParent> process = sSpareProcesses->LastElement();
sSpareProcesses->RemoveElementAt(sSpareProcesses->Length() - 1);
if (sSpareProcesses->IsEmpty() && sNuwaReady) {
NS_ASSERTION(sNuwaProcess != nullptr,
"Nuwa process is not present!");
ScheduleDelayedNuwaFork();
}
return process.forget();
}
/**
* Publish a ContentParent to spare process list.
*/
static void
PublishSpareProcess(ContentParent* aContent)
{
MOZ_ASSERT(NS_IsMainThread());
if (!sNuwaForkWaitTasks->IsEmpty()) {
sNuwaForkWaitTasks->ElementAt(0)->Cancel();
sNuwaForkWaitTasks->RemoveElementAt(0);
}
sSpareProcesses->AppendElement(aContent);
}
static void
MaybeForgetSpare(ContentParent* aContent)
{
MOZ_ASSERT(NS_IsMainThread());
if (sSpareProcesses->RemoveElement(aContent)) {
return;
}
if (aContent == sNuwaProcess) {
sNuwaProcess = nullptr;
sNuwaReady = false;
ScheduleDelayedNuwaFork();
}
}
#endif
// PreallocateAppProcess is called by the PreallocatedProcessManager.
// ContentParent then takes this process back within
// MaybeTakePreallocatedAppProcess.
@ -433,11 +312,7 @@ ContentParent::MaybeTakePreallocatedAppProcess(const nsAString& aAppManifestURL,
ChildPrivileges aPrivs,
ProcessPriority aInitialPriority)
{
#ifdef MOZ_NUWA_PROCESS
nsRefPtr<ContentParent> process = GetSpareProcess();
#else
nsRefPtr<ContentParent> process = PreallocatedProcessManager::Take();
#endif
if (!process) {
return nullptr;
}
@ -464,17 +339,8 @@ ContentParent::StartUp()
sCanLaunchSubprocesses = true;
sSpareProcesses = new nsAutoTArray<nsRefPtr<ContentParent>, 4>();
ClearOnShutdown(&sSpareProcesses);
sNuwaForkWaitTasks = new nsTArray<CancelableTask*>();
ClearOnShutdown(&sNuwaForkWaitTasks);
#ifdef MOZ_NUWA_PROCESS
ScheduleDelayedNuwaFork();
#else
// Try to preallocate a process that we can transform into an app later.
PreallocatedProcessManager::AllocateAfterDelay();
#endif
}
/*static*/ void
@ -1027,25 +893,13 @@ ContentParent::MarkAsDead()
mIsAlive = false;
}
void
ContentParent::OnNuwaForkTimeout()
{
if (!sNuwaForkWaitTasks->IsEmpty()) {
sNuwaForkWaitTasks->RemoveElementAt(0);
}
// We haven't RecvAddNewProcess() after SendNuwaFork(). Maybe the main
// thread of the Nuwa process is in deadlock.
MOZ_ASSERT(false, "Can't fork from the nuwa process.");
}
void
ContentParent::OnChannelError()
{
nsRefPtr<ContentParent> content(this);
PContentParent::OnChannelError();
#ifdef MOZ_NUWA_PROCESS
MaybeForgetSpare(this);
PreallocatedProcessManager::MaybeForgetSpare(this);
#endif
}
@ -1801,19 +1655,12 @@ ContentParent::RecvGetShowPasswordSetting(bool* showPassword)
bool
ContentParent::RecvFirstIdle()
{
#ifdef MOZ_NUWA_PROCESS
if (sSpareProcesses->IsEmpty() && sNuwaReady) {
ScheduleDelayedNuwaFork();
}
return true;
#else
// When the ContentChild goes idle, it sends us a FirstIdle message
// which we use as a good time to prelaunch another process. If we
// prelaunch any sooner than this, then we'll be competing with the
// child process and slowing it down.
PreallocatedProcessManager::AllocateAfterDelay();
return true;
#endif
}
bool
@ -1897,34 +1744,16 @@ ContentParent::RecvBroadcastVolume(const nsString& aVolumeName)
#endif
}
bool
ContentParent::SendNuwaFork()
{
if (this != sNuwaProcess) {
return false;
}
CancelableTask* nuwaForkTimeoutTask = NewRunnableMethod(
this, &ContentParent::OnNuwaForkTimeout);
sNuwaForkWaitTasks->AppendElement(nuwaForkTimeoutTask);
MessageLoop::current()->
PostDelayedTask(FROM_HERE,
nuwaForkTimeoutTask,
NUWA_FORK_WAIT_DURATION_MS);
return PContentParent::SendNuwaFork();
}
bool
ContentParent::RecvNuwaReady()
{
NS_ASSERTION(!sNuwaReady, "Multiple Nuwa processes created!");
ProcessPriorityManager::SetProcessPriority(sNuwaProcess,
hal::PROCESS_PRIORITY_FOREGROUND);
sNuwaReady = true;
SendNuwaFork();
#ifdef MOZ_NUWA_PROCESS
PreallocatedProcessManager::OnNuwaReady();
return true;
#else
NS_ERROR("ContentParent::RecvNuwaReady() not implemented!");
return false;
#endif
}
bool
@ -1939,7 +1768,7 @@ ContentParent::RecvAddNewProcess(const uint32_t& aPid,
aFds,
base::PRIVILEGES_DEFAULT);
content->Init();
PublishSpareProcess(content);
PreallocatedProcessManager::PublishSpareProcess(content);
return true;
#else
NS_ERROR("ContentParent::RecvAddNewProcess() not implemented!");

View File

@ -92,7 +92,7 @@ public:
*/
static already_AddRefed<ContentParent> PreallocateAppProcess();
static void RunNuwaProcess();
static already_AddRefed<ContentParent> RunNuwaProcess();
/**
* Get or create a content process for the given TabContext. aFrameElement
@ -209,8 +209,6 @@ public:
return PContentParent::RecvPJavaScriptConstructor(aActor);
}
virtual bool SendNuwaFork();
protected:
void OnChannelConnected(int32_t pid) MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason why);

View File

@ -9,6 +9,19 @@
#include "mozilla/Preferences.h"
#include "mozilla/dom/ContentParent.h"
#include "nsIPropertyBag2.h"
#include "ProcessPriorityManager.h"
#include "nsServiceManagerUtils.h"
#include "nsCxPusher.h"
#ifdef MOZ_NUWA_PROCESS
#include "ipc/Nuwa.h"
#endif
// This number is fairly arbitrary ... the intention is to put off
// launching another app process until the last one has finished
// loading its content, to reduce CPU/memory/IO contention.
#define DEFAULT_ALLOCATE_DELAY 1000
#define NUWA_FORK_WAIT_DURATION_MS 2000 // 2 seconds.
using namespace mozilla;
using namespace mozilla::hal;
@ -35,6 +48,31 @@ public:
void AllocateNow();
already_AddRefed<ContentParent> Take();
#ifdef MOZ_NUWA_PROCESS
public:
void ScheduleDelayedNuwaFork();
void DelayedNuwaFork();
void PublishSpareProcess(ContentParent* aContent);
void MaybeForgetSpare(ContentParent* aContent);
void OnNuwaReady();
already_AddRefed<ContentParent> GetSpareProcess();
private:
void OnNuwaForkTimeout();
void NuwaFork();
// initialization off the critical path of app startup.
CancelableTask* mPreallocateAppProcessTask;
// The array containing the preallocated processes. 4 as the inline storage size
// should be enough so we don't need to grow the nsAutoTArray.
nsAutoTArray<nsRefPtr<ContentParent>, 4> mSpareProcesses;
nsTArray<CancelableTask*> mNuwaForkWaitTasks;
// Nuwa process is ready for creating new process.
bool mIsNuwaReady;
#endif
private:
static mozilla::StaticRefPtr<PreallocatedProcessManagerImpl> sSingleton;
@ -72,6 +110,10 @@ NS_IMPL_ISUPPORTS1(PreallocatedProcessManagerImpl, nsIObserver)
PreallocatedProcessManagerImpl::PreallocatedProcessManagerImpl()
: mEnabled(false)
#ifdef MOZ_NUWA_PROCESS
, mPreallocateAppProcessTask(nullptr)
, mIsNuwaReady(false)
#endif
{}
void
@ -127,7 +169,11 @@ PreallocatedProcessManagerImpl::Enable()
}
mEnabled = true;
#ifdef MOZ_NUWA_PROCESS
ScheduleDelayedNuwaFork();
#else
AllocateAfterDelay();
#endif
}
void
@ -140,7 +186,8 @@ PreallocatedProcessManagerImpl::AllocateAfterDelay()
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
NewRunnableMethod(this, &PreallocatedProcessManagerImpl::AllocateOnIdle),
Preferences::GetUint("dom.ipc.processPrelaunch.delayMs", 1000));
Preferences::GetUint("dom.ipc.processPrelaunch.delayMs",
DEFAULT_ALLOCATE_DELAY));
}
void
@ -165,6 +212,135 @@ PreallocatedProcessManagerImpl::AllocateNow()
mPreallocatedAppProcess = ContentParent::PreallocateAppProcess();
}
#ifdef MOZ_NUWA_PROCESS
void
PreallocatedProcessManagerImpl::ScheduleDelayedNuwaFork()
{
MOZ_ASSERT(NS_IsMainThread());
if (mPreallocateAppProcessTask) {
// Make sure there is only one request running.
return;
}
mPreallocateAppProcessTask = NewRunnableMethod(
this, &PreallocatedProcessManagerImpl::DelayedNuwaFork);
MessageLoop::current()->PostDelayedTask(
FROM_HERE, mPreallocateAppProcessTask,
Preferences::GetUint("dom.ipc.processPrelaunch.delayMs",
DEFAULT_ALLOCATE_DELAY));
}
void
PreallocatedProcessManagerImpl::DelayedNuwaFork()
{
MOZ_ASSERT(NS_IsMainThread());
mPreallocateAppProcessTask = nullptr;
if (!mIsNuwaReady) {
if (!mPreallocatedAppProcess) {
mPreallocatedAppProcess = ContentParent::RunNuwaProcess();
}
// else mPreallocatedAppProcess is starting. It will NuwaFork() when ready.
} else if (mSpareProcesses.IsEmpty()) {
NuwaFork();
}
}
/**
* Get a spare ContentParent from mSpareProcesses list.
*/
already_AddRefed<ContentParent>
PreallocatedProcessManagerImpl::GetSpareProcess()
{
MOZ_ASSERT(NS_IsMainThread());
if (mSpareProcesses.IsEmpty()) {
return nullptr;
}
nsRefPtr<ContentParent> process = mSpareProcesses.LastElement();
mSpareProcesses.RemoveElementAt(mSpareProcesses.Length() - 1);
if (mSpareProcesses.IsEmpty() && mIsNuwaReady) {
NS_ASSERTION(mPreallocatedAppProcess != nullptr,
"Nuwa process is not present!");
ScheduleDelayedNuwaFork();
}
return process.forget();
}
/**
* Publish a ContentParent to spare process list.
*/
void
PreallocatedProcessManagerImpl::PublishSpareProcess(ContentParent* aContent)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mNuwaForkWaitTasks.IsEmpty()) {
mNuwaForkWaitTasks.ElementAt(0)->Cancel();
mNuwaForkWaitTasks.RemoveElementAt(0);
}
mSpareProcesses.AppendElement(aContent);
}
void
PreallocatedProcessManagerImpl::MaybeForgetSpare(ContentParent* aContent)
{
MOZ_ASSERT(NS_IsMainThread());
if (mSpareProcesses.RemoveElement(aContent)) {
return;
}
if (aContent == mPreallocatedAppProcess) {
mPreallocatedAppProcess = nullptr;
mIsNuwaReady = false;
ScheduleDelayedNuwaFork();
}
}
void
PreallocatedProcessManagerImpl::OnNuwaReady()
{
NS_ASSERTION(!mIsNuwaReady, "Multiple Nuwa processes created!");
ProcessPriorityManager::SetProcessPriority(mPreallocatedAppProcess,
hal::PROCESS_PRIORITY_FOREGROUND);
mIsNuwaReady = true;
NuwaFork();
}
void
PreallocatedProcessManagerImpl::OnNuwaForkTimeout()
{
if (!mNuwaForkWaitTasks.IsEmpty()) {
mNuwaForkWaitTasks.RemoveElementAt(0);
}
// We haven't RecvAddNewProcess() after NuwaFork(). Maybe the main
// thread of the Nuwa process is in deadlock.
MOZ_ASSERT(false, "Can't fork from the nuwa process.");
}
void
PreallocatedProcessManagerImpl::NuwaFork()
{
CancelableTask* nuwaForkTimeoutTask = NewRunnableMethod(
this, &PreallocatedProcessManagerImpl::OnNuwaForkTimeout);
mNuwaForkWaitTasks.AppendElement(nuwaForkTimeoutTask);
MessageLoop::current()->PostDelayedTask(FROM_HERE,
nuwaForkTimeoutTask,
NUWA_FORK_WAIT_DURATION_MS);
mPreallocatedAppProcess->SendNuwaFork();
}
#endif
void
PreallocatedProcessManagerImpl::Disable()
{
@ -174,8 +350,24 @@ PreallocatedProcessManagerImpl::Disable()
mEnabled = false;
#ifdef MOZ_NUWA_PROCESS
// Cancel pending fork.
if (mPreallocateAppProcessTask) {
mPreallocateAppProcessTask->Cancel();
mPreallocateAppProcessTask = nullptr;
}
#endif
if (mPreallocatedAppProcess) {
mPreallocatedAppProcess->ShutDown();
#ifdef MOZ_NUWA_PROCESS
while (mSpareProcesses.Length() > 0){
nsRefPtr<ContentParent> process = mSpareProcesses[0];
process->Close();
mSpareProcesses.RemoveElementAt(0);
}
mIsNuwaReady = false;
#endif
mPreallocatedAppProcess->Close();
mPreallocatedAppProcess = nullptr;
}
}
@ -199,6 +391,11 @@ PreallocatedProcessManagerImpl::ObserveProcessShutdown(nsISupports* aSubject)
}
}
inline PreallocatedProcessManagerImpl* GetPPMImpl()
{
return PreallocatedProcessManagerImpl::Singleton();
}
} // anonymous namespace
namespace mozilla {
@ -206,25 +403,53 @@ namespace mozilla {
/* static */ void
PreallocatedProcessManager::AllocateAfterDelay()
{
PreallocatedProcessManagerImpl::Singleton()->AllocateAfterDelay();
#ifdef MOZ_NUWA_PROCESS
GetPPMImpl()->ScheduleDelayedNuwaFork();
#else
GetPPMImpl()->AllocateAfterDelay();
#endif
}
/* static */ void
PreallocatedProcessManager::AllocateOnIdle()
{
PreallocatedProcessManagerImpl::Singleton()->AllocateOnIdle();
GetPPMImpl()->AllocateOnIdle();
}
/* static */ void
PreallocatedProcessManager::AllocateNow()
{
PreallocatedProcessManagerImpl::Singleton()->AllocateNow();
GetPPMImpl()->AllocateNow();
}
/* static */ already_AddRefed<ContentParent>
PreallocatedProcessManager::Take()
{
return PreallocatedProcessManagerImpl::Singleton()->Take();
#ifdef MOZ_NUWA_PROCESS
return GetPPMImpl()->GetSpareProcess();
#else
return GetPPMImpl()->Take();
#endif
}
#ifdef MOZ_NUWA_PROCESS
/* static */ void
PreallocatedProcessManager::PublishSpareProcess(ContentParent* aContent)
{
GetPPMImpl()->PublishSpareProcess(aContent);
}
/* static */ void
PreallocatedProcessManager::MaybeForgetSpare(ContentParent* aContent)
{
GetPPMImpl()->MaybeForgetSpare(aContent);
}
/* static */ void
PreallocatedProcessManager::OnNuwaReady()
{
GetPPMImpl()->OnNuwaReady();
}
#endif
} // namespace mozilla

View File

@ -78,6 +78,12 @@ public:
*/
static already_AddRefed<ContentParent> Take();
#ifdef MOZ_NUWA_PROCESS
static void PublishSpareProcess(ContentParent* aContent);
static void MaybeForgetSpare(ContentParent* aContent);
static void OnNuwaReady();
#endif
private:
PreallocatedProcessManager();
DISALLOW_EVIL_CONSTRUCTORS(PreallocatedProcessManager);

View File

@ -829,7 +829,6 @@ RTCError.prototype = {
// This is a separate object because we don't want to expose it to DOM.
function PeerConnectionObserver() {
this._dompc = null;
this._guard = new WeakReferent(this);
}
PeerConnectionObserver.prototype = {
classDescription: "PeerConnectionObserver",
@ -1127,20 +1126,6 @@ PeerConnectionObserver.prototype = {
getSupportedConstraints: function(dict) {
return dict;
},
get weakReferent() {
return this._guard;
}
};
// A PeerConnectionObserver member that c++ can do weak references on
function WeakReferent(parent) {
this._parent = parent; // prevents parent from going away without us
}
WeakReferent.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
Ci.nsISupportsWeakReference]),
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(

View File

@ -23,7 +23,7 @@ dictionary MmsDeliveryInfo
// |delivery| = "received" or not yet delivered).
};
[scriptable, builtinclass, uuid(3593c914-420a-11e3-a297-a3bdd768257f)]
[scriptable, builtinclass, uuid(82ca2465-f967-4107-a4da-65b7a15d5dba)]
interface nsIDOMMozMmsMessage : nsISupports
{
/**
@ -71,5 +71,5 @@ interface nsIDOMMozMmsMessage : nsISupports
// manually downloaded.
// Request read report from sender or not.
readonly attribute boolean isReadReportRequested;
readonly attribute boolean readReportRequested;
};

View File

@ -14,7 +14,7 @@ interface nsIDOMMozSmsSegmentInfo;
#define MOBILE_MESSAGE_SERVICE_CONTRACTID "@mozilla.org/mobilemessage/mobilemessageservice;1"
%}
[scriptable, builtinclass, uuid(c9a1aa14-7088-4f22-9d7f-b0c6ce9cf484)]
[scriptable, builtinclass, uuid(7255f557-0dd1-42f9-82fa-031cebb76bb5)]
interface nsIMobileMessageService : nsISupports
{
[implicit_jscontext]
@ -45,7 +45,7 @@ interface nsIMobileMessageService : nsISupports
in DOMString smil,
in jsval attachments,
in jsval expiryDate,
in boolean isReadReportRequested);
in boolean readReportRequested);
nsIDOMMozSmsSegmentInfo createSmsSegmentInfo(in long segments,
in long charsPerSegment,

View File

@ -47,7 +47,7 @@ MmsMessage::MmsMessage(int32_t aId,
const nsAString& aSmil,
const nsTArray<MmsAttachment>& aAttachments,
uint64_t aExpiryDate,
bool aIsReadReportRequested)
bool aReadReportRequested)
: mId(aId),
mThreadId(aThreadId),
mIccId(aIccId),
@ -61,7 +61,7 @@ MmsMessage::MmsMessage(int32_t aId,
mSmil(aSmil),
mAttachments(aAttachments),
mExpiryDate(aExpiryDate),
mIsReadReportRequested(aIsReadReportRequested)
mReadReportRequested(aReadReportRequested)
{
}
@ -77,7 +77,7 @@ MmsMessage::MmsMessage(const mobilemessage::MmsMessageData& aData)
, mSubject(aData.subject())
, mSmil(aData.smil())
, mExpiryDate(aData.expiryDate())
, mIsReadReportRequested(aData.isReadReportRequested())
, mReadReportRequested(aData.readReportRequested())
{
uint32_t len = aData.attachments().Length();
mAttachments.SetCapacity(len);
@ -339,7 +339,7 @@ MmsMessage::GetData(ContentParent* aParent,
aData.subject() = mSubject;
aData.smil() = mSmil;
aData.expiryDate() = mExpiryDate;
aData.isReadReportRequested() = mIsReadReportRequested;
aData.readReportRequested() = mReadReportRequested;
aData.deliveryInfo().SetCapacity(mDeliveryInfo.Length());
for (uint32_t i = 0; i < mDeliveryInfo.Length(); i++) {
@ -658,9 +658,9 @@ MmsMessage::GetExpiryDate(JSContext* cx, JS::Value* aDate)
}
NS_IMETHODIMP
MmsMessage::GetIsReadReportRequested(bool* aIsReadReportRequested)
MmsMessage::GetReadReportRequested(bool* aReadReportRequested)
{
*aIsReadReportRequested = mIsReadReportRequested;
*aReadReportRequested = mReadReportRequested;
return NS_OK;
}

View File

@ -40,7 +40,7 @@ public:
const nsAString& aSmil,
const nsTArray<idl::MmsAttachment>& aAttachments,
uint64_t aExpiryDate,
bool aIsReadReportRequested);
bool aReadReportRequested);
MmsMessage(const mobilemessage::MmsMessageData& aData);
@ -57,7 +57,7 @@ public:
const nsAString& aSmil,
const JS::Value& aAttachments,
const JS::Value& aExpiryDate,
bool aIsReadReportRequested,
bool aReadReportRequested,
JSContext* aCx,
nsIDOMMozMmsMessage** aMessage);
@ -79,7 +79,7 @@ private:
nsString mSmil;
nsTArray<idl::MmsAttachment> mAttachments;
uint64_t mExpiryDate;
bool mIsReadReportRequested;
bool mReadReportRequested;
};
} // namespace dom

View File

@ -74,7 +74,7 @@ MobileMessageService::CreateMmsMessage(int32_t aId,
const nsAString& aSmil,
const JS::Value& aAttachments,
const JS::Value& aExpiryDate,
bool aIsReadReportRequested,
bool aReadReportRequested,
JSContext* aCx,
nsIDOMMozMmsMessage** aMessage)
{
@ -91,7 +91,7 @@ MobileMessageService::CreateMmsMessage(int32_t aId,
aSmil,
aAttachments,
aExpiryDate,
aIsReadReportRequested,
aReadReportRequested,
aCx,
aMessage);
}

View File

@ -1290,7 +1290,7 @@ MobileMessageDatabaseService.prototype = {
if (headers["x-mms-expiry"] != undefined) {
expiryDate = aMessageRecord.timestamp + headers["x-mms-expiry"] * 1000;
}
let isReadReportRequested = headers["x-mms-read-report"] || false;
let readReportRequested = headers["x-mms-read-report"] || false;
return gMobileMessageService.createMmsMessage(aMessageRecord.id,
aMessageRecord.threadId,
aMessageRecord.iccId,
@ -1304,7 +1304,7 @@ MobileMessageDatabaseService.prototype = {
smil,
attachments,
expiryDate,
isReadReportRequested);
readReportRequested);
}
},

View File

@ -68,7 +68,7 @@ struct MmsMessageData
nsString smil;
MmsAttachmentData[] attachments;
uint64_t expiryDate;
bool isReadReportRequested;
bool readReportRequested;
};
union MobileMessageData

View File

@ -16,7 +16,7 @@ Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
Cu.importGlobalProperties(["indexedDB"]);
const DB_NAME = "net_stats";
const DB_VERSION = 3;
const DB_VERSION = 4;
const STORE_NAME = "net_stats";
// Constant defining the maximum values allowed per interface. If more, older
@ -92,6 +92,34 @@ NetworkStatsDB.prototype = {
if (DEBUG) {
debug("Created object stores and indexes for version 3");
}
} else if (currVersion == 3) {
// Delete redundent indexes (leave "network" only).
objectStore = aTransaction.objectStore(STORE_NAME);
if (objectStore.indexNames.contains("appId")) {
objectStore.deleteIndex("appId");
}
if (objectStore.indexNames.contains("networkType")) {
objectStore.deleteIndex("networkType");
}
if (objectStore.indexNames.contains("timestamp")) {
objectStore.deleteIndex("timestamp");
}
if (objectStore.indexNames.contains("rxBytes")) {
objectStore.deleteIndex("rxBytes");
}
if (objectStore.indexNames.contains("txBytes")) {
objectStore.deleteIndex("txBytes");
}
if (objectStore.indexNames.contains("rxTotalBytes")) {
objectStore.deleteIndex("rxTotalBytes");
}
if (objectStore.indexNames.contains("txTotalBytes")) {
objectStore.deleteIndex("txTotalBytes");
}
if (DEBUG) {
debug("Deleted redundent indexes for version 4");
}
}
}
},

View File

@ -935,6 +935,9 @@ function RadioInterface(options) {
lock.get("ril.data.enabled", this);
lock.get("ril.data.apnSettings", this);
// Read the default client id for data call.
lock.get("ril.data.defaultServiceId", this);
// Read the "time.clock.automatic-update.enabled" setting to see if
// we need to adjust the system clock time by NITZ or SNTP.
lock.get(kSettingsClockAutoUpdateEnabled, this);
@ -1742,6 +1745,34 @@ RadioInterface.prototype = {
apnSetting.types.length);
},
handleDataClientIdChange: function handleDataClientIdChange() {
// Default data has been switched to the current RadioInterface.
// If there is an active default data call, wait for it to get
// disconnected, otherwise connect directly.
if (this.clientId == this._dataDefaultClientId &&
this._dataEnabled) {
this.dataCallSettings.oldEnabled = this.dataCallSettings.enabled;
this.dataCallSettings.enabled = true;
if (gNetworkManager.active &&
gNetworkManager.active.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
if (DEBUG) this.debug("Default data active, wait for it to get disconnected.");
this._dataCallSetupPending = true;
return;
}
this.updateRILNetworkInterface();
return;
}
// Default data has been switched from this current RadioInterface,
// disconnet data call if it is enabled.
if (this.clientId != this._dataDefaultClientId &&
this.dataCallSettings.enabled) {
this.dataCallSettings.oldEnabled = this.dataCallSettings.enabled;
this.dataCallSettings.enabled = false;
this.updateRILNetworkInterface();
}
},
updateRILNetworkInterface: function updateRILNetworkInterface() {
let apnSetting = this.apnSettings.byType.default;
if (!this.validateApnSetting(apnSetting)) {
@ -2359,6 +2390,18 @@ RadioInterface.prototype = {
this._sntp.request();
}
}
// DSDS: setup pending data connection when switching the default id
// for data call.
// We can not use network.type to tell if it's NETWORK_TYPE_MOBILE,
// since the type is removed from RILNetworkInterface.connectedTypes
// on disconnect().
if (network.state == Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN &&
this._dataCallSetupPending) {
if (DEBUG) this.debug("Default data disconnected, setup pending data call.");
this._dataCallSetupPending = false;
this.updateRILNetworkInterface();
}
break;
case kScreenStateChangedTopic:
this.workerMessenger.send("setScreenState", { on: (data === "on") });
@ -2371,6 +2414,17 @@ RadioInterface.prototype = {
apnSettings: null,
// Flag to determine the data state to start with when we boot up. It
// corresponds to the 'ril.data.enabled' setting from the UI.
_dataEnabled: null,
// Flag to record the default client id for data call.
_dataDefaultClientId: null,
// Flag to determine if we need to setup data call when we are notified
// that another data call has been disconnected.
_dataCallSetupPending: false,
// Flag to determine whether to update system clock automatically. It
// corresponds to the "time.clock.automatic-update.enabled" setting.
_clockAutoUpdateEnabled: null,
@ -2430,15 +2484,15 @@ RadioInterface.prototype = {
break;
case "ril.data.enabled":
if (DEBUG) this.debug("'ril.data.enabled' is now " + aResult);
let enabled;
if (Array.isArray(aResult)) {
enabled = aResult[this.clientId];
} else {
// Backward compability
enabled = aResult;
if (this._dataEnabled == aResult) {
break;
}
this._dataEnabled = aResult;
if (this.clientId != this._dataDefaultClientId) {
break;
}
this.dataCallSettings.oldEnabled = this.dataCallSettings.enabled;
this.dataCallSettings.enabled = enabled;
this.dataCallSettings.enabled = aResult;
this.updateRILNetworkInterface();
break;
case "ril.data.roaming_enabled":
@ -2453,6 +2507,15 @@ RadioInterface.prototype = {
this.updateRILNetworkInterface();
}
break;
case "ril.data.defaultServiceId":
aResult = aResult ? aResult : 0;
if (DEBUG) this.debug("'ril.data.defaultServiceId' is now " + aResult);
if (this._dataDefaultClientId == aResult) {
break;
}
this._dataDefaultClientId = aResult;
this.handleDataClientIdChange();
break;
case kSettingsClockAutoUpdateEnabled:
this._clockAutoUpdateEnabled = aResult;
if (!this._clockAutoUpdateEnabled) {
@ -3682,18 +3745,17 @@ RILNetworkInterface.prototype = {
this.radioInterface.updateRILNetworkInterface();
}
Services.obs.notifyObservers(this,
kNetworkInterfaceStateChangedTopic,
null);
if (this.state == RIL.GECKO_NETWORK_STATE_UNKNOWN &&
this.registeredAsNetworkInterface) {
gNetworkManager.unregisterNetworkInterface(this);
this.registeredAsNetworkInterface = false;
this.cid = null;
this.connectedTypes = [];
return;
}
Services.obs.notifyObservers(this,
kNetworkInterfaceStateChangedTopic,
null);
},
receiveDataCallList: function receiveDataCallList(dataCalls, length) {

View File

@ -94,6 +94,13 @@ partial interface HTMLElement {
readonly attribute long offsetHeight;
};
// Extension for scroll-grabbing, used in the B2G dynamic toolbar.
// This is likely to be revised.
partial interface HTMLElement {
[Func="nsGenericHTMLElement::IsScrollGrabAllowed"]
attribute boolean scrollgrab;
};
[NoInterfaceObject]
interface TouchEventHandlers {
[Func="nsGenericHTMLElement::TouchEventsEnabled"]

View File

@ -42,9 +42,6 @@ interface PeerConnectionObserver
void onAddTrack();
void onRemoveTrack();
/* Used by c++ to know when Observer goes away */
readonly attribute nsISupports weakReferent;
/* Helper function to access supported constraints defined in webidl. Needs to
* be in a separate webidl object we hold, so putting it here was convenient.
*/

View File

@ -585,6 +585,7 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
WriteParam(aMsg, aParam.mMayHaveTouchListeners);
WriteParam(aMsg, aParam.mPresShellId);
WriteParam(aMsg, aParam.mIsRoot);
WriteParam(aMsg, aParam.mHasScrollgrab);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
@ -602,7 +603,8 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
ReadParam(aMsg, aIter, &aResult->mDevPixelsPerCSSPixel) &&
ReadParam(aMsg, aIter, &aResult->mMayHaveTouchListeners) &&
ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
ReadParam(aMsg, aIter, &aResult->mIsRoot));
ReadParam(aMsg, aIter, &aResult->mIsRoot) &&
ReadParam(aMsg, aIter, &aResult->mHasScrollgrab));
}
};

View File

@ -54,6 +54,7 @@ public:
, mMayHaveTouchListeners(false)
, mPresShellId(-1)
, mIsRoot(false)
, mHasScrollgrab(false)
{}
// Default copy ctor and operator= are fine
@ -256,6 +257,9 @@ public:
// Whether or not this is the root scroll frame for the root content document.
bool mIsRoot;
// Whether or not this frame is for an element marked 'scrollgrab'.
bool mHasScrollgrab;
};
/**

View File

@ -21,6 +21,8 @@
#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc
#include "nsThreadUtils.h" // for NS_IsMainThread
#include <algorithm> // for std::stable_sort
#define APZC_LOG(...)
// #define APZC_LOG(...) printf_stderr("APZC: " __VA_ARGS__)
@ -271,6 +273,8 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent,
if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_START) {
mTouchCount++;
mApzcForInputBlock = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[0].mScreenPoint));
if (multiTouchInput.mTouches.Length() == 1) // pan, not pinch
mApzcForInputBlock = AdjustForScrollGrab(mApzcForInputBlock);
for (size_t i = 1; i < multiTouchInput.mTouches.Length(); i++) {
nsRefPtr<AsyncPanZoomController> apzc2 = GetTargetAPZC(ScreenPoint(multiTouchInput.mTouches[i].mScreenPoint));
mApzcForInputBlock = CommonAncestor(mApzcForInputBlock.get(), apzc2.get());
@ -313,6 +317,7 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent,
// then null it out so we don't keep a dangling reference and leak things.
if (mTouchCount == 0) {
mApzcForInputBlock = nullptr;
mOverscrollHandoffChain.clear();
}
}
break;
@ -348,6 +353,8 @@ APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
ScreenPoint aPoint)
{
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aPoint);
if (aEvent.touches.Length() == 1) // pan, not pinch
apzc = AdjustForScrollGrab(apzc);
gfx3DMatrix transformToApzc, transformToGecko;
// Reset the cached apz transform
mCachedTransformToApzcForInputBlock = transformToApzc;
@ -423,6 +430,7 @@ APZCTreeManager::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
}
if (mTouchCount == 0) {
mApzcForInputBlock = nullptr;
mOverscrollHandoffChain.clear();
}
}
return ret;
@ -612,34 +620,37 @@ APZCTreeManager::ClearTree()
}
void
APZCTreeManager::HandleOverscroll(AsyncPanZoomController* aChild, ScreenPoint aStartPoint, ScreenPoint aEndPoint)
APZCTreeManager::HandleOverscroll(AsyncPanZoomController* aPrev, ScreenPoint aStartPoint, ScreenPoint aEndPoint,
int aOverscrollHandoffChainIndex)
{
nsRefPtr<AsyncPanZoomController> parent;
{
// The tree lock needs to be held while navigating from an apzc to its
// parent. We don't hold it any longer though because GetInputTransforms()
// does its own locking, and AttemptScroll() can call HandleOverscroll()
// recursively.
MonitorAutoLock lock(mTreeLock);
parent = aChild->GetParent();
// Increment the current index into the chain of APZCs that handle overscroll
// for the current pan gesture. Since we are in overscroll, we have scrolled
// the previous APZC as far as possible, and will now hand off the remaining
// scroll to the next one.
++aOverscrollHandoffChainIndex;
if (aOverscrollHandoffChainIndex >= mOverscrollHandoffChain.length()) {
// Nothing more to scroll - ignore the rest of the pan gesture.
return;
}
if (parent == nullptr)
nsRefPtr<AsyncPanZoomController> next = mOverscrollHandoffChain[aOverscrollHandoffChainIndex];
if (next == nullptr)
return;
gfx3DMatrix transformToApzc;
gfx3DMatrix transformToGecko; // ignored
// Convert start and end points to untransformed screen coordinates.
GetInputTransforms(aChild, transformToApzc, transformToGecko);
GetInputTransforms(aPrev, transformToApzc, transformToGecko);
ApplyTransform(&aStartPoint, transformToApzc.Inverse());
ApplyTransform(&aEndPoint, transformToApzc.Inverse());
// Convert start and end points to parent's transformed screen coordinates.
GetInputTransforms(parent.get(), transformToApzc, transformToGecko);
// Convert start and end points to next's transformed screen coordinates.
GetInputTransforms(next, transformToApzc, transformToGecko);
ApplyTransform(&aStartPoint, transformToApzc);
ApplyTransform(&aEndPoint, transformToApzc);
parent->AttemptScroll(aStartPoint, aEndPoint);
next->AttemptScroll(aStartPoint, aEndPoint, aOverscrollHandoffChainIndex);
}
bool
@ -673,6 +684,13 @@ APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid)
return target.forget();
}
struct CompareByScrollPriority
{
bool operator()(const nsRefPtr<AsyncPanZoomController>& a, const nsRefPtr<AsyncPanZoomController>& b) {
return a->HasScrollgrab() && !b->HasScrollgrab();
}
};
already_AddRefed<AsyncPanZoomController>
APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint)
{
@ -689,6 +707,46 @@ APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint)
return target.forget();
}
already_AddRefed<AsyncPanZoomController>
APZCTreeManager::AdjustForScrollGrab(const nsRefPtr<AsyncPanZoomController>& aInitialTarget)
{
// Scroll grabbing is a mechanism that allows content to specify that
// the initial target of a pan should be not the innermost scrollable
// frame at the touch point (which is what GetTargetAPZC finds), but
// something higher up in the tree.
// It's not sufficient to just find the initial target, however, as
// overscroll can be handed off to another APZC. Without scroll grabbing,
// handoff just occurs from child to parent. With scroll grabbing, the
// handoff order can be different, so we build a chain of APZCs in the
// order in which scroll will be handed off to them.
mOverscrollHandoffChain.clear();
// Start with the child -> parent chain.
for (AsyncPanZoomController* apzc = aInitialTarget; apzc; apzc = apzc->GetParent()) {
if (!mOverscrollHandoffChain.append(apzc)) {
NS_WARNING("Vector::append failed");
mOverscrollHandoffChain.clear();
return nullptr;
}
}
// Now adjust the chain to account for scroll grabbing. Sorting is a bit
// of an overkill here, but scroll grabbing will likely be generalized
// to scroll priorities, so we might as well do it this way.
// The sorting being stable ensures that the relative order between
// non-scrollgrabbing APZCs remains child -> parent.
// (The relative order between scrollgrabbing APZCs will also remain
// child -> parent, though that's just an artefact of the implementation
// and users of 'scrollgrab' should not rely on this.)
std::stable_sort(mOverscrollHandoffChain.begin(), mOverscrollHandoffChain.end(),
CompareByScrollPriority());
// The initial target is the first APZC in the handoff chain.
nsRefPtr<AsyncPanZoomController> result = mOverscrollHandoffChain.length() > 0 ? mOverscrollHandoffChain[0] : nullptr;
return result.forget();
}
void
APZCTreeManager::GetRootAPZCsFor(const uint64_t& aLayersId,
nsTArray< nsRefPtr<AsyncPanZoomController> >* aOutRootApzcs)

View File

@ -18,6 +18,7 @@
#include "nsCOMPtr.h" // for already_AddRefed
#include "nsISupportsImpl.h"
#include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc
#include "mozilla/Vector.h" // for mozilla::Vector
class gfx3DMatrix;
template <class E> class nsTArray;
@ -213,15 +214,21 @@ public:
/**
* This is a callback for AsyncPanZoomController to call when a touch-move
* event causes overscroll. The overscroll will be passed on to the parent
* APZC. |aStartPoint| and |aEndPoint| are in |aAPZC|'s transformed screen
* event causes overscroll. The overscroll will be passed on to the next
* APZC in the overscroll handoff chain, which was determined in the
* GetTargetAPZC() call for the first touch event of the touch block (usually
* the handoff chain is child -> parent, but scroll grabbing can change this).
* |aStartPoint| and |aEndPoint| are in |aAPZC|'s transformed screen
* coordinates (i.e. the same coordinates in which touch points are given to
* APZCs). The amount of the overscroll is represented by two points rather
* than a displacement because with certain 3D transforms, the same
* displacement between different points in transformed coordinates can
* represent different displacements in untransformed coordinates.
* |aOverscrollHandoffChainIndex| is |aAPZC|'s current position in the
* overscroll handoff chain.
*/
void HandleOverscroll(AsyncPanZoomController* aAPZC, ScreenPoint aStartPoint, ScreenPoint aEndPoint);
void HandleOverscroll(AsyncPanZoomController* aAPZC, ScreenPoint aStartPoint, ScreenPoint aEndPoint,
int aOverscrollHandoffChainIndex);
protected:
/**
@ -239,6 +246,10 @@ public:
*/
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint);
/*
* Adjust the target APZC of an input event to account for scroll grabbing.
*/
already_AddRefed<AsyncPanZoomController> AdjustForScrollGrab(const nsRefPtr<AsyncPanZoomController>& aInitialTarget);
void GetRootAPZCsFor(const uint64_t& aLayersId,
nsTArray< nsRefPtr<AsyncPanZoomController> >* aOutRootApzcs);
void GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut,
@ -295,10 +306,16 @@ private:
* screen coordinates, as returned through the 'aTransformToApzcOut' parameter
* of GetInputTransform(), at the start of the input block. This is cached
* because this transform can change over the course of the input block,
* but for some operations we need to use the initial tranform.
* but for some operations we need to use the initial transform.
* Meaningless if mApzcForInputBlock is nullptr.
*/
gfx3DMatrix mCachedTransformToApzcForInputBlock;
/* The chain of APZCs that will handle pans for the current touch input
* block, in the order in which they will be scrolled. When one APZC has
* been scrolled as far as it can, any overscroll will be handed off to
* the next APZC in the chain.
*/
Vector< nsRefPtr<AsyncPanZoomController> > mOverscrollHandoffChain;
static float sDPI;
};

View File

@ -839,7 +839,8 @@ void AsyncPanZoomController::UpdateWithTouchAtDevicePoint(const MultiTouchInput&
}
void AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint,
const ScreenPoint& aEndPoint) {
const ScreenPoint& aEndPoint,
int aOverscrollHandoffChainIndex) {
// "start - end" rather than "end - start" because e.g. moving your finger
// down (*positive* direction along y axis) causes the vertical scroll offset
// to *decrease* as the page follows your finger.
@ -878,7 +879,8 @@ void AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint,
APZCTreeManager* treeManagerLocal = mTreeManager;
if (treeManagerLocal) {
// "+ overscroll" rather than "- overscroll" for the same reason as above.
treeManagerLocal->HandleOverscroll(this, aEndPoint + overscroll, aEndPoint);
treeManagerLocal->HandleOverscroll(this, aEndPoint + overscroll, aEndPoint,
aOverscrollHandoffChainIndex);
}
}
}

View File

@ -271,8 +271,19 @@ public:
* If this attempt causes overscroll (i.e. the layer cannot be scrolled
* by the entire amount requested), the overscroll is passed back to the
* tree manager via APZCTreeManager::HandleOverscroll().
* |aOverscrollHandoffChainIndex| is used by the tree manager to keep track
* of which APZC to hand off the overscroll to; this function simply
* propagates it to APZCTreeManager::HandleOverscroll() in the event of
* overscroll.
*/
void AttemptScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint);
void AttemptScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint,
int aOverscrollHandoffChainIndex = 0);
/**
* Returns whether this APZC is for an element marked with the 'scrollgrab'
* attribute.
*/
bool HasScrollgrab() const { return mFrameMetrics.mHasScrollgrab; }
protected:
/**

View File

@ -48,6 +48,7 @@
#include "mozilla/LookAndFeel.h"
#include "mozilla/Preferences.h"
#include "ActiveLayerTracker.h"
#include "nsContentUtils.h"
#include <stdint.h>
#include <algorithm>
@ -713,6 +714,13 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
metrics.mPresShellId = presShell->GetPresShellId();
// If the scroll frame's content is marked 'scrollgrab', record this
// in the FrameMetrics so APZ knows to provide the scroll grabbing
// behaviour.
if (aScrollFrame && nsContentUtils::HasScrollgrab(aScrollFrame->GetContent())) {
metrics.mHasScrollgrab = true;
}
aRoot->SetFrameMetrics(metrics);
}

View File

@ -2349,12 +2349,17 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}
// Since making new layers is expensive, only use nsDisplayScrollLayer
// if the area is scrollable and we're the content process.
// if the area is scrollable and we're the content process (unless we're on
// B2G, where we support async scrolling for scrollable elements in the
// parent process as well).
// When a displayport is being used, force building of a layer so that
// CompositorParent can always find the scrollable layer for the root content
// document.
// If the element is marked 'scrollgrab', also force building of a layer
// so that APZ can implement scroll grabbing.
mShouldBuildScrollableLayer = usingDisplayport || nsContentUtils::HasScrollgrab(mOuter->GetContent());
bool shouldBuildLayer = false;
if (usingDisplayport) {
if (mShouldBuildScrollableLayer) {
shouldBuildLayer = true;
} else {
nsRect scrollRange = GetScrollRange();
@ -2376,14 +2381,12 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
(!mIsRoot || !mOuter->PresContext()->IsRootContentDocument());
}
mShouldBuildScrollableLayer = false;
if (shouldBuildLayer) {
// ScrollLayerWrapper must always be created because it initializes the
// scroll layer count. The display lists depend on this.
ScrollLayerWrapper wrapper(mOuter, mScrolledFrame);
if (usingDisplayport) {
mShouldBuildScrollableLayer = true;
if (mShouldBuildScrollableLayer) {
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
// For root scrollframes in documents where the CSS viewport has been

View File

@ -677,7 +677,7 @@ PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
MOZ_ASSERT(aThread);
mThread = do_QueryInterface(aThread);
mPCObserver.Set(&aObserver);
mPCObserver = do_GetWeakReference(&aObserver);
// Find the STS thread
@ -978,6 +978,28 @@ PeerConnectionImpl::CreateDataChannel(const nsAString& aLabel,
return NS_OK;
}
// do_QueryObjectReferent() - Helps get PeerConnectionObserver from nsWeakPtr.
//
// nsWeakPtr deals in XPCOM interfaces, while webidl bindings are concrete objs.
// TODO: Turn this into a central (template) function somewhere (Bug 939178)
//
// Without it, each weak-ref call in this file would look like this:
//
// nsCOMPtr<nsISupportsWeakReference> tmp = do_QueryReferent(mPCObserver);
// nsRefPtr<nsSupportsWeakReference> tmp2 = do_QueryObject(tmp);
// nsRefPtr<PeerConnectionObserver> pco = static_cast<PeerConnectionObserver*>(&*tmp2);
// if (!pco) {
// return;
// }
static already_AddRefed<PeerConnectionObserver>
do_QueryObjectReferent(nsIWeakReference* aRawPtr) {
nsCOMPtr<nsISupportsWeakReference> tmp = do_QueryReferent(aRawPtr);
nsRefPtr<nsSupportsWeakReference> tmp2 = do_QueryObject(tmp);
nsRefPtr<PeerConnectionObserver> tmp3 = static_cast<PeerConnectionObserver*>(&*tmp2);
return tmp3.forget();
}
void
PeerConnectionImpl::NotifyConnection()
{
@ -986,7 +1008,7 @@ PeerConnectionImpl::NotifyConnection()
CSFLogDebug(logTag, "%s", __FUNCTION__);
#ifdef MOZILLA_INTERNAL_API
nsRefPtr<PeerConnectionObserver> pco = mPCObserver.MayGet();
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (!pco) {
return;
}
@ -1007,7 +1029,7 @@ PeerConnectionImpl::NotifyClosedConnection()
CSFLogDebug(logTag, "%s", __FUNCTION__);
#ifdef MOZILLA_INTERNAL_API
nsRefPtr<PeerConnectionObserver> pco = mPCObserver.MayGet();
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (!pco) {
return;
}
@ -1047,7 +1069,7 @@ PeerConnectionImpl::NotifyDataChannel(already_AddRefed<DataChannel> aChannel)
getter_AddRefs(domchannel));
NS_ENSURE_SUCCESS_VOID(rv);
nsRefPtr<PeerConnectionObserver> pco = mPCObserver.MayGet();
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (!pco) {
return;
}
@ -1513,7 +1535,7 @@ PeerConnectionImpl::onCallEvent(const OnCallEventArgs& args)
break;
}
nsRefPtr<PeerConnectionObserver> pco = mPCObserver.MayGet();
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (!pco) {
return;
}
@ -1536,7 +1558,7 @@ PeerConnectionImpl::ChangeReadyState(PCImplReadyState aReadyState)
mReadyState = aReadyState;
// Note that we are passing an nsRefPtr which keeps the observer live.
nsRefPtr<PeerConnectionObserver> pco = mPCObserver.MayGet();
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (!pco) {
return;
}
@ -1558,7 +1580,7 @@ PeerConnectionImpl::SetSignalingState_m(PCImplSignalingState aSignalingState)
}
mSignalingState = aSignalingState;
nsRefPtr<PeerConnectionObserver> pco = mPCObserver.MayGet();
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (!pco) {
return;
}
@ -1657,7 +1679,7 @@ PeerConnectionImpl::IceStateChange_m(PCImplIceState aState)
break;
}
nsRefPtr<PeerConnectionObserver> pco = mPCObserver.MayGet();
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (!pco) {
return NS_OK;
}
@ -1760,7 +1782,7 @@ void PeerConnectionImpl::OnStatsReport_m(
uint32_t trackId,
nsresult result,
nsAutoPtr<RTCStatsReportInternal> report) {
PeerConnectionObserver* pco = mPCObserver.MayGet();
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (pco) {
JSErrorResult rv;
if (NS_SUCCEEDED(result)) {
@ -1853,30 +1875,4 @@ PeerConnectionImpl::GetRemoteStreams(nsTArray<nsRefPtr<DOMMediaStream > >& resul
#endif
}
// WeakConcretePtr gets around WeakPtr not working on concrete types by using
// the attribute getWeakReferent, a member that supports weak refs, as a guard.
void
PeerConnectionImpl::WeakConcretePtr::Set(PeerConnectionObserver *aObserver) {
mObserver = aObserver;
#ifdef MOZILLA_INTERNAL_API
MOZ_ASSERT(NS_IsMainThread());
JSErrorResult rv;
nsCOMPtr<nsISupports> tmp = aObserver->GetWeakReferent(rv);
MOZ_ASSERT(!rv.Failed());
mWeakPtr = do_GetWeakReference(tmp);
#else
mWeakPtr = do_GetWeakReference(aObserver);
#endif
}
PeerConnectionObserver *
PeerConnectionImpl::WeakConcretePtr::MayGet() {
#ifdef MOZILLA_INTERNAL_API
MOZ_ASSERT(NS_IsMainThread());
#endif
nsCOMPtr<nsISupports> guard = do_QueryReferent(mWeakPtr);
return (!guard) ? nullptr : mObserver;
}
} // end sipcc namespace

View File

@ -510,20 +510,9 @@ private:
mozilla::dom::PCImplIceState mIceState;
nsCOMPtr<nsIThread> mThread;
// WeakConcretePtr to PeerConnectionObserver. TODO: Remove after bug 928535
//
// This is only safe to use on the main thread
// TODO: Remove if we ever properly wire PeerConnection for cycle-collection.
class WeakConcretePtr
{
public:
WeakConcretePtr() : mObserver(nullptr) {}
void Set(PeerConnectionObserver *aObserver);
PeerConnectionObserver *MayGet();
private:
PeerConnectionObserver *mObserver;
nsWeakPtr mWeakPtr;
} mPCObserver;
nsWeakPtr mPCObserver;
nsCOMPtr<nsPIDOMWindow> mWindow;
// The SDP sent in from JS - here for debugging.

View File

@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ParentProcessController.h"
#include "nsIContent.h"
#include "nsLayoutUtils.h"
#include "APZCCallbackHelper.h"
#include "base/message_loop.h"
namespace mozilla {
namespace widget {
class RequestContentRepaintEvent : public nsRunnable
{
typedef mozilla::layers::FrameMetrics FrameMetrics;
public:
RequestContentRepaintEvent(const FrameMetrics& aFrameMetrics)
: mFrameMetrics(aFrameMetrics)
{
}
NS_IMETHOD Run() {
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(mFrameMetrics.mScrollId);
if (content) {
APZCCallbackHelper::UpdateSubFrame(content, mFrameMetrics);
}
return NS_OK;
}
protected:
const FrameMetrics mFrameMetrics;
};
void
ParentProcessController::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
{
if (aFrameMetrics.mScrollId == FrameMetrics::NULL_SCROLL_ID) {
return;
}
nsCOMPtr<nsIRunnable> r = new RequestContentRepaintEvent(aFrameMetrics);
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(r);
} else {
r->Run();
}
}
void
ParentProcessController::PostDelayedTask(Task* aTask, int aDelayMs)
{
MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs);
}
}
}

View File

@ -0,0 +1,34 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __mozilla_widget_DynamicToolbarController_h__
#define __mozilla_widget_DynamicToolbarController_h__
#include "mozilla/layers/GeckoContentController.h"
namespace mozilla {
namespace widget {
class ParentProcessController : public mozilla::layers::GeckoContentController
{
typedef mozilla::layers::FrameMetrics FrameMetrics;
public:
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) MOZ_OVERRIDE;
virtual void PostDelayedTask(Task* aTask, int aDelayMs) MOZ_OVERRIDE;
// No-ops
virtual void HandleDoubleTap(const CSSIntPoint& aPoint) MOZ_OVERRIDE {}
virtual void HandleSingleTap(const CSSIntPoint& aPoint) MOZ_OVERRIDE {}
virtual void HandleLongTap(const CSSIntPoint& aPoint) MOZ_OVERRIDE {}
virtual void SendAsyncScrollDOMEvent(bool aIsRoot,
const CSSRect &aContentRect,
const CSSSize &aScrollableSize) MOZ_OVERRIDE {}
};
}
}
#endif /*__mozilla_widget_DynamicToolbarController_h__ */

View File

@ -54,6 +54,7 @@ SOURCES += [
'nsWidgetFactory.cpp',
'nsWindow.cpp',
'OrientationObserver.cpp',
'ParentProcessController.cpp',
'ProcessOrientation.cpp'
]

View File

@ -44,6 +44,8 @@
#include "libdisplay/GonkDisplay.h"
#include "pixelflinger/format.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/layers/CompositorParent.h"
#include "ParentProcessController.h"
#include "HwcComposer2D.h"
@ -589,6 +591,10 @@ nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
if (sUsingOMTC) {
CreateCompositor();
if (mCompositorParent) {
uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId();
CompositorParent::SetControllerForLayerTree(rootLayerTreeId, new ParentProcessController());
}
if (mLayerManager)
return mLayerManager;
}