mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-16 13:56:29 +00:00
Bug 1267941 - Implement Storage API estimate() feature, r=janv,baku
This commit is contained in:
parent
4667ca7c1b
commit
ba9fa0d68a
@ -47,6 +47,7 @@
|
||||
#include "mozilla/dom/Permissions.h"
|
||||
#include "mozilla/dom/Presentation.h"
|
||||
#include "mozilla/dom/ServiceWorkerContainer.h"
|
||||
#include "mozilla/dom/StorageManager.h"
|
||||
#include "mozilla/dom/TCPSocket.h"
|
||||
#include "mozilla/dom/Telephony.h"
|
||||
#include "mozilla/dom/Voicemail.h"
|
||||
@ -232,6 +233,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTVManager)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputPortManager)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
|
||||
#ifdef MOZ_B2G_RIL
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
|
||||
#endif
|
||||
@ -276,6 +278,8 @@ Navigator::Invalidate()
|
||||
|
||||
mPermissions = nullptr;
|
||||
|
||||
mStorageManager = nullptr;
|
||||
|
||||
// If there is a page transition, make sure delete the geolocation object.
|
||||
if (mGeolocation) {
|
||||
mGeolocation->Shutdown();
|
||||
@ -658,6 +662,21 @@ Navigator::GetPermissions(ErrorResult& aRv)
|
||||
return mPermissions;
|
||||
}
|
||||
|
||||
StorageManager*
|
||||
Navigator::Storage()
|
||||
{
|
||||
MOZ_ASSERT(mWindow);
|
||||
|
||||
if(!mStorageManager) {
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
|
||||
MOZ_ASSERT(global);
|
||||
|
||||
mStorageManager = new StorageManager(global);
|
||||
}
|
||||
|
||||
return mStorageManager;
|
||||
}
|
||||
|
||||
// Values for the network.cookie.cookieBehavior pref are documented in
|
||||
// nsCookieService.cpp.
|
||||
#define COOKIE_BEHAVIOR_REJECT 2
|
||||
|
@ -101,6 +101,7 @@ class DeviceStorageAreaListener;
|
||||
class Presentation;
|
||||
class LegacyMozTCPSocket;
|
||||
class VRDisplay;
|
||||
class StorageManager;
|
||||
|
||||
namespace time {
|
||||
class TimeManager;
|
||||
@ -287,6 +288,8 @@ public:
|
||||
|
||||
bool MozE10sEnabled();
|
||||
|
||||
StorageManager* Storage();
|
||||
|
||||
static void GetAcceptLanguages(nsTArray<nsString>& aLanguages);
|
||||
|
||||
// WebIDL helper methods
|
||||
@ -377,6 +380,7 @@ private:
|
||||
#endif
|
||||
nsTArray<RefPtr<Promise> > mVRGetDisplaysPromises;
|
||||
nsTArray<uint32_t> mRequestedVibrationPattern;
|
||||
RefPtr<StorageManager> mStorageManager;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -43,6 +43,32 @@ function storageUsage() {
|
||||
});
|
||||
}
|
||||
|
||||
function groupUsage() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
navigator.storage.estimate().then(storageEstimation => {
|
||||
resolve(storageEstimation.usage, 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function workerGroupUsage() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
function workerScript() {
|
||||
navigator.storage.estimate().then(storageEstimation => {
|
||||
postMessage(storageEstimation.usage);
|
||||
});
|
||||
}
|
||||
|
||||
let url =
|
||||
URL.createObjectURL(new Blob(["(", workerScript.toSource(), ")()"]));
|
||||
|
||||
let worker = new Worker(url);
|
||||
worker.onmessage = function (e) {
|
||||
resolve(e.data, 0);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function resetStorage() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var qms = SpecialPowers.Services.qms;
|
||||
@ -142,6 +168,26 @@ SpecialPowers.pushPrefEnv({
|
||||
ok(fullUsage > initialUsage, 'disk usage should have grown');
|
||||
})
|
||||
|
||||
// Test groupUsage()
|
||||
.then(function() {
|
||||
return resetStorage();
|
||||
}).then(function() {
|
||||
return groupUsage();
|
||||
}).then(function(usage) {
|
||||
fullUsage = usage;
|
||||
ok(fullUsage > initialUsage, 'disk group usage should have grown');
|
||||
})
|
||||
|
||||
// Test workerGroupUsage()
|
||||
.then(function() {
|
||||
return resetStorage();
|
||||
}).then(function() {
|
||||
return workerGroupUsage();
|
||||
}).then(function(usage) {
|
||||
fullUsage = usage;
|
||||
ok(fullUsage > initialUsage, 'disk group usage on worker should have grown');
|
||||
})
|
||||
|
||||
// Now perform a new Cache operation that will reopen the origin. This
|
||||
// should clean up the orphaned body.
|
||||
.then(function() {
|
||||
|
@ -96,6 +96,7 @@ support-files =
|
||||
unit/test_setVersion_events.js
|
||||
unit/test_setVersion_exclusion.js
|
||||
unit/test_setVersion_throw.js
|
||||
unit/test_storage_manager_estimate.js
|
||||
unit/test_success_events_after_abort.js
|
||||
unit/test_table_locks.js
|
||||
unit/test_table_rollback.js
|
||||
@ -355,6 +356,8 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
||||
[test_setVersion_throw.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
||||
[test_storage_manager_estimate.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
||||
[test_success_events_after_abort.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
|
||||
[test_table_locks.html]
|
||||
|
19
dom/indexedDB/test/test_storage_manager_estimate.html
Normal file
19
dom/indexedDB/test/test_storage_manager_estimate.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Test for StorageManager</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7" src="unit/test_storage_manager_estimate.js"></script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
56
dom/indexedDB/test/unit/test_storage_manager_estimate.js
Normal file
56
dom/indexedDB/test/unit/test_storage_manager_estimate.js
Normal file
@ -0,0 +1,56 @@
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
const name = this.window ? window.location.pathname :
|
||||
"test_storage_manager_estimate.js";
|
||||
const objectStoreName = "storagesManager";
|
||||
const arraySize = 1e6;
|
||||
|
||||
ok('estimate' in navigator.storage, 'Has estimate function');
|
||||
is(typeof navigator.storage.estimate, 'function', 'estimate is function');
|
||||
ok(navigator.storage.estimate() instanceof Promise,
|
||||
'estimate() method exists and returns a Promise');
|
||||
|
||||
navigator.storage.estimate().then(estimation => {
|
||||
testGenerator.send(estimation.usage);
|
||||
});
|
||||
|
||||
let before = yield undefined;
|
||||
|
||||
let request = indexedDB.open(name, 1);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = grabEventAndContinueHandler;
|
||||
request.onsuccess = continueToNextStep;
|
||||
let event = yield undefined;
|
||||
|
||||
let db = event.target.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
let objectStore = db.createObjectStore(objectStoreName, { });
|
||||
yield undefined;
|
||||
|
||||
navigator.storage.estimate().then(estimation => {
|
||||
testGenerator.send(estimation.usage);
|
||||
});
|
||||
let usageAfterCreate = yield undefined;
|
||||
ok(usageAfterCreate > before, 'estimated usage must increase after createObjectStore');
|
||||
|
||||
let txn = db.transaction(objectStoreName, "readwrite");
|
||||
objectStore = txn.objectStore(objectStoreName);
|
||||
objectStore.put(new Uint8Array(arraySize), 'k');
|
||||
txn.oncomplete = continueToNextStep;
|
||||
txn.onabort = errorHandler;
|
||||
txn.onerror = errorHandler;
|
||||
event = yield undefined;
|
||||
|
||||
navigator.storage.estimate().then(estimation => {
|
||||
testGenerator.send(estimation.usage);
|
||||
});
|
||||
let usageAfterPut = yield undefined;
|
||||
ok(usageAfterPut > usageAfterCreate, 'estimated usage must increase after putting large object');
|
||||
db.close();
|
||||
|
||||
finishTest();
|
||||
yield undefined;
|
||||
}
|
@ -503,7 +503,6 @@ QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aCallback);
|
||||
MOZ_ASSERT(nsContentUtils::IsCallerChrome());
|
||||
|
||||
RefPtr<UsageRequest> request = new UsageRequest(aPrincipal, aCallback);
|
||||
|
||||
|
353
dom/quota/StorageManager.cpp
Normal file
353
dom/quota/StorageManager.cpp
Normal file
@ -0,0 +1,353 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "StorageManager.h"
|
||||
|
||||
#include "mozilla/dom/PromiseWorkerProxy.h"
|
||||
#include "mozilla/dom/quota/QuotaManagerService.h"
|
||||
#include "mozilla/dom/StorageManagerBinding.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsIQuotaCallbacks.h"
|
||||
#include "nsIQuotaRequests.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
using namespace mozilla::dom::workers;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
// This class is used to get quota usage callback.
|
||||
class EstimateResolver final
|
||||
: public nsIQuotaUsageCallback
|
||||
{
|
||||
class FinishWorkerRunnable;
|
||||
|
||||
// If this resolver was created for a window then mPromise must be non-null.
|
||||
// Otherwise mProxy must be non-null.
|
||||
RefPtr<Promise> mPromise;
|
||||
RefPtr<PromiseWorkerProxy> mProxy;
|
||||
|
||||
nsresult mResultCode;
|
||||
StorageEstimate mStorageEstimate;
|
||||
|
||||
public:
|
||||
explicit EstimateResolver(Promise* aPromise)
|
||||
: mPromise(aPromise)
|
||||
, mResultCode(NS_OK)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aPromise);
|
||||
}
|
||||
|
||||
explicit EstimateResolver(PromiseWorkerProxy* aProxy)
|
||||
: mProxy(aProxy)
|
||||
, mResultCode(NS_OK)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aProxy);
|
||||
}
|
||||
|
||||
void
|
||||
ResolveOrReject(Promise* aPromise);
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
NS_DECL_NSIQUOTAUSAGECALLBACK
|
||||
|
||||
private:
|
||||
~EstimateResolver()
|
||||
{ }
|
||||
};
|
||||
|
||||
// This class is used to return promise on worker thread.
|
||||
class EstimateResolver::FinishWorkerRunnable final
|
||||
: public WorkerRunnable
|
||||
{
|
||||
RefPtr<EstimateResolver> mResolver;
|
||||
|
||||
public:
|
||||
explicit FinishWorkerRunnable(EstimateResolver* aResolver)
|
||||
: WorkerRunnable(aResolver->mProxy->GetWorkerPrivate())
|
||||
, mResolver(aResolver)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aResolver);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
|
||||
};
|
||||
|
||||
class EstimateWorkerMainThreadRunnable
|
||||
: public WorkerMainThreadRunnable
|
||||
{
|
||||
RefPtr<PromiseWorkerProxy> mProxy;
|
||||
|
||||
public:
|
||||
EstimateWorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
PromiseWorkerProxy* aProxy)
|
||||
: WorkerMainThreadRunnable(aWorkerPrivate,
|
||||
NS_LITERAL_CSTRING("StorageManager :: Estimate"))
|
||||
, mProxy(aProxy)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(aProxy);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
MainThreadRun() override;
|
||||
};
|
||||
|
||||
nsresult
|
||||
GetUsageForPrincipal(nsIPrincipal* aPrincipal,
|
||||
nsIQuotaUsageCallback* aCallback,
|
||||
nsIQuotaUsageRequest** aRequest)
|
||||
{
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aCallback);
|
||||
MOZ_ASSERT(aRequest);
|
||||
|
||||
nsCOMPtr<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate();
|
||||
if (NS_WARN_IF(!qms)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = qms->GetUsageForPrincipal(aPrincipal, aCallback, true, aRequest);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
};
|
||||
|
||||
nsresult
|
||||
GetStorageEstimate(nsIQuotaUsageRequest* aRequest,
|
||||
StorageEstimate& aStorageEstimate)
|
||||
{
|
||||
MOZ_ASSERT(aRequest);
|
||||
|
||||
uint64_t usage;
|
||||
nsresult rv = aRequest->GetUsage(&usage);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint64_t limit;
|
||||
rv = aRequest->GetLimit(&limit);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
aStorageEstimate.mUsage.Construct() = usage;
|
||||
aStorageEstimate.mQuota.Construct() = limit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/*******************************************************************************
|
||||
* Local class implementations
|
||||
******************************************************************************/
|
||||
|
||||
void
|
||||
EstimateResolver::ResolveOrReject(Promise* aPromise)
|
||||
{
|
||||
MOZ_ASSERT(aPromise);
|
||||
|
||||
if (NS_SUCCEEDED(mResultCode)) {
|
||||
aPromise->MaybeResolve(mStorageEstimate);
|
||||
} else {
|
||||
aPromise->MaybeReject(mResultCode);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(EstimateResolver, nsIQuotaUsageCallback)
|
||||
|
||||
NS_IMETHODIMP
|
||||
EstimateResolver::OnUsageResult(nsIQuotaUsageRequest *aRequest)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aRequest);
|
||||
|
||||
nsresult rv = aRequest->GetResultCode(&mResultCode);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mResultCode = rv;
|
||||
} else if (NS_SUCCEEDED(mResultCode)) {
|
||||
rv = GetStorageEstimate(aRequest, mStorageEstimate);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mResultCode = rv;
|
||||
}
|
||||
}
|
||||
|
||||
// In a main thread request.
|
||||
if (!mProxy) {
|
||||
MOZ_ASSERT(mPromise);
|
||||
|
||||
ResolveOrReject(mPromise);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// In a worker thread request.
|
||||
MutexAutoLock lock(mProxy->Lock());
|
||||
|
||||
if (NS_WARN_IF(mProxy->CleanedUp())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<FinishWorkerRunnable> runnable = new FinishWorkerRunnable(this);
|
||||
if (NS_WARN_IF(!runnable->Dispatch())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
EstimateResolver::
|
||||
FinishWorkerRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
RefPtr<PromiseWorkerProxy> proxy = mResolver->mProxy;
|
||||
MOZ_ASSERT(proxy);
|
||||
|
||||
RefPtr<Promise> promise = proxy->WorkerPromise();
|
||||
MOZ_ASSERT(promise);
|
||||
|
||||
mResolver->ResolveOrReject(promise);
|
||||
|
||||
proxy->CleanUp();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
EstimateWorkerMainThreadRunnable::MainThreadRun()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mProxy->Lock());
|
||||
if (mProxy->CleanedUp()) {
|
||||
return true;
|
||||
}
|
||||
principal = mProxy->GetWorkerPrivate()->GetPrincipal();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(principal);
|
||||
|
||||
RefPtr<EstimateResolver> resolver = new EstimateResolver(mProxy);
|
||||
|
||||
RefPtr<nsIQuotaUsageRequest> request;
|
||||
nsresult rv =
|
||||
GetUsageForPrincipal(principal, resolver, getter_AddRefs(request));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* StorageManager
|
||||
******************************************************************************/
|
||||
|
||||
StorageManager::StorageManager(nsIGlobalObject* aGlobal)
|
||||
: mOwner(aGlobal)
|
||||
{
|
||||
MOZ_ASSERT(aGlobal);
|
||||
}
|
||||
|
||||
StorageManager::~StorageManager()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
StorageManager::Estimate(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(mOwner);
|
||||
|
||||
RefPtr<Promise> promise = Promise::Create(mOwner, aRv);
|
||||
if (NS_WARN_IF(!promise)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mOwner);
|
||||
if (NS_WARN_IF(!window)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
|
||||
if (NS_WARN_IF(!doc)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
|
||||
MOZ_ASSERT(principal);
|
||||
|
||||
RefPtr<EstimateResolver> resolver = new EstimateResolver(promise);
|
||||
|
||||
RefPtr<nsIQuotaUsageRequest> request;
|
||||
nsresult rv =
|
||||
GetUsageForPrincipal(principal, resolver, getter_AddRefs(request));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
RefPtr<PromiseWorkerProxy> promiseProxy =
|
||||
PromiseWorkerProxy::Create(workerPrivate, promise);
|
||||
if (NS_WARN_IF(!promiseProxy)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<EstimateWorkerMainThreadRunnable> runnnable =
|
||||
new EstimateWorkerMainThreadRunnable(promiseProxy->GetWorkerPrivate(),
|
||||
promiseProxy);
|
||||
|
||||
runnnable->Dispatch(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(StorageManager, mOwner)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(StorageManager)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(StorageManager)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StorageManager)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
JSObject*
|
||||
StorageManager::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return StorageManagerBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
55
dom/quota/StorageManager.h
Normal file
55
dom/quota/StorageManager.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_StorageManager_h
|
||||
#define mozilla_dom_StorageManager_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Promise;
|
||||
struct StorageEstimate;
|
||||
|
||||
class StorageManager final
|
||||
: public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> mOwner;
|
||||
|
||||
public:
|
||||
explicit
|
||||
StorageManager(nsIGlobalObject* aGlobal);
|
||||
|
||||
nsIGlobalObject*
|
||||
GetParentObject() const
|
||||
{
|
||||
return mOwner;
|
||||
}
|
||||
|
||||
// WebIDL
|
||||
already_AddRefed<Promise>
|
||||
Estimate(ErrorResult& aRv);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StorageManager)
|
||||
|
||||
// nsWrapperCache
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
private:
|
||||
~StorageManager();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_StorageManager_h
|
@ -12,6 +12,10 @@ XPIDL_SOURCES += [
|
||||
|
||||
XPIDL_MODULE = 'dom_quota'
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'StorageManager.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom.quota += [
|
||||
'ActorsParent.h',
|
||||
'Client.h',
|
||||
@ -32,6 +36,7 @@ UNIFIED_SOURCES += [
|
||||
'FileStreams.cpp',
|
||||
'QuotaManagerService.cpp',
|
||||
'QuotaRequests.cpp',
|
||||
'StorageManager.cpp',
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
@ -44,6 +49,7 @@ include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
LOCAL_INCLUDES += [
|
||||
'../workers',
|
||||
'/caps',
|
||||
]
|
||||
|
||||
|
@ -1069,6 +1069,8 @@ var interfaceNamesInGlobalScope =
|
||||
"Storage",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"StorageEvent",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"StorageManager",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"StyleSheet",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -30,6 +30,7 @@ Navigator implements NavigatorOnLine;
|
||||
Navigator implements NavigatorContentUtils;
|
||||
Navigator implements NavigatorStorageUtils;
|
||||
Navigator implements NavigatorConcurrentHardware;
|
||||
Navigator implements NavigatorStorage;
|
||||
|
||||
[NoInterfaceObject, Exposed=(Window,Worker)]
|
||||
interface NavigatorID {
|
||||
@ -85,6 +86,11 @@ interface NavigatorContentUtils {
|
||||
//void unregisterContentHandler(DOMString mimeType, DOMString url);
|
||||
};
|
||||
|
||||
[NoInterfaceObject, Exposed=(Window,Worker)]
|
||||
interface NavigatorStorage {
|
||||
readonly attribute StorageManager storage;
|
||||
};
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface NavigatorStorageUtils {
|
||||
// NOT IMPLEMENTED
|
||||
|
24
dom/webidl/StorageManager.webidl
Normal file
24
dom/webidl/StorageManager.webidl
Normal file
@ -0,0 +1,24 @@
|
||||
/* -*- Mode: IDL; 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://storage.spec.whatwg.org/#storagemanager
|
||||
*
|
||||
*/
|
||||
|
||||
[Exposed=(Window,Worker)]
|
||||
interface StorageManager {
|
||||
// [Throws]
|
||||
// Promise<boolean> persisted();
|
||||
// [Throws]
|
||||
// [Exposed=Window] Promise<boolean> persist();
|
||||
[Throws]
|
||||
Promise<StorageEstimate> estimate();
|
||||
};
|
||||
|
||||
dictionary StorageEstimate {
|
||||
unsigned long long usage;
|
||||
unsigned long long quota;
|
||||
};
|
@ -11,3 +11,4 @@ WorkerNavigator implements NavigatorID;
|
||||
WorkerNavigator implements NavigatorLanguage;
|
||||
WorkerNavigator implements NavigatorOnLine;
|
||||
WorkerNavigator implements NavigatorConcurrentHardware;
|
||||
WorkerNavigator implements NavigatorStorage;
|
||||
|
@ -433,6 +433,7 @@ WEBIDL_FILES = [
|
||||
'StereoPannerNode.webidl',
|
||||
'Storage.webidl',
|
||||
'StorageEvent.webidl',
|
||||
'StorageManager.webidl',
|
||||
'StorageType.webidl',
|
||||
'StyleSheet.webidl',
|
||||
'StyleSheetList.webidl',
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseWorkerProxy.h"
|
||||
#include "mozilla/dom/StorageManager.h"
|
||||
#include "mozilla/dom/WorkerNavigator.h"
|
||||
#include "mozilla/dom/WorkerNavigatorBinding.h"
|
||||
|
||||
@ -26,8 +27,7 @@ namespace dom {
|
||||
|
||||
using namespace mozilla::dom::workers;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerNavigator)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WorkerNavigator, mStorageManager);
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WorkerNavigator, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WorkerNavigator, Release)
|
||||
|
||||
@ -164,5 +164,21 @@ WorkerNavigator::HardwareConcurrency() const
|
||||
return rts->ClampedHardwareConcurrency();
|
||||
}
|
||||
|
||||
StorageManager*
|
||||
WorkerNavigator::Storage()
|
||||
{
|
||||
if (!mStorageManager) {
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
RefPtr<nsIGlobalObject> global = workerPrivate->GlobalScope();
|
||||
MOZ_ASSERT(global);
|
||||
|
||||
mStorageManager = new StorageManager(global);
|
||||
}
|
||||
|
||||
return mStorageManager;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -15,12 +15,14 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Promise;
|
||||
class StorageManager;
|
||||
|
||||
class WorkerNavigator final : public nsWrapperCache
|
||||
{
|
||||
typedef struct workers::RuntimeService::NavigatorProperties NavigatorProperties;
|
||||
|
||||
NavigatorProperties mProperties;
|
||||
RefPtr<StorageManager> mStorageManager;
|
||||
bool mOnline;
|
||||
|
||||
WorkerNavigator(const NavigatorProperties& aProperties,
|
||||
@ -101,6 +103,8 @@ public:
|
||||
void SetLanguages(const nsTArray<nsString>& aLanguages);
|
||||
|
||||
uint64_t HardwareConcurrency() const;
|
||||
|
||||
StorageManager* Storage();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -15,6 +15,7 @@ var supportedProps = [
|
||||
"language",
|
||||
"languages",
|
||||
"hardwareConcurrency",
|
||||
"storage"
|
||||
];
|
||||
|
||||
self.onmessage = function(event) {
|
||||
|
@ -98,6 +98,19 @@ function workerTestGetIsB2G(cb) {
|
||||
});
|
||||
}
|
||||
|
||||
function workerTestGetStorageManager(cb) {
|
||||
addEventListener('message', function workerTestGetStorageManagerCB(e) {
|
||||
if (e.data.type !== 'returnStorageManager') {
|
||||
return;
|
||||
}
|
||||
removeEventListener('message', workerTestGetStorageManagerCB);
|
||||
cb(e.data.result);
|
||||
});
|
||||
client.postMessage({
|
||||
type: 'getStorageManager'
|
||||
});
|
||||
}
|
||||
|
||||
addEventListener('message', function workerWrapperOnMessage(e) {
|
||||
removeEventListener('message', workerWrapperOnMessage);
|
||||
var data = e.data;
|
||||
|
@ -195,6 +195,8 @@ var interfaceNamesInGlobalScope =
|
||||
"ServiceWorkerGlobalScope",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"ServiceWorkerRegistration",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"StorageManager",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"SubtleCrypto",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
@ -40,6 +40,11 @@ Tests of DOM Worker Navigator
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.name === "storage") {
|
||||
is(typeof navigator.storage, typeof args.value, "storage type matches");
|
||||
return;
|
||||
}
|
||||
|
||||
is(navigator[args.name], args.value,
|
||||
"Mismatched navigator string for " + args.name + "!");
|
||||
};
|
||||
|
@ -179,6 +179,8 @@ var interfaceNamesInGlobalScope =
|
||||
"Response",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{ name: "ServiceWorkerRegistration", b2g: false },
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"StorageManager",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
"SubtleCrypto",
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
Loading…
x
Reference in New Issue
Block a user