mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 05:37:11 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1246051 - have MediaQueue<T>::Peek/PeekFront return a RefPtr<> to avoid dangling pointers per comment 0. r=gerald. (00f334efb1) - Bug 1264199: P1. Perform audio conversion in the MSDM taskqueue and ahead of use. r=kinetik (001936e3ea) - Bug 1267983 - include MediaQueue.h; r=jwwang (036107d765) - Bug 1264199: P0. Fix nsDequeue/MediaQueue methods constness. r=jwwang (9aa33dfcb5) - Bug 1264199: P0.1. Export SaferMultDiv method. r=gerald (0b7a35ae4d) - Bug 1264199: P2. Ensure the AudioStream only ever receive the same content format. r=kinetik (a180d09279) - Bug 1264199: P3. Attempt to minimize audio quality loss and unnecessary processing. r=kinetik (29d57b5a33) - Bug 1264199: P4. Add mono to stereo upmix to AudioConverter. r=rillian (49c029bd86) - Bug 1264199: P5. Perform all downmixing operations in DecodedAudioDataSink. r=kinetik (05a479f095) - Bug 1264199: P6. Drain resampler when changing format or reaching the end. r=kinetik (8639102a94) - Bug 1264199: P8. Handle potential resampling errors. r=kinetik (1267e4e73d) - Bug 1264199: P9. Include pending frames in HasUnplayedFrames calculation. r=jwwang (ce7097fc90) - Bug 1263496 - Part 1: fix for @mozilla.org/nullprincipal;1 r=bholley (c4c462a1bc) - Bug 1263496 - Part 2: fix for NS_NULLPRINCIPAL_CONTRACTID. r=bholley (c1504240ec) - Bug 1263496 - Part 3: fix for nsNullPrincipal::Create (0196a5a3ce) - Bug 1261009 - Remove the Data Store API, r=fabrice (b22e580107) - Bug 1261405 - Rename PushPermissionDescriptor.userVisible to `userVisibleOnly`. r=baku (4de70267cc) - Bug 1266821 - Remove PushPermissionDescriptor from the Permissions API. r=baku (196cd83442) - Bug 1268393 - Some compilation issues in ServiceWorker code, r=ehsan (d9c2f2554b) - Merge branch 'dev' of https://github.com/rmottola/Arctic-Fox into dev (6f6c606911) - Bug 1267733 P1 Treat last-update-time as infinitely in the past when checking for service worker update after restart. r=jdm (255da0a9e2) - Bug 1209095 - Accept opaqueredirection fetch results if the request redirection type is manual. r=bkelly (6fe92d1368) - Bug 1267733 P2 Pass ServiceWorkerRegistrationInfo down to CancelChannelRunnable. r=jdm (0ec51f09ef) - Bug 1267733 P3 Trigger service worker update after failed interception. r=jdm (f89a7998d4) - Bug 1267733 P4 Add a wpt test that verifies a service worker update can recover from a broken navigation interception. r=jdm (9dc0ce97bd) - Bug 1267691: Assert on failed attempts to shutdown a thread from itself r=froyd (0cbd1e458c) - Bug 1180533 - Disable BackgroundHangMonitor on gonk (a2d666e741) - Bug 1121216 - disable BackgroundHangMonitor for TSan builds; r=jchen (ef15d1016f) - Bug 1265621 - Use StaticRefPtr in Omnijar.cpp; r=froydnj (81bc32836e) - Bug 1265621 - Expose outer zip readers in Omnijar::GetReader; r=froydnj (ce3f82929e) - Bug 1267021 - Use fallible allocation and move semantics for Push events. r=wchen (3a1ae23d8d) - Bug 1222899 - Handle geolocation-device-events callback. r=kchen (a33bcf4297) - Bug 1237831 - Update GonkGPSGeolocationProvider.cpp to use B2G-style. r=jst (d389eedf47) - Bug 1245033 - Build break in dom/system/gonk/GonkGPSGeolocationProvider.cpp:541:126: error: format '%d' expects argument of type 'int', but argument 5 has type 'nsresult'. r=fabrice (ecde789edf) - Bug 1264287: Convert Wifi to use |UniquePtr|, r=nfroyd (9bad7792bf) - Bug 1267577 - Move nsRunnable to mozilla::Runnable. r=gsvelto (f58e2161f2) - Bug 1210370 - Close wpa_supplicant before we shutdown nsIWifiProxyService. r=mrbkap (5cd4dce58f) - Bug 1218629 - Save audio volume for each device to setting db r=alwu (2f1847dd6f) - Bug 1249437 - Remove workaround of volume control r=alwu (13cd144a89) - Bug 1268432: Replace |Task| with |Runnable| in B2G code r=fabrice (bcc768e9cb) - Bug 1226483 - Add ASSERT check to AudioManager::SelectDeviceFromDevices() r=alwu (446e8f634e) - Bug 1229234 - Enable audio_is_output_device() on ICS r=alwu (84aae07f23) - Bug 1267369 - Only generate typelib data for scriptable interfaces; r=khuey (e49b44c9ce) - Bug 1155969 - Make runtests.py flake8 compliant. r=ted (1de456b206) - Bug 1266569 - Avoid including the ChromeUtils binding in Base64.h. r=froydnj (7ba39a7687) - Bug 1267568 part 1 - Add a weak ptr to nsGlobalChromeWindow to remember the pres shell we set the fullscreen change flag. r=smaug (83995d5296) - Bug 1267568 part 2 - Add helper method to nsIPresShell to get the RefreshDriver. r=smaug (c60589fb40) - Bug 1267568 part 3 - Use an individual method for check whether resize should be delayed. r=smaug (f0ab5156d1) - Bug 1267568 part 4 - Replace InFullscreenChange flag of PresShell with IsResizeSuppressed flag in RefreshDriver. r=smaug (0a54f5a08b) - Bug 1267568 part 5 - Replace the old FullscreenChangePrepare class with a single function. r=smaug (4196e82852) - Bug 1267568 part 6 - Send fullscreen message before triggering any potential reflow. r=dao (fe9133ca2d) - Bug 1243352 - attribute a value for ProxyHandlerInfo::mPrefAction in ProxyHandlerInfo::SetPreferredAction. r=blassey (577c23e4cb) - Bug 1266433 - Send Push observer notifications to parent and content processes. f=janx r=dragana (768c173c2c) - Bug 1267493 - Replace isURIPotentiallyTrustworthy usage in Push with a testing pref. r=dragana (96434b90d9) - Bug 1266433 - Send an observer notification when a push subscription is lost. f=janx r=dragana (a7c7277e02) - Bug 1247685 - Send subscription keys to the Push server. r=mt (651fc0cad3) - Bug 1266540 - Stub out Push error reporting for the GCM and H2 backends. r=wchen (fd00c311aa) - Bug 1266623 - Up/down mix WASAPI capture streams when stream formats don't match. r=padenot (ca92ec20ab) - Bug 1267930 - When the wasapi rendering loop is stuck and we're shuttin down, leak the thread and continue the shutdown process. r=kinetik (04419ad94d) - Bug 1269692 - Update cubeb to revision 17e3048d0afa1152776fb1867cdb61c49fae69e4. (3de098f4bb) - Bug 1251502 - Update cubeb's udpate.sh script to account for new files. r=kinetik (a3ae5f27c1) - Bug 1243234 - Hide MP4Metadata behind an impl pointer. r=giles (1543bedf28) - Bug 1243234 - Update rust mp4parse telemetry reporting. r=kinetik (bb5c999c06) - Bug 1242807 - Fix mp4parse-rust's error reporting via telemetry. r=giles (a3ca1b133b) - Bug 1243234 - Move mp4parse-rust code into MP4MetadataRust impl. r=giles (ec4d6bcf0e) - Bug 1243234 - Remove now-unnecessary StagefrightPrivate wrapper. r=giles (1e2c54232b) - Bug 1243234 - Move mp4parse-rust initialization into constructor and clean up try_rust. r=giles (291c01f45a) - Bug 1243234 - Update rust mp4parse to v0.2.1. r=kinetik (d2774346cd) - Bug 1264622: [MP4] Resync stagefright's updateAudioTrackInfoFromESDS_MPEG4Audio with upstream. r=kentuckyfriedtakahe (b4b596507b) - Bug 1254721: Ensure consistency between Cenc offsets and sizes table. r=gerald (59bd7122d1) - Bug 1151202 - libstagefright: Fix compilation for systems without <sys/cdefs.h>. r=cpearce (e219658c31) - Bug 1255866 - stagefright: Fix unused variable warnings. r=ajones (62afc26384) - Bug 1251821: increase UDP socket send buffer on Win 7 r=jdm,jesup (e0d6e545f4) - Bug 929977: Add support for RFC 7675 ICE consent freshness. r=bwc,mt (ea8a565a65) - Bug 1231981 - Part 1: Very basic test TURN server for running in CI. r=ahal,drno (c98a79810b) - Bug 1231981 - Part 2: A websocket-to-process bridge script that can be used by JS to launch an ICE server for testing. r=ahal (5bdb00dfd1) - Bug 1231981 - Part 2.1: Only run the websocket/process bridge for media tests. r=ahal (86f97e2eb6) - Bug 1225729: Whitelist specific bad RTCP timestamp value r=drno (f0c8402fd0) - Bug 1193045 - Check selected attribute for all calls. r=bwc (7eb4095c34) - Bug 1213056 - update tests to use maplike getStats. r=bwc (d27f997290) - Bug 1231981 - Part 3: Set up TURN server for webrtc mochitests, when configured to. r=drno (38e4455eec) - Bug 1231975 - Part 1: Basic audio mochitests for NAT scenarios. r=drno (16efaf581e) - Bug 1231975 - Part 2: Break a reference cycle between NrTcpSocketIpc and TCPSocketChild, in the same manner as the UDP case. r=mcmanus (1fa55e3e5f)
This commit is contained in:
@@ -914,13 +914,6 @@ pref("network.sntp.pools", // Servers separated by ';'.
|
||||
pref("network.sntp.port", 123);
|
||||
pref("network.sntp.timeout", 30); // In seconds.
|
||||
|
||||
// Enable dataStore
|
||||
pref("dom.datastore.enabled", true);
|
||||
// When an entry is changed, use two timers to fire system messages in a more
|
||||
// moderate pattern.
|
||||
pref("dom.datastore.sysMsgOnChangeShortTimeoutSec", 10);
|
||||
pref("dom.datastore.sysMsgOnChangeLongTimeoutSec", 60);
|
||||
|
||||
// DOM Inter-App Communication API.
|
||||
pref("dom.inter-app-communication-api.enabled", true);
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
window.performance.mark('gecko-shell-loadstart');
|
||||
|
||||
Cu.import('resource://gre/modules/ContactService.jsm');
|
||||
Cu.import('resource://gre/modules/DataStoreChangeNotifier.jsm');
|
||||
Cu.import('resource://gre/modules/AlarmService.jsm');
|
||||
Cu.import('resource://gre/modules/ActivitiesService.jsm');
|
||||
Cu.import('resource://gre/modules/NotificationDB.jsm');
|
||||
@@ -1138,22 +1137,50 @@ window.addEventListener('ContentStart', function update_onContentStart() {
|
||||
|
||||
updatePrompt.wrappedJSObject.handleContentStart(shell);
|
||||
});
|
||||
/* The "GPSChipOn" is to indicate that GPS engine is turned ON by the modem.
|
||||
During this GPS engine is turned ON by the modem, we make the location tracking icon visible to user.
|
||||
Once GPS engine is turned OFF, the location icon will disappear.
|
||||
If GPS engine is not turned ON by the modem or GPS location service is triggered,
|
||||
we let GPS service take over the control of showing the location tracking icon.
|
||||
The regular sequence of the geolocation-device-events is: starting-> GPSStarting-> shutdown-> GPSShutdown
|
||||
*/
|
||||
|
||||
|
||||
(function geolocationStatusTracker() {
|
||||
let gGeolocationActive = false;
|
||||
let GPSChipOn = false;
|
||||
|
||||
Services.obs.addObserver(function(aSubject, aTopic, aData) {
|
||||
let oldState = gGeolocationActive;
|
||||
if (aData == "starting") {
|
||||
gGeolocationActive = true;
|
||||
} else if (aData == "shutdown") {
|
||||
gGeolocationActive = false;
|
||||
let promptWarning = false;
|
||||
switch (aData) {
|
||||
case "GPSStarting":
|
||||
if (!gGeolocationActive) {
|
||||
gGeolocationActive = true;
|
||||
GPSChipOn = true;
|
||||
promptWarning = true;
|
||||
}
|
||||
break;
|
||||
case "GPSShutdown":
|
||||
if (GPSChipOn) {
|
||||
gGeolocationActive = false;
|
||||
GPSChipOn = false;
|
||||
}
|
||||
break;
|
||||
case "starting":
|
||||
gGeolocationActive = true;
|
||||
GPSChipOn = false;
|
||||
break;
|
||||
case "shutdown":
|
||||
gGeolocationActive = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gGeolocationActive != oldState) {
|
||||
shell.sendChromeEvent({
|
||||
type: 'geolocation-status',
|
||||
active: gGeolocationActive
|
||||
active: gGeolocationActive,
|
||||
prompt: promptWarning
|
||||
});
|
||||
}
|
||||
}, "geolocation-device-events", false);
|
||||
|
||||
@@ -938,10 +938,6 @@ bin/libfreebl_32int64_3.so
|
||||
@RESPATH@/components/FxAccountsUIGlue.js
|
||||
@RESPATH@/components/services_fxaccounts.xpt
|
||||
|
||||
@RESPATH@/components/DataStore.manifest
|
||||
@RESPATH@/components/DataStoreImpl.js
|
||||
@RESPATH@/components/dom_datastore.xpt
|
||||
|
||||
@RESPATH@/components/MobileIdentity.manifest
|
||||
@RESPATH@/components/MobileIdentity.js
|
||||
@RESPATH@/components/dom_mobileidentity.xpt
|
||||
|
||||
@@ -131,22 +131,7 @@ var FullScreen = {
|
||||
let topWin = event.target.ownerDocument.defaultView.top;
|
||||
browser = gBrowser.getBrowserForContentWindow(topWin);
|
||||
}
|
||||
if (!browser || !this.enterDomFullscreen(browser)) {
|
||||
if (document.fullscreenElement) {
|
||||
// MozDOMFullscreen:Entered is dispatched synchronously in
|
||||
// fullscreen change, hence we have to avoid calling this
|
||||
// method synchronously here.
|
||||
setTimeout(() => document.exitFullscreen(), 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// If it is a remote browser, send a message to ask the content
|
||||
// to enter fullscreen state. We don't need to do so if it is an
|
||||
// in-process browser, since all related document should have
|
||||
// entered fullscreen state at this point.
|
||||
if (this._isRemoteBrowser(browser)) {
|
||||
browser.messageManager.sendAsyncMessage("DOMFullscreen:Entered");
|
||||
}
|
||||
this.enterDomFullscreen(browser);
|
||||
break;
|
||||
}
|
||||
case "MozDOMFullscreen:Exited":
|
||||
@@ -178,22 +163,30 @@ var FullScreen = {
|
||||
},
|
||||
|
||||
enterDomFullscreen : function(aBrowser) {
|
||||
if (!document.fullscreenElement)
|
||||
return false;
|
||||
if (!document.fullscreenElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we've received a fullscreen notification, we have to ensure that the
|
||||
// element that's requesting fullscreen belongs to the browser that's currently
|
||||
// active. If not, we exit fullscreen since the "full-screen document" isn't
|
||||
// actually visible now.
|
||||
if (gBrowser.selectedBrowser != aBrowser) {
|
||||
return false;
|
||||
if (!aBrowser || gBrowser.selectedBrowser != aBrowser ||
|
||||
// The top-level window has lost focus since the request to enter
|
||||
// full-screen was made. Cancel full-screen.
|
||||
Services.focus.activeWindow != window) {
|
||||
// This function is called synchronously in fullscreen change, so
|
||||
// we have to avoid calling exitFullscreen synchronously here.
|
||||
setTimeout(() => document.exitFullscreen(), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
let focusManager = Services.focus;
|
||||
if (focusManager.activeWindow != window) {
|
||||
// The top-level window has lost focus since the request to enter
|
||||
// full-screen was made. Cancel full-screen.
|
||||
return false;
|
||||
// If it is a remote browser, send a message to ask the content
|
||||
// to enter fullscreen state. We don't need to do so if it is an
|
||||
// in-process browser, since all related document should have
|
||||
// entered fullscreen state at this point.
|
||||
if (this._isRemoteBrowser(aBrowser)) {
|
||||
aBrowser.messageManager.sendAsyncMessage("DOMFullscreen:Entered");
|
||||
}
|
||||
|
||||
document.documentElement.setAttribute("inDOMFullscreen", true);
|
||||
@@ -210,8 +203,6 @@ var FullScreen = {
|
||||
// If a fullscreen window loses focus, we show a warning when the
|
||||
// fullscreen window is refocused.
|
||||
window.addEventListener("activate", this);
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
cleanup: function () {
|
||||
@@ -224,6 +215,9 @@ var FullScreen = {
|
||||
},
|
||||
|
||||
cleanupDomFullscreen: function () {
|
||||
window.messageManager
|
||||
.broadcastAsyncMessage("DOMFullscreen:CleanUp");
|
||||
|
||||
this._WarningBox.close();
|
||||
gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen);
|
||||
gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen);
|
||||
@@ -231,9 +225,6 @@ var FullScreen = {
|
||||
window.removeEventListener("activate", this);
|
||||
|
||||
document.documentElement.removeAttribute("inDOMFullscreen");
|
||||
|
||||
window.messageManager
|
||||
.broadcastAsyncMessage("DOMFullscreen:CleanUp");
|
||||
},
|
||||
|
||||
_isRemoteBrowser: function (aBrowser) {
|
||||
|
||||
@@ -887,12 +887,16 @@ FeedWriter.prototype = {
|
||||
* The window of the document invoking the BrowserFeedWriter
|
||||
*/
|
||||
_getOriginalURI(aWindow) {
|
||||
let chan = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIWebNavigation).
|
||||
QueryInterface(Ci.nsIDocShell).currentDocumentChannel;
|
||||
let docShell = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
let chan = docShell.currentDocumentChannel;
|
||||
|
||||
let nullPrincipal = Cc["@mozilla.org/nullprincipal;1"].
|
||||
createInstance(Ci.nsIPrincipal);
|
||||
// We probably need to call InheritFromDocShellToDoc for this, but right now
|
||||
// we can't call it from JS.
|
||||
let attrs = docShell.getOriginAttributes();
|
||||
let ssm = Services.scriptSecurityManager;
|
||||
let nullPrincipal = ssm.createNullPrincipal(attrs);
|
||||
|
||||
let resolvedURI = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService).
|
||||
@@ -1185,13 +1189,19 @@ FeedWriter.prototype = {
|
||||
}
|
||||
let faviconURI = makeURI(readerURI.prePath + "/favicon.ico");
|
||||
let self = this;
|
||||
let usePrivateBrowsing = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.QueryInterface(Ci.nsILoadContext)
|
||||
.usePrivateBrowsing;
|
||||
let nullPrincipal = Cc["@mozilla.org/nullprincipal;1"]
|
||||
.createInstance(Ci.nsIPrincipal);
|
||||
|
||||
let docShell = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
let usePrivateBrowsing = docShell.QueryInterface(Ci.nsILoadContext)
|
||||
.usePrivateBrowsing;
|
||||
|
||||
// We probably need to call InheritFromDocShellToDoc for this, but right now
|
||||
// we can't call it from JS.
|
||||
let attrs = docShell.getOriginAttributes();
|
||||
let ssm = Services.scriptSecurityManager;
|
||||
let nullPrincipal = ssm.createNullPrincipal(attrs);
|
||||
|
||||
this._faviconService.setAndFetchFaviconForPage(readerURI, faviconURI, false,
|
||||
usePrivateBrowsing ? this._faviconService.FAVICON_LOAD_PRIVATE
|
||||
: this._faviconService.FAVICON_LOAD_NON_PRIVATE,
|
||||
|
||||
@@ -1720,13 +1720,14 @@ Experiments.ExperimentEntry.prototype = {
|
||||
_runFilterFunction: Task.async(function* (jsfilter) {
|
||||
this._log.trace("runFilterFunction() - filter: " + jsfilter);
|
||||
|
||||
const nullprincipal = Cc["@mozilla.org/nullprincipal;1"].createInstance(Ci.nsIPrincipal);
|
||||
let ssm = Services.scriptSecurityManager;
|
||||
const nullPrincipal = ssm.createNullPrincipal({});
|
||||
let options = {
|
||||
sandboxName: "telemetry experiments jsfilter sandbox",
|
||||
wantComponents: false,
|
||||
};
|
||||
|
||||
let sandbox = Cu.Sandbox(nullprincipal, options);
|
||||
let sandbox = Cu.Sandbox(nullPrincipal, options);
|
||||
try {
|
||||
Cu.evalInSandbox(jsfilter, sandbox);
|
||||
} catch (e) {
|
||||
|
||||
@@ -838,10 +838,6 @@ bin/libfreebl_32int64_3.so
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@RESPATH@/components/DataStore.manifest
|
||||
@RESPATH@/components/DataStoreImpl.js
|
||||
@RESPATH@/components/dom_datastore.xpt
|
||||
|
||||
@RESPATH@/components/dom_audiochannel.xpt
|
||||
|
||||
; Shutdown Terminator
|
||||
|
||||
@@ -553,7 +553,7 @@ BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI, const PrincipalOriginAttrib
|
||||
&inheritsPrincipal);
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
if (NS_FAILED(rv) || inheritsPrincipal) {
|
||||
return nsNullPrincipal::Create();
|
||||
return nsNullPrincipal::Create(aAttrs);
|
||||
}
|
||||
|
||||
// Check whether the URI knows what its principal is supposed to be.
|
||||
@@ -562,7 +562,7 @@ BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI, const PrincipalOriginAttrib
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
uriPrinc->GetPrincipal(getter_AddRefs(principal));
|
||||
if (!principal) {
|
||||
return nsNullPrincipal::Create();
|
||||
return nsNullPrincipal::Create(aAttrs);
|
||||
}
|
||||
RefPtr<BasePrincipal> concrete = Cast(principal);
|
||||
return concrete.forget();
|
||||
|
||||
+54
-25
@@ -123,6 +123,32 @@ nsJSPrincipals::ReadPrincipals(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||
return ReadKnownPrincipalType(aCx, aReader, tag, aOutPrincipals);
|
||||
}
|
||||
|
||||
static bool
|
||||
ReadSuffixAndSpec(JSStructuredCloneReader* aReader,
|
||||
PrincipalOriginAttributes& aAttrs,
|
||||
nsACString& aSpec)
|
||||
{
|
||||
uint32_t suffixLength, specLength;
|
||||
if (!JS_ReadUint32Pair(aReader, &suffixLength, &specLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString suffix;
|
||||
suffix.SetLength(suffixLength);
|
||||
if (!JS_ReadBytes(aReader, suffix.BeginWriting(), suffixLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aAttrs.PopulateFromSuffix(suffix);
|
||||
|
||||
aSpec.SetLength(specLength);
|
||||
if (!JS_ReadBytes(aReader, aSpec.BeginWriting(), specLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ReadPrincipalInfo(JSStructuredCloneReader* aReader,
|
||||
uint32_t aTag,
|
||||
@@ -131,7 +157,12 @@ ReadPrincipalInfo(JSStructuredCloneReader* aReader,
|
||||
if (aTag == SCTAG_DOM_SYSTEM_PRINCIPAL) {
|
||||
aInfo = SystemPrincipalInfo();
|
||||
} else if (aTag == SCTAG_DOM_NULL_PRINCIPAL) {
|
||||
aInfo = NullPrincipalInfo();
|
||||
PrincipalOriginAttributes attrs;
|
||||
nsAutoCString dummy;
|
||||
if (!ReadSuffixAndSpec(aReader, attrs, dummy)) {
|
||||
return false;
|
||||
}
|
||||
aInfo = NullPrincipalInfo(attrs);
|
||||
} else if (aTag == SCTAG_DOM_EXPANDED_PRINCIPAL) {
|
||||
uint32_t length, unused;
|
||||
if (!JS_ReadUint32Pair(aReader, &length, &unused)) {
|
||||
@@ -155,25 +186,12 @@ ReadPrincipalInfo(JSStructuredCloneReader* aReader,
|
||||
|
||||
aInfo = expanded;
|
||||
} else if (aTag == SCTAG_DOM_CONTENT_PRINCIPAL) {
|
||||
uint32_t suffixLength, specLength;
|
||||
if (!JS_ReadUint32Pair(aReader, &suffixLength, &specLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString suffix;
|
||||
suffix.SetLength(suffixLength);
|
||||
if (!JS_ReadBytes(aReader, suffix.BeginWriting(), suffixLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString spec;
|
||||
spec.SetLength(specLength);
|
||||
if (!JS_ReadBytes(aReader, spec.BeginWriting(), specLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PrincipalOriginAttributes attrs;
|
||||
attrs.PopulateFromSuffix(suffix);
|
||||
nsAutoCString spec;
|
||||
if (!ReadSuffixAndSpec(aReader, attrs, spec)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aInfo = ContentPrincipalInfo(attrs, spec);
|
||||
} else {
|
||||
MOZ_CRASH("unexpected principal structured clone tag");
|
||||
@@ -214,11 +232,26 @@ nsJSPrincipals::ReadKnownPrincipalType(JSContext* aCx,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
WriteSuffixAndSpec(JSStructuredCloneWriter* aWriter,
|
||||
const PrincipalOriginAttributes& aAttrs,
|
||||
const nsCString& aSpec)
|
||||
{
|
||||
nsAutoCString suffix;
|
||||
aAttrs.CreateSuffix(suffix);
|
||||
|
||||
return JS_WriteUint32Pair(aWriter, suffix.Length(), aSpec.Length()) &&
|
||||
JS_WriteBytes(aWriter, suffix.get(), suffix.Length()) &&
|
||||
JS_WriteBytes(aWriter, aSpec.get(), aSpec.Length());
|
||||
}
|
||||
|
||||
static bool
|
||||
WritePrincipalInfo(JSStructuredCloneWriter* aWriter, const PrincipalInfo& aInfo)
|
||||
{
|
||||
if (aInfo.type() == PrincipalInfo::TNullPrincipalInfo) {
|
||||
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_NULL_PRINCIPAL, 0);
|
||||
const NullPrincipalInfo& nullInfo = aInfo;
|
||||
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_NULL_PRINCIPAL, 0) &&
|
||||
WriteSuffixAndSpec(aWriter, nullInfo.attrs(), EmptyCString());
|
||||
}
|
||||
if (aInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
|
||||
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_SYSTEM_PRINCIPAL, 0);
|
||||
@@ -240,12 +273,8 @@ WritePrincipalInfo(JSStructuredCloneWriter* aWriter, const PrincipalInfo& aInfo)
|
||||
|
||||
MOZ_ASSERT(aInfo.type() == PrincipalInfo::TContentPrincipalInfo);
|
||||
const ContentPrincipalInfo& cInfo = aInfo;
|
||||
nsAutoCString suffix;
|
||||
cInfo.attrs().CreateSuffix(suffix);
|
||||
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_CONTENT_PRINCIPAL, 0) &&
|
||||
JS_WriteUint32Pair(aWriter, suffix.Length(), cInfo.spec().Length()) &&
|
||||
JS_WriteBytes(aWriter, suffix.get(), suffix.Length()) &&
|
||||
JS_WriteBytes(aWriter, cInfo.spec().get(), cInfo.spec().Length());
|
||||
WriteSuffixAndSpec(aWriter, cInfo.attrs(), cInfo.spec());
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "nsDocShell.h"
|
||||
#include "nsNullPrincipal.h"
|
||||
#include "nsNullPrincipalURI.h"
|
||||
#include "nsMemory.h"
|
||||
@@ -40,7 +41,20 @@ nsNullPrincipal::CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom)
|
||||
{
|
||||
RefPtr<nsNullPrincipal> nullPrin = new nsNullPrincipal();
|
||||
nsresult rv = nullPrin->Init(Cast(aInheritFrom)->OriginAttributesRef());
|
||||
return NS_SUCCEEDED(rv) ? nullPrin.forget() : nullptr;
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
return nullPrin.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<nsNullPrincipal>
|
||||
nsNullPrincipal::CreateWithInheritedAttributes(nsIDocShell* aDocShell)
|
||||
{
|
||||
PrincipalOriginAttributes attrs;
|
||||
attrs.InheritFromDocShellToDoc(nsDocShell::Cast(aDocShell)->GetOriginAttributes(), nullptr);
|
||||
|
||||
RefPtr<nsNullPrincipal> nullPrin = new nsNullPrincipal();
|
||||
nsresult rv = nullPrin->Init(attrs);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
return nullPrin.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<nsNullPrincipal>
|
||||
@@ -48,7 +62,7 @@ nsNullPrincipal::Create(const PrincipalOriginAttributes& aOriginAttributes)
|
||||
{
|
||||
RefPtr<nsNullPrincipal> nullPrin = new nsNullPrincipal();
|
||||
nsresult rv = nullPrin->Init(aOriginAttributes);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
return nullPrin.forget();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
|
||||
class nsIDocShell;
|
||||
class nsIURI;
|
||||
|
||||
#define NS_NULLPRINCIPAL_CID \
|
||||
@@ -47,10 +48,10 @@ public:
|
||||
NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
|
||||
nsresult GetOriginInternal(nsACString& aOrigin) override;
|
||||
|
||||
// Returns null on failure.
|
||||
static already_AddRefed<nsNullPrincipal> CreateWithInheritedAttributes(nsIPrincipal *aInheritFrom);
|
||||
static already_AddRefed<nsNullPrincipal> CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom);
|
||||
|
||||
static already_AddRefed<nsNullPrincipal> CreateWithInheritedAttributes(nsIDocShell* aDocShell);
|
||||
|
||||
// Returns null on failure.
|
||||
static already_AddRefed<nsNullPrincipal>
|
||||
Create(const mozilla::PrincipalOriginAttributes& aOriginAttributes = mozilla::PrincipalOriginAttributes());
|
||||
|
||||
|
||||
@@ -366,14 +366,12 @@ nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
|
||||
if (loadInfo->LoadingPrincipal()) {
|
||||
prin =
|
||||
nsNullPrincipal::CreateWithInheritedAttributes(loadInfo->LoadingPrincipal());
|
||||
NS_ENSURE_TRUE(prin, NS_ERROR_FAILURE);
|
||||
} else {
|
||||
NeckoOriginAttributes nAttrs;
|
||||
loadInfo->GetOriginAttributes(&nAttrs);
|
||||
PrincipalOriginAttributes pAttrs;
|
||||
pAttrs.InheritFromNecko(nAttrs);
|
||||
prin = nsNullPrincipal::Create(pAttrs);
|
||||
NS_ENSURE_TRUE(prin, NS_ERROR_FAILURE);
|
||||
}
|
||||
prin.forget(aPrincipal);
|
||||
return NS_OK;
|
||||
@@ -1212,7 +1210,6 @@ nsScriptSecurityManager::CreateNullPrincipal(JS::Handle<JS::Value> aOriginAttrib
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
nsCOMPtr<nsIPrincipal> prin = nsNullPrincipal::Create(attrs);
|
||||
NS_ENSURE_TRUE(prin, NS_ERROR_FAILURE);
|
||||
prin.forget(aPrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -120,8 +120,12 @@ function createDummyDocument() {
|
||||
});
|
||||
let docShell = getDocShell(frame);
|
||||
let eventTarget = docShell.chromeEventHandler;
|
||||
docShell.createAboutBlankContentViewer(Cc["@mozilla.org/nullprincipal;1"]
|
||||
.createInstance(Ci.nsIPrincipal));
|
||||
let ssm = Services.scriptSecurityManager;
|
||||
|
||||
// We probably need to call InheritFromDocShellToDoc to get the correct origin
|
||||
// attributes, but right now we can't call it from JS.
|
||||
let nullPrincipal = ssm.createNullPrincipal(docShell.getOriginAttributes());
|
||||
docShell.createAboutBlankContentViewer(nullPrincipal);
|
||||
let window = docShell.contentViewer.DOMDocument.defaultView;
|
||||
window.location = "data:text/html,<html></html>";
|
||||
let deferred = promise.defer();
|
||||
|
||||
@@ -1481,8 +1481,8 @@ nsDocShell::LoadURI(nsIURI* aURI,
|
||||
// for in InternalLoad is data:, javascript:, and about:blank
|
||||
// URIs. For other URIs this would all be dead wrong!
|
||||
|
||||
nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(owner);
|
||||
if (owner && mItemType != typeChrome) {
|
||||
nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(owner);
|
||||
if (nsContentUtils::IsSystemPrincipal(ownerPrincipal)) {
|
||||
if (ownerIsExplicit) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
@@ -1495,7 +1495,10 @@ nsDocShell::LoadURI(nsIURI* aURI,
|
||||
}
|
||||
// Don't inherit from the current page. Just do the safe thing
|
||||
// and pretend that we were loaded by a nullprincipal.
|
||||
owner = nsNullPrincipal::Create();
|
||||
//
|
||||
// We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't
|
||||
// have origin attributes.
|
||||
owner = nsNullPrincipal::CreateWithInheritedAttributes(this);
|
||||
inheritOwner = false;
|
||||
}
|
||||
}
|
||||
@@ -1506,7 +1509,9 @@ nsDocShell::LoadURI(nsIURI* aURI,
|
||||
|
||||
if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_OWNER) {
|
||||
inheritOwner = false;
|
||||
owner = nsNullPrincipal::Create();
|
||||
owner = ownerPrincipal ?
|
||||
nsNullPrincipal::CreateWithInheritedAttributes(ownerPrincipal) :
|
||||
nsNullPrincipal::CreateWithInheritedAttributes(this);
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
@@ -7967,7 +7972,6 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
if (mSandboxFlags & SANDBOXED_ORIGIN) {
|
||||
principal = nsNullPrincipal::CreateWithInheritedAttributes(aPrincipal);
|
||||
NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
|
||||
} else {
|
||||
principal = aPrincipal;
|
||||
}
|
||||
@@ -12153,7 +12157,6 @@ nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
|
||||
if (loadInfo->LoadingPrincipal()) {
|
||||
owner = nsNullPrincipal::CreateWithInheritedAttributes(
|
||||
loadInfo->LoadingPrincipal());
|
||||
NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
|
||||
} else {
|
||||
// get the OriginAttributes
|
||||
NeckoOriginAttributes nAttrs;
|
||||
@@ -12162,7 +12165,6 @@ nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
|
||||
pAttrs.InheritFromNecko(nAttrs);
|
||||
|
||||
owner = nsNullPrincipal::Create(pAttrs);
|
||||
NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);
|
||||
}
|
||||
} else if (loadInfo->GetForceInheritPrincipal()) {
|
||||
owner = loadInfo->TriggeringPrincipal();
|
||||
@@ -12337,8 +12339,7 @@ nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType)
|
||||
// Ensure that we have an owner. Otherwise javascript: URIs will
|
||||
// pick it up from the about:blank page we just loaded, and we
|
||||
// don't really want even that in this case.
|
||||
owner = nsNullPrincipal::Create();
|
||||
NS_ENSURE_TRUE(owner, NS_ERROR_OUT_OF_MEMORY);
|
||||
owner = nsNullPrincipal::CreateWithInheritedAttributes(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14026,8 +14027,7 @@ nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview)
|
||||
nsCOMPtr<nsIDocumentViewerPrint> print = do_QueryInterface(mContentViewer);
|
||||
if (!print || !print->IsInitializedForPrintPreview()) {
|
||||
Stop(nsIWebNavigation::STOP_ALL);
|
||||
nsCOMPtr<nsIPrincipal> principal = nsNullPrincipal::Create();
|
||||
NS_ENSURE_STATE(principal);
|
||||
nsCOMPtr<nsIPrincipal> principal = nsNullPrincipal::CreateWithInheritedAttributes(this);
|
||||
nsresult rv = CreateAboutBlankContentViewer(principal, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
print = do_QueryInterface(mContentViewer);
|
||||
|
||||
@@ -170,10 +170,6 @@ AppsService.prototype = {
|
||||
return UserCustomizations.isFromExtension(aURI);
|
||||
},
|
||||
|
||||
updateDataStoreEntriesFromLocalId: function(aLocalId) {
|
||||
return DOMApplicationRegistry.updateDataStoreEntriesFromLocalId(aLocalId);
|
||||
},
|
||||
|
||||
classID : APPS_SERVICE_CID,
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIAppsService])
|
||||
}
|
||||
|
||||
@@ -419,10 +419,6 @@ this.DOMApplicationRegistry = {
|
||||
|
||||
getAppInfo: function getAppInfo(aAppId) {
|
||||
return AppsUtils.getAppInfo(this.webapps, aAppId);
|
||||
},
|
||||
|
||||
updateDataStoreEntriesFromLocalId: function(aLocalId) {
|
||||
debug("updateDataStoreEntriesFromLocalId() not yet supported on child!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,10 +147,6 @@ XPCOMUtils.defineLazyGetter(this, "interAppCommService", function() {
|
||||
.getService(Ci.nsIInterAppCommService);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "dataStoreService",
|
||||
"@mozilla.org/datastore-service;1",
|
||||
"nsIDataStoreService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "appsService",
|
||||
"@mozilla.org/AppsService;1",
|
||||
"nsIAppsService");
|
||||
@@ -450,18 +446,6 @@ this.DOMApplicationRegistry = {
|
||||
}
|
||||
}),
|
||||
|
||||
updateDataStoreForApp: Task.async(function*(aId) {
|
||||
if (!this.webapps[aId]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create or Update the DataStore for this app
|
||||
let results = yield this._readManifests([{ id: aId }]);
|
||||
let app = this.webapps[aId];
|
||||
this.updateDataStore(app.localId, app.origin, app.manifestURL,
|
||||
results[0].manifest, app.appStatus);
|
||||
}),
|
||||
|
||||
appKind: function(aApp, aManifest) {
|
||||
if (aApp.origin.startsWith("android://")) {
|
||||
return this.kAndroid;
|
||||
@@ -813,52 +797,10 @@ this.DOMApplicationRegistry = {
|
||||
Services.prefs.setBoolPref("dom.apps.reset-permissions", true);
|
||||
}
|
||||
|
||||
// DataStores must be initialized at startup.
|
||||
for (let id in this.webapps) {
|
||||
yield this.updateDataStoreForApp(id);
|
||||
}
|
||||
|
||||
yield this.registerAppsHandlers(runUpdate);
|
||||
}.bind(this)).then(null, Cu.reportError);
|
||||
},
|
||||
|
||||
updateDataStore: function(aId, aOrigin, aManifestURL, aManifest) {
|
||||
if (!aManifest) {
|
||||
debug("updateDataStore: no manifest for " + aOrigin);
|
||||
return;
|
||||
}
|
||||
|
||||
let uri = Services.io.newURI(aOrigin, null, null);
|
||||
let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager);
|
||||
let principal = secMan.createCodebasePrincipal(uri, {appId: aId});
|
||||
if (!dataStoreService.checkPermission(principal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ('datastores-owned' in aManifest) {
|
||||
for (let name in aManifest['datastores-owned']) {
|
||||
let readonly = "access" in aManifest['datastores-owned'][name]
|
||||
? aManifest['datastores-owned'][name].access == 'readonly'
|
||||
: false;
|
||||
|
||||
dataStoreService.installDataStore(aId, name, aOrigin, aManifestURL,
|
||||
readonly);
|
||||
}
|
||||
}
|
||||
|
||||
if ('datastores-access' in aManifest) {
|
||||
for (let name in aManifest['datastores-access']) {
|
||||
let readonly = ("readonly" in aManifest['datastores-access'][name]) &&
|
||||
!aManifest['datastores-access'][name].readonly
|
||||
? false : true;
|
||||
|
||||
dataStoreService.installAccessDataStore(aId, name, aOrigin,
|
||||
aManifestURL, readonly);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// |aEntryPoint| is either the entry_point name or the null in which case we
|
||||
// use the root of the manifest.
|
||||
//
|
||||
@@ -1969,8 +1911,6 @@ this.DOMApplicationRegistry = {
|
||||
manifestURL: app.manifestURL },
|
||||
true);
|
||||
}
|
||||
this.updateDataStore(this.webapps[id].localId, app.origin,
|
||||
app.manifestURL, newManifest);
|
||||
MessageBroadcaster.broadcastMessage("Webapps:UpdateState", {
|
||||
app: app,
|
||||
manifest: newManifest,
|
||||
@@ -2419,9 +2359,6 @@ this.DOMApplicationRegistry = {
|
||||
}, true);
|
||||
}
|
||||
|
||||
this.updateDataStore(this.webapps[aId].localId, aApp.origin,
|
||||
aApp.manifestURL, aApp.manifest);
|
||||
|
||||
aApp.name = aNewManifest.name;
|
||||
aApp.csp = manifest.csp || "";
|
||||
aApp.updateTime = Date.now();
|
||||
@@ -3076,9 +3013,6 @@ this.DOMApplicationRegistry = {
|
||||
this.doUninstall.bind(this, aData, aData.mm)
|
||||
);
|
||||
}
|
||||
|
||||
this.updateDataStore(this.webapps[id].localId, this.webapps[id].origin,
|
||||
this.webapps[id].manifestURL, jsonManifest);
|
||||
}
|
||||
|
||||
for (let prop of ["installState", "downloadAvailable", "downloading",
|
||||
@@ -3217,9 +3151,6 @@ this.DOMApplicationRegistry = {
|
||||
}, true);
|
||||
}
|
||||
|
||||
this.updateDataStore(this.webapps[aId].localId, aNewApp.origin,
|
||||
aNewApp.manifestURL, aManifest);
|
||||
|
||||
if (aInstallSuccessCallback) {
|
||||
yield aInstallSuccessCallback(aNewApp, aManifest, zipFile.path);
|
||||
}
|
||||
@@ -4755,13 +4686,6 @@ this.DOMApplicationRegistry = {
|
||||
return AppsUtils.areAnyAppsInstalled(this.webapps);
|
||||
},
|
||||
|
||||
updateDataStoreEntriesFromLocalId: function(aLocalId) {
|
||||
let app = appsService.getAppByLocalId(aLocalId);
|
||||
if (app) {
|
||||
this.updateDataStoreForApp(app.id);
|
||||
}
|
||||
},
|
||||
|
||||
_notifyCategoryAndObservers: function(subject, topic, data, msg) {
|
||||
const serviceMarker = "service,";
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - basic operation on a readonly db</title>
|
||||
<title>?!?</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="file_test_widget.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
|
||||
@@ -74,7 +74,9 @@ ThreadSafeChromeUtils::Base64URLEncode(GlobalObject& aGlobal,
|
||||
MOZ_CRASH("Uninitialized union: expected buffer or view");
|
||||
}
|
||||
|
||||
nsresult rv = mozilla::Base64URLEncode(length, data, aOptions, aResult);
|
||||
auto paddingPolicy = aOptions.mPad ? Base64URLEncodePaddingPolicy::Include :
|
||||
Base64URLEncodePaddingPolicy::Omit;
|
||||
nsresult rv = mozilla::Base64URLEncode(length, data, paddingPolicy, aResult);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aResult.Truncate();
|
||||
aRv.Throw(rv);
|
||||
@@ -88,8 +90,26 @@ ThreadSafeChromeUtils::Base64URLDecode(GlobalObject& aGlobal,
|
||||
JS::MutableHandle<JSObject*> aRetval,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
Base64URLDecodePaddingPolicy paddingPolicy;
|
||||
switch (aOptions.mPadding) {
|
||||
case Base64URLDecodePadding::Require:
|
||||
paddingPolicy = Base64URLDecodePaddingPolicy::Require;
|
||||
break;
|
||||
|
||||
case Base64URLDecodePadding::Ignore:
|
||||
paddingPolicy = Base64URLDecodePaddingPolicy::Ignore;
|
||||
break;
|
||||
|
||||
case Base64URLDecodePadding::Reject:
|
||||
paddingPolicy = Base64URLDecodePaddingPolicy::Reject;
|
||||
break;
|
||||
|
||||
default:
|
||||
aRv.Throw(NS_ERROR_INVALID_ARG);
|
||||
return;
|
||||
}
|
||||
FallibleTArray<uint8_t> data;
|
||||
nsresult rv = mozilla::Base64URLDecode(aString, aOptions, data);
|
||||
nsresult rv = mozilla::Base64URLDecode(aString, paddingPolicy, data);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
|
||||
@@ -352,7 +352,6 @@ DOMParser::Init(nsIPrincipal* principal, nsIURI* documentURI,
|
||||
// Don't give DOMParsers the system principal. Use a null
|
||||
// principal instead.
|
||||
mPrincipal = nsNullPrincipal::Create();
|
||||
NS_ENSURE_TRUE(mPrincipal, NS_ERROR_FAILURE);
|
||||
|
||||
if (!mDocumentURI) {
|
||||
rv = mPrincipal->GetURI(getter_AddRefs(mDocumentURI));
|
||||
@@ -468,8 +467,6 @@ DOMParser::SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult)
|
||||
AttemptedInitMarker marker(&mAttemptedInit);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> prin = nsNullPrincipal::Create();
|
||||
NS_ENSURE_TRUE(prin, NS_ERROR_FAILURE);
|
||||
|
||||
rv = Init(prin, nullptr, nullptr, scriptHandlingObject);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
@@ -96,7 +96,6 @@
|
||||
#endif
|
||||
|
||||
#include "nsIDOMGlobalPropertyInitializer.h"
|
||||
#include "mozilla/dom/DataStoreService.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
#include "nsScriptNameSpaceManager.h"
|
||||
@@ -1504,38 +1503,6 @@ Navigator::GetDeprecatedBattery(ErrorResult& aRv)
|
||||
return mBatteryManager;
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Promise>
|
||||
Navigator::GetDataStores(nsPIDOMWindowInner* aWindow,
|
||||
const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!aWindow || !aWindow->GetDocShell()) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<DataStoreService> service = DataStoreService::GetOrCreate();
|
||||
if (!service) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> promise;
|
||||
aRv = service->GetDataStores(aWindow, aName, aOwner, getter_AddRefs(promise));
|
||||
|
||||
RefPtr<Promise> p = static_cast<Promise*>(promise.get());
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Navigator::GetDataStores(const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
return GetDataStores(mWindow, aName, aOwner, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Navigator::GetFeature(const nsAString& aName, ErrorResult& aRv)
|
||||
{
|
||||
@@ -2295,75 +2262,6 @@ Navigator::HasUserMediaSupport(JSContext* /* unused */,
|
||||
Preferences::GetBool("media.peerconnection.enabled", false);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
Navigator::HasDataStoreSupport(nsIPrincipal* aPrincipal)
|
||||
{
|
||||
workers::AssertIsOnMainThread();
|
||||
|
||||
return DataStoreService::CheckPermission(aPrincipal);
|
||||
}
|
||||
|
||||
// A WorkerMainThreadRunnable to synchronously dispatch the call of
|
||||
// HasDataStoreSupport() from the worker thread to the main thread.
|
||||
class HasDataStoreSupportRunnable final
|
||||
: public workers::WorkerCheckAPIExposureOnMainThreadRunnable
|
||||
{
|
||||
public:
|
||||
bool mResult;
|
||||
|
||||
explicit HasDataStoreSupportRunnable(workers::WorkerPrivate* aWorkerPrivate)
|
||||
: workers::WorkerCheckAPIExposureOnMainThreadRunnable(aWorkerPrivate)
|
||||
, mResult(false)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool
|
||||
MainThreadRun() override
|
||||
{
|
||||
workers::AssertIsOnMainThread();
|
||||
|
||||
mResult = Navigator::HasDataStoreSupport(mWorkerPrivate->GetPrincipal());
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/* static */
|
||||
bool
|
||||
Navigator::HasDataStoreSupport(JSContext* aCx, JSObject* aGlobal)
|
||||
{
|
||||
// If the caller is on the worker thread, dispatch this to the main thread.
|
||||
if (!NS_IsMainThread()) {
|
||||
workers::WorkerPrivate* workerPrivate =
|
||||
workers::GetWorkerPrivateFromContext(aCx);
|
||||
workerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
RefPtr<HasDataStoreSupportRunnable> runnable =
|
||||
new HasDataStoreSupportRunnable(workerPrivate);
|
||||
return runnable->Dispatch() && runnable->mResult;
|
||||
}
|
||||
|
||||
workers::AssertIsOnMainThread();
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx, aGlobal);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> win = GetWindowFromGlobal(global);
|
||||
if (!win) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsIDocument* doc = win->GetExtantDoc();
|
||||
if (!doc || !doc->NodePrincipal()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return HasDataStoreSupport(doc->NodePrincipal());
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G
|
||||
/* static */
|
||||
bool
|
||||
|
||||
@@ -164,11 +164,6 @@ public:
|
||||
Promise* GetBattery(ErrorResult& aRv);
|
||||
battery::BatteryManager* GetDeprecatedBattery(ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<Promise> GetDataStores(nsPIDOMWindowInner* aWindow,
|
||||
const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static void AppName(nsAString& aAppName, bool aUsePrefOverriddenValue);
|
||||
|
||||
static nsresult GetPlatform(nsAString& aPlatform,
|
||||
@@ -186,10 +181,6 @@ public:
|
||||
// NavigatorBinding::ClearCachedUserAgentValue(this);
|
||||
void ClearUserAgentCache();
|
||||
|
||||
already_AddRefed<Promise> GetDataStores(const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// Feature Detection API
|
||||
already_AddRefed<Promise> GetFeature(const nsAString& aName,
|
||||
ErrorResult& aRv);
|
||||
@@ -326,10 +317,6 @@ public:
|
||||
static bool HasUserMediaSupport(JSContext* /* unused */,
|
||||
JSObject* /* unused */);
|
||||
|
||||
static bool HasDataStoreSupport(nsIPrincipal* aPrincipal);
|
||||
|
||||
static bool HasDataStoreSupport(JSContext* cx, JSObject* aGlobal);
|
||||
|
||||
#ifdef MOZ_B2G
|
||||
static bool HasMobileIdSupport(JSContext* aCx, JSObject* aGlobal);
|
||||
#endif
|
||||
|
||||
@@ -4506,8 +4506,7 @@ nsContentUtils::ConvertToPlainText(const nsAString& aSourceBuffer,
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
NS_NewURI(getter_AddRefs(uri), "about:blank");
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
do_CreateInstance(NS_NULLPRINCIPAL_CONTRACTID);
|
||||
nsCOMPtr<nsIPrincipal> principal = nsNullPrincipal::Create();
|
||||
nsCOMPtr<nsIDOMDocument> domDocument;
|
||||
nsresult rv = NS_NewDOMDocument(getter_AddRefs(domDocument),
|
||||
EmptyString(),
|
||||
|
||||
@@ -3063,37 +3063,25 @@ nsDOMWindowUtils::RemoteFrameFullscreenReverted()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS FullscreenChangePrepare
|
||||
static void
|
||||
PrepareForFullscreenChange(nsIPresShell* aPresShell, const nsSize& aSize,
|
||||
nsSize* aOldSize = nullptr)
|
||||
{
|
||||
public:
|
||||
FullscreenChangePrepare(nsIPresShell* aPresShell,
|
||||
const nsSize& aSize, nsSize* aOldSize = nullptr)
|
||||
: mPresShell(aPresShell)
|
||||
{
|
||||
if (mPresShell) {
|
||||
mPresShell->SetIsInFullscreenChange(true);
|
||||
}
|
||||
if (aSize.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (nsViewManager* viewManager = mPresShell->GetViewManager()) {
|
||||
if (!aPresShell) {
|
||||
return;
|
||||
}
|
||||
if (nsRefreshDriver* rd = aPresShell->GetRefreshDriver()) {
|
||||
rd->SetIsResizeSuppressed();
|
||||
}
|
||||
if (!aSize.IsEmpty()) {
|
||||
if (nsViewManager* viewManager = aPresShell->GetViewManager()) {
|
||||
if (aOldSize) {
|
||||
viewManager->GetWindowDimensions(&aOldSize->width, &aOldSize->height);
|
||||
}
|
||||
viewManager->SetWindowDimensions(aSize.width, aSize.height);
|
||||
}
|
||||
}
|
||||
|
||||
~FullscreenChangePrepare()
|
||||
{
|
||||
if (mPresShell) {
|
||||
mPresShell->SetIsInFullscreenChange(false);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIPresShell> mPresShell;
|
||||
};
|
||||
}
|
||||
|
||||
class OldWindowSize : public LinkedListElement<OldWindowSize>
|
||||
{
|
||||
@@ -3166,7 +3154,7 @@ nsDOMWindowUtils::HandleFullscreenRequests(bool* aRetVal)
|
||||
presContext->DeviceContext()->GetRect(screenRect);
|
||||
}
|
||||
nsSize oldSize;
|
||||
FullscreenChangePrepare prepare(GetPresShell(), screenRect.Size(), &oldSize);
|
||||
PrepareForFullscreenChange(GetPresShell(), screenRect.Size(), &oldSize);
|
||||
OldWindowSize::Set(doc->GetWindow(), oldSize);
|
||||
|
||||
*aRetVal = nsIDocument::HandlePendingFullscreenRequests(doc);
|
||||
@@ -3190,7 +3178,7 @@ nsDOMWindowUtils::ExitFullscreen()
|
||||
// set the window dimensions in advance. Since the resize message
|
||||
// comes after the fullscreen change call, doing so could avoid an
|
||||
// extra resize reflow after this point.
|
||||
FullscreenChangePrepare prepare(GetPresShell(), oldSize);
|
||||
PrepareForFullscreenChange(GetPresShell(), oldSize);
|
||||
nsIDocument::ExitFullscreenInDocTree(doc);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
+21
-12
@@ -6415,13 +6415,6 @@ nsGlobalWindow::SetFullscreenInternal(FullscreenReason aReason,
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't setup the widget, we may need to manually set this
|
||||
// flag, or the assertion in FinishFullscreenChange is violated.
|
||||
if (nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell()) {
|
||||
if (!presShell->IsInFullscreenChange()) {
|
||||
presShell->SetIsInFullscreenChange(true);
|
||||
}
|
||||
}
|
||||
FinishFullscreenChange(aFullScreen);
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -6435,8 +6428,18 @@ nsGlobalWindow::SetWidgetFullscreen(FullscreenReason aReason, bool aIsFullscreen
|
||||
MOZ_ASSERT(!AsOuter()->GetFrameElementInternal(), "Content window should not call this");
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
|
||||
if (nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell()) {
|
||||
presShell->SetIsInFullscreenChange(true);
|
||||
if (!NS_WARN_IF(!IsChromeWindow())) {
|
||||
auto chromeWin = static_cast<nsGlobalChromeWindow*>(this);
|
||||
if (!NS_WARN_IF(chromeWin->mFullscreenPresShell)) {
|
||||
if (nsIPresShell* shell = mDocShell->GetPresShell()) {
|
||||
if (nsRefreshDriver* rd = shell->GetRefreshDriver()) {
|
||||
chromeWin->mFullscreenPresShell = do_GetWeakReference(shell);
|
||||
MOZ_ASSERT(chromeWin->mFullscreenPresShell);
|
||||
rd->SetIsResizeSuppressed();
|
||||
rd->Freeze();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nsresult rv = aReason == FullscreenReason::ForFullscreenMode ?
|
||||
// If we enter fullscreen for fullscreen mode, we want
|
||||
@@ -6478,9 +6481,15 @@ nsGlobalWindow::FinishFullscreenChange(bool aIsFullscreen)
|
||||
// respond visually if we are kicked into full screen mode
|
||||
DispatchCustomEvent(NS_LITERAL_STRING("fullscreen"));
|
||||
|
||||
if (nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell()) {
|
||||
MOZ_ASSERT(presShell->IsInFullscreenChange());
|
||||
presShell->SetIsInFullscreenChange(false);
|
||||
if (!NS_WARN_IF(!IsChromeWindow())) {
|
||||
auto chromeWin = static_cast<nsGlobalChromeWindow*>(this);
|
||||
if (nsCOMPtr<nsIPresShell> shell =
|
||||
do_QueryReferent(chromeWin->mFullscreenPresShell)) {
|
||||
if (nsRefreshDriver* rd = shell->GetRefreshDriver()) {
|
||||
rd->Thaw();
|
||||
}
|
||||
chromeWin->mFullscreenPresShell = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mWakeLock && mFullScreen) {
|
||||
|
||||
@@ -1986,6 +1986,10 @@ public:
|
||||
nsCOMPtr<nsIBrowserDOMWindow> mBrowserDOMWindow;
|
||||
nsCOMPtr<nsIMessageBroadcaster> mMessageManager;
|
||||
nsInterfaceHashtable<nsStringHashKey, nsIMessageBroadcaster> mGroupMessageManagers;
|
||||
// A weak pointer to the nsPresShell that we are doing fullscreen for.
|
||||
// The pointer being set indicates we've set the IsInFullscreenChange
|
||||
// flag on this pres shell.
|
||||
nsWeakPtr mFullscreenPresShell;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -182,7 +182,6 @@ nsNodeInfoManager::Init(nsIDocument *aDocument)
|
||||
"Being inited when we already have a principal?");
|
||||
|
||||
mPrincipal = nsNullPrincipal::Create();
|
||||
NS_ENSURE_TRUE(mPrincipal, NS_ERROR_FAILURE);
|
||||
|
||||
if (aDocument) {
|
||||
mBindingManager = new nsBindingManager(aDocument);
|
||||
|
||||
@@ -1524,8 +1524,7 @@ nsTreeSanitizer::InitializeStatics()
|
||||
sAttributesMathML->PutEntry(*kAttributesMathML[i]);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
do_CreateInstance(NS_NULLPRINCIPAL_CONTRACTID);
|
||||
nsCOMPtr<nsIPrincipal> principal = nsNullPrincipal::Create();
|
||||
principal.forget(&sNullPrincipal);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,8 +88,10 @@ function testDecode(input, decoded) {
|
||||
function test_base64URLDecode() {
|
||||
throws(_ => ChromeUtils.base64URLDecode(""), /TypeError/,
|
||||
"Should require decoding options");
|
||||
throws(_ => ChromeUtils.base64URLEncode("", {}), /TypeError/,
|
||||
throws(_ => ChromeUtils.base64URLDecode("", {}), /TypeError/,
|
||||
"Decoding should require the padding option");
|
||||
throws(_ => ChromeUtils.base64URLDecode("", { padding: "chocolate" }),
|
||||
"Decoding should throw for invalid padding policy");
|
||||
|
||||
for (let {decoded, encoded} of binaryTests) {
|
||||
testDecode(encoded, decoded);
|
||||
|
||||
@@ -362,25 +362,6 @@ DOMInterfaces = {
|
||||
'nativeType': 'nsDOMDataChannel',
|
||||
},
|
||||
|
||||
'DataStore': [{
|
||||
'workers': False
|
||||
}, {
|
||||
'workers': True,
|
||||
'nativeType': 'mozilla::dom::workers::WorkerDataStore',
|
||||
'implicitJSContext': ['name', 'owner', 'readOnly', 'get', 'remove',
|
||||
'clear', 'revisionId', 'getLength', 'sync']
|
||||
}],
|
||||
|
||||
'DataStoreCursor': [{
|
||||
'workers': False,
|
||||
'wrapperCache': False
|
||||
}, {
|
||||
'workers': True,
|
||||
'nativeType': 'mozilla::dom::workers::WorkerDataStoreCursor',
|
||||
'wrapperCache': False,
|
||||
'implicitJSContext': ['store', 'next', 'close']
|
||||
}],
|
||||
|
||||
'DedicatedWorkerGlobalScope': {
|
||||
'headerFile': 'mozilla/dom/WorkerScope.h',
|
||||
'workers': True,
|
||||
@@ -1612,10 +1593,6 @@ DOMInterfaces = {
|
||||
},
|
||||
},
|
||||
|
||||
'WorkerNavigator': {
|
||||
'implicitJSContext': ['getDataStores'],
|
||||
},
|
||||
|
||||
'XMLHttpRequest': [
|
||||
{
|
||||
'nativeType': 'nsXMLHttpRequest',
|
||||
|
||||
@@ -99,9 +99,6 @@ SimpleGlobalObject::Create(GlobalType globalType, JS::Handle<JS::Value> proto)
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
if (NS_IsMainThread()) {
|
||||
principal = nsNullPrincipal::Create();
|
||||
if (!principal) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> global(cx,
|
||||
|
||||
@@ -129,7 +129,7 @@ private:
|
||||
};
|
||||
|
||||
class BluetoothA2dpManager::InitProfileResultHandlerRunnable final
|
||||
: public nsRunnable
|
||||
: public Runnable
|
||||
{
|
||||
public:
|
||||
InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||
@@ -171,7 +171,7 @@ BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
|
||||
|
||||
if (sBtA2dpInterface) {
|
||||
BT_LOGR("Bluetooth A2DP interface is already initalized.");
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch A2DP Init runnable");
|
||||
@@ -184,7 +184,7 @@ BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!btInf)) {
|
||||
// If there's no Bluetooth interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch A2DP OnError runnable");
|
||||
@@ -197,7 +197,7 @@ BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!setupInterface)) {
|
||||
// If there's no Setup interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch A2DP OnError runnable");
|
||||
@@ -210,7 +210,7 @@ BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!a2dpInterface)) {
|
||||
// If there's no A2DP interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch A2DP OnError runnable");
|
||||
@@ -329,7 +329,7 @@ private:
|
||||
};
|
||||
|
||||
class BluetoothA2dpManager::DeinitProfileResultHandlerRunnable final
|
||||
: public nsRunnable
|
||||
: public Runnable
|
||||
{
|
||||
public:
|
||||
DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||
@@ -365,7 +365,7 @@ BluetoothA2dpManager::DeinitA2dpInterface(BluetoothProfileResultHandler* aRes)
|
||||
|
||||
if (!sBtA2dpInterface) {
|
||||
BT_LOGR("Bluetooth A2DP interface has not been initalized.");
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch A2DP Deinit runnable");
|
||||
@@ -378,7 +378,7 @@ BluetoothA2dpManager::DeinitA2dpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!btInf)) {
|
||||
// If there's no backend interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch A2DP OnError runnable");
|
||||
@@ -391,7 +391,7 @@ BluetoothA2dpManager::DeinitA2dpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!setupInterface)) {
|
||||
// If there's no Setup interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch A2DP OnError runnable");
|
||||
|
||||
@@ -172,7 +172,7 @@ private:
|
||||
};
|
||||
|
||||
class BluetoothAvrcpManager::InitProfileResultHandlerRunnable final
|
||||
: public nsRunnable
|
||||
: public Runnable
|
||||
{
|
||||
public:
|
||||
InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||
@@ -211,7 +211,7 @@ BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
|
||||
|
||||
if (sBtAvrcpInterface) {
|
||||
BT_LOGR("Bluetooth AVRCP interface is already initalized.");
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch AVRCP Init runnable");
|
||||
@@ -224,7 +224,7 @@ BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!btInf)) {
|
||||
// If there's no Bluetooth interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
|
||||
@@ -237,7 +237,7 @@ BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!setupInterface)) {
|
||||
// If there's no Setup interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
|
||||
@@ -250,7 +250,7 @@ BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!avrcpInterface)) {
|
||||
// If there's no AVRCP interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
|
||||
@@ -350,7 +350,7 @@ private:
|
||||
};
|
||||
|
||||
class BluetoothAvrcpManager::DeinitProfileResultHandlerRunnable final
|
||||
: public nsRunnable
|
||||
: public Runnable
|
||||
{
|
||||
public:
|
||||
DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||
@@ -386,7 +386,7 @@ BluetoothAvrcpManager::DeinitAvrcpInterface(BluetoothProfileResultHandler* aRes)
|
||||
|
||||
if (!sBtAvrcpInterface) {
|
||||
BT_LOGR("Bluetooth AVRCP interface has not been initalized.");
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch AVRCP Deinit runnable");
|
||||
@@ -399,7 +399,7 @@ BluetoothAvrcpManager::DeinitAvrcpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!btInf)) {
|
||||
// If there's no backend interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
|
||||
@@ -412,7 +412,7 @@ BluetoothAvrcpManager::DeinitAvrcpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!setupInterface)) {
|
||||
// If there's no Setup interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
|
||||
@@ -434,7 +434,7 @@ BluetoothAvrcpManager::HandleShutdown()
|
||||
sBluetoothAvrcpManager = nullptr;
|
||||
}
|
||||
|
||||
class BluetoothAvrcpManager::ConnectRunnable final : public nsRunnable
|
||||
class BluetoothAvrcpManager::ConnectRunnable final : public Runnable
|
||||
{
|
||||
public:
|
||||
ConnectRunnable(BluetoothAvrcpManager* aManager)
|
||||
@@ -467,7 +467,7 @@ BluetoothAvrcpManager::Connect(const BluetoothAddress& aDeviceAddress,
|
||||
NS_DispatchToMainThread(new ConnectRunnable(this));
|
||||
}
|
||||
|
||||
class BluetoothAvrcpManager::DisconnectRunnable final : public nsRunnable
|
||||
class BluetoothAvrcpManager::DisconnectRunnable final : public Runnable
|
||||
{
|
||||
public:
|
||||
DisconnectRunnable(BluetoothAvrcpManager* aManager)
|
||||
|
||||
@@ -88,16 +88,17 @@ BluetoothDaemonSocketModule::ConnectCmd(const BluetoothAddress& aBdAddr,
|
||||
/* |DeleteTask| deletes a class instance on the I/O thread
|
||||
*/
|
||||
template <typename T>
|
||||
class DeleteTask final : public Task
|
||||
class DeleteTask final : public Runnable
|
||||
{
|
||||
public:
|
||||
DeleteTask(T* aPtr)
|
||||
: mPtr(aPtr)
|
||||
{ }
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
mPtr = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -134,7 +135,7 @@ public:
|
||||
}
|
||||
|
||||
MessageLoopForIO::current()->PostTask(
|
||||
FROM_HERE, new DeleteTask<AcceptWatcher>(this));
|
||||
MakeAndAddRef<DeleteTask<AcceptWatcher>>(this));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -145,8 +146,8 @@ BluetoothDaemonSocketModule::AcceptCmd(int aFd,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
/* receive Bluedroid's socket-setup messages and client fd */
|
||||
Task* t = new SocketMessageWatcherTask(new AcceptWatcher(aFd, aRes));
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t);
|
||||
XRE_GetIOMessageLoop()->PostTask(
|
||||
MakeAndAddRef<SocketMessageWatcherTask>(new AcceptWatcher(aFd, aRes)));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -157,8 +158,8 @@ BluetoothDaemonSocketModule::CloseCmd(BluetoothSocketResultHandler* aRes)
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
/* stop the watcher corresponding to |aRes| */
|
||||
Task* t = new DeleteSocketMessageWatcherTask(aRes);
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t);
|
||||
XRE_GetIOMessageLoop()->PostTask(
|
||||
MakeAndAddRef<DeleteSocketMessageWatcherTask>(aRes));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -273,7 +274,7 @@ public:
|
||||
}
|
||||
|
||||
MessageLoopForIO::current()->PostTask(
|
||||
FROM_HERE, new DeleteTask<ConnectWatcher>(this));
|
||||
MakeAndAddRef<DeleteTask<ConnectWatcher>>(this));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -298,8 +299,8 @@ BluetoothDaemonSocketModule::ConnectRsp(const DaemonSocketPDUHeader& aHeader,
|
||||
}
|
||||
|
||||
/* receive Bluedroid's socket-setup messages */
|
||||
Task* t = new SocketMessageWatcherTask(new ConnectWatcher(fd, aRes));
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, t);
|
||||
XRE_GetIOMessageLoop()->PostTask(
|
||||
MakeAndAddRef<SocketMessageWatcherTask>(new ConnectWatcher(fd, aRes)));
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -465,7 +465,7 @@ private:
|
||||
};
|
||||
|
||||
class BluetoothGattManager::InitProfileResultHandlerRunnable final
|
||||
: public nsRunnable
|
||||
: public Runnable
|
||||
{
|
||||
public:
|
||||
InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||
@@ -501,7 +501,7 @@ BluetoothGattManager::InitGattInterface(BluetoothProfileResultHandler* aRes)
|
||||
|
||||
if (sBluetoothGattInterface) {
|
||||
BT_LOGR("Bluetooth GATT interface is already initalized.");
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch GATT Init runnable");
|
||||
@@ -514,7 +514,7 @@ BluetoothGattManager::InitGattInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!btInf)) {
|
||||
// If there's no Bluetooth interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch GATT OnError runnable");
|
||||
@@ -527,7 +527,7 @@ BluetoothGattManager::InitGattInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!setupInterface)) {
|
||||
// If there's no Setup interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch GATT OnError runnable");
|
||||
@@ -540,7 +540,7 @@ BluetoothGattManager::InitGattInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!gattInterface)) {
|
||||
// If there's no GATT interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch GATT OnError runnable");
|
||||
@@ -615,7 +615,7 @@ private:
|
||||
};
|
||||
|
||||
class BluetoothGattManager::DeinitProfileResultHandlerRunnable final
|
||||
: public nsRunnable
|
||||
: public Runnable
|
||||
{
|
||||
public:
|
||||
DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||
@@ -651,7 +651,7 @@ BluetoothGattManager::DeinitGattInterface(BluetoothProfileResultHandler* aRes)
|
||||
|
||||
if (!sBluetoothGattInterface) {
|
||||
BT_LOGR("Bluetooth GATT interface has not been initalized.");
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch GATT Deinit runnable");
|
||||
@@ -664,7 +664,7 @@ BluetoothGattManager::DeinitGattInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!btInf)) {
|
||||
// If there's no backend interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch GATT OnError runnable");
|
||||
@@ -677,7 +677,7 @@ BluetoothGattManager::DeinitGattInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!setupInterface)) {
|
||||
// If there's no Setup interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch GATT OnError runnable");
|
||||
|
||||
@@ -78,7 +78,7 @@ private:
|
||||
};
|
||||
|
||||
class BluetoothHidManager::InitProfileResultHandlerRunnable final
|
||||
: public nsRunnable
|
||||
: public Runnable
|
||||
{
|
||||
public:
|
||||
InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||
@@ -114,7 +114,7 @@ BluetoothHidManager::InitHidInterface(BluetoothProfileResultHandler* aRes)
|
||||
|
||||
if (sBluetoothHidInterface) {
|
||||
BT_LOGR("Bluetooth HID interface is already initialized.");
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HID Init runnable");
|
||||
@@ -127,7 +127,7 @@ BluetoothHidManager::InitHidInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!btInf)) {
|
||||
// If there's no backend interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HID OnError runnable");
|
||||
@@ -140,7 +140,7 @@ BluetoothHidManager::InitHidInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!setupInterface)) {
|
||||
// If there's no Setup interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HID OnError runnable");
|
||||
@@ -153,7 +153,7 @@ BluetoothHidManager::InitHidInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!hidinterface)) {
|
||||
// If there's no HID interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HID OnError runnable");
|
||||
@@ -230,7 +230,7 @@ private:
|
||||
};
|
||||
|
||||
class BluetoothHidManager::DeinitProfileResultHandlerRunnable final
|
||||
: public nsRunnable
|
||||
: public Runnable
|
||||
{
|
||||
public:
|
||||
DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||
@@ -266,7 +266,7 @@ BluetoothHidManager::DeinitHidInterface(BluetoothProfileResultHandler* aRes)
|
||||
|
||||
if (!sBluetoothHidInterface) {
|
||||
BT_LOGR("Bluetooth Hid interface has not been initialized.");
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HID Deinit runnable");
|
||||
@@ -279,7 +279,7 @@ BluetoothHidManager::DeinitHidInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!btInf)) {
|
||||
// If there's no backend interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HID OnError runnable");
|
||||
@@ -292,7 +292,7 @@ BluetoothHidManager::DeinitHidInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!setupInterface)) {
|
||||
// If there's no Setup interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HID OnError runnable");
|
||||
|
||||
@@ -102,7 +102,7 @@ BluetoothOppManager::Observe(nsISupports* aSubject,
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
class BluetoothOppManager::SendSocketDataTask final : public nsRunnable
|
||||
class BluetoothOppManager::SendSocketDataTask final : public Runnable
|
||||
{
|
||||
public:
|
||||
SendSocketDataTask(UniquePtr<uint8_t[]> aStream, uint32_t aSize)
|
||||
@@ -126,7 +126,7 @@ private:
|
||||
uint32_t mSize;
|
||||
};
|
||||
|
||||
class BluetoothOppManager::ReadFileTask final : public nsRunnable
|
||||
class BluetoothOppManager::ReadFileTask final : public Runnable
|
||||
{
|
||||
public:
|
||||
ReadFileTask(nsIInputStream* aInputStream,
|
||||
@@ -172,7 +172,7 @@ private:
|
||||
uint32_t mAvailablePacketSize;
|
||||
};
|
||||
|
||||
class BluetoothOppManager::CloseSocketTask final : public Task
|
||||
class BluetoothOppManager::CloseSocketTask final : public Runnable
|
||||
{
|
||||
public:
|
||||
CloseSocketTask(BluetoothSocket* aSocket) : mSocket(aSocket)
|
||||
@@ -180,10 +180,11 @@ public:
|
||||
MOZ_ASSERT(aSocket);
|
||||
}
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mSocket->Close();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1138,8 +1139,8 @@ BluetoothOppManager::ClientDataHandler(UnixSocketBuffer* aMessage)
|
||||
// Disconnect request, so we make a delay here. If the socket hasn't been
|
||||
// disconnected, we will close it.
|
||||
if (mSocket) {
|
||||
MessageLoop::current()->
|
||||
PostDelayedTask(FROM_HERE, new CloseSocketTask(mSocket), 1000);
|
||||
MessageLoop::current()->PostDelayedTask(
|
||||
MakeAndAddRef<CloseSocketTask>(mSocket), 1000);
|
||||
}
|
||||
} else if (mLastCommand == ObexRequestCode::Connect) {
|
||||
MOZ_ASSERT(!mFileName.IsEmpty());
|
||||
|
||||
@@ -200,12 +200,14 @@ public:
|
||||
, mFd(aFd)
|
||||
{ }
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(!GetIO()->IsConsumerThread());
|
||||
MOZ_ASSERT(!IsCanceled());
|
||||
|
||||
GetIO()->Connect(mFd);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -220,13 +222,14 @@ public:
|
||||
, mFd(aFd)
|
||||
{ }
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(!GetIO()->IsConsumerThread());
|
||||
|
||||
if (!IsCanceled()) {
|
||||
GetIO()->Listen(mFd);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -240,11 +243,13 @@ class SocketConnectClientFdTask final
|
||||
: SocketIOTask<DroidSocketImpl>(aImpl)
|
||||
{ }
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(!GetIO()->IsConsumerThread());
|
||||
|
||||
GetIO()->ConnectClientFd();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -303,7 +308,7 @@ DroidSocketImpl::Accept(int aFd)
|
||||
mConnectionStatus = SOCKET_IS_CONNECTED;
|
||||
|
||||
GetConsumerThread()->PostTask(
|
||||
FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_SUCCESS));
|
||||
MakeAndAddRef<SocketEventTask>(this, SocketEventTask::CONNECT_SUCCESS));
|
||||
|
||||
AddWatchers(READ_WATCHER, true);
|
||||
if (HasPendingData()) {
|
||||
@@ -347,12 +352,14 @@ public:
|
||||
, mFd(aFd)
|
||||
{ }
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(!GetIO()->IsConsumerThread());
|
||||
MOZ_ASSERT(!IsCanceled());
|
||||
|
||||
GetIO()->Accept(mFd);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -386,8 +393,8 @@ public:
|
||||
}
|
||||
|
||||
mImpl->mConsumer->SetAddress(aBdAddress);
|
||||
mImpl->GetIOLoop()->PostTask(FROM_HERE,
|
||||
new AcceptTask(mImpl, fd.forget()));
|
||||
mImpl->GetIOLoop()->PostTask(
|
||||
mozilla::MakeAndAddRef<AcceptTask>(mImpl, fd.forget()));
|
||||
}
|
||||
|
||||
void OnError(BluetoothStatus aStatus) override
|
||||
@@ -416,11 +423,13 @@ public:
|
||||
, mListenFd(aListenFd)
|
||||
{ }
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(GetIO()->IsConsumerThread());
|
||||
|
||||
GetIO()->mConsumer->Accept(mListenFd, new AcceptResultHandler(GetIO()));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -438,7 +447,7 @@ DroidSocketImpl::OnSocketCanAcceptWithoutBlocking(int aFd)
|
||||
*/
|
||||
|
||||
RemoveWatchers(READ_WATCHER);
|
||||
GetConsumerThread()->PostTask(FROM_HERE, new InvokeAcceptTask(this, aFd));
|
||||
GetConsumerThread()->PostTask(MakeAndAddRef<InvokeAcceptTask>(this, aFd));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -483,7 +492,7 @@ DroidSocketImpl::OnSocketCanConnectWithoutBlocking(int aFd)
|
||||
mConnectionStatus = SOCKET_IS_CONNECTED;
|
||||
|
||||
GetConsumerThread()->PostTask(
|
||||
FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_SUCCESS));
|
||||
MakeAndAddRef<SocketEventTask>(this, SocketEventTask::CONNECT_SUCCESS));
|
||||
|
||||
AddWatchers(READ_WATCHER, true);
|
||||
if (HasPendingData()) {
|
||||
@@ -519,7 +528,7 @@ public:
|
||||
, mBuffer(aBuffer)
|
||||
{ }
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
DroidSocketImpl* io = SocketTask<DroidSocketImpl>::GetIO();
|
||||
|
||||
@@ -528,13 +537,15 @@ public:
|
||||
if (NS_WARN_IF(io->IsShutdownOnConsumerThread())) {
|
||||
// Since we've already explicitly closed and the close
|
||||
// happened before this, this isn't really an error.
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
BluetoothSocket* bluetoothSocket = io->GetBluetoothSocket();
|
||||
MOZ_ASSERT(bluetoothSocket);
|
||||
|
||||
bluetoothSocket->ReceiveSocketData(mBuffer);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -544,8 +555,8 @@ private:
|
||||
void
|
||||
DroidSocketImpl::ConsumeBuffer()
|
||||
{
|
||||
GetConsumerThread()->PostTask(FROM_HERE,
|
||||
new ReceiveTask(this, mBuffer.release()));
|
||||
GetConsumerThread()->PostTask(
|
||||
MakeAndAddRef<ReceiveTask>(this, mBuffer.release()));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -605,8 +616,8 @@ public:
|
||||
}
|
||||
|
||||
mImpl->mConsumer->SetAddress(aBdAddress);
|
||||
mImpl->GetIOLoop()->PostTask(FROM_HERE,
|
||||
new SocketConnectTask(mImpl, aFd));
|
||||
mImpl->GetIOLoop()->PostTask(
|
||||
mozilla::MakeAndAddRef<SocketConnectTask>(mImpl, aFd));
|
||||
}
|
||||
|
||||
void OnError(BluetoothStatus aStatus) override
|
||||
@@ -682,7 +693,8 @@ public:
|
||||
{
|
||||
MOZ_ASSERT(mImpl->IsConsumerThread());
|
||||
|
||||
mImpl->GetIOLoop()->PostTask(FROM_HERE, new SocketListenTask(mImpl, aFd));
|
||||
mImpl->GetIOLoop()->PostTask(
|
||||
mozilla::MakeAndAddRef<SocketListenTask>(mImpl, aFd));
|
||||
}
|
||||
|
||||
void OnError(BluetoothStatus aStatus) override
|
||||
@@ -776,8 +788,8 @@ BluetoothSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
|
||||
MOZ_ASSERT(!mImpl->IsShutdownOnConsumerThread());
|
||||
|
||||
mImpl->GetIOLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
new SocketIOSendTask<DroidSocketImpl, UnixSocketIOBuffer>(mImpl, aBuffer));
|
||||
MakeAndAddRef<SocketIOSendTask<DroidSocketImpl, UnixSocketIOBuffer>>(
|
||||
mImpl, aBuffer));
|
||||
}
|
||||
|
||||
// |SocketBase|
|
||||
@@ -860,7 +872,7 @@ BluetoothSocket::Cleanup()
|
||||
// sever the relationship here so any future calls to listen
|
||||
// or connect will create a new implementation.
|
||||
mImpl->ShutdownOnConsumerThread();
|
||||
mImpl->GetIOLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mImpl));
|
||||
mImpl->GetIOLoop()->PostTask(MakeAndAddRef<SocketIOShutdownTask>(mImpl));
|
||||
mImpl = nullptr;
|
||||
|
||||
mSocketInterface = nullptr;
|
||||
|
||||
@@ -277,10 +277,11 @@ SocketMessageWatcherTask::SocketMessageWatcherTask(
|
||||
MOZ_ASSERT(mWatcher);
|
||||
}
|
||||
|
||||
void
|
||||
NS_IMETHODIMP
|
||||
SocketMessageWatcherTask::Run()
|
||||
{
|
||||
mWatcher->Watch();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -294,19 +295,20 @@ DeleteSocketMessageWatcherTask::DeleteSocketMessageWatcherTask(
|
||||
MOZ_ASSERT(mRes);
|
||||
}
|
||||
|
||||
void
|
||||
NS_IMETHODIMP
|
||||
DeleteSocketMessageWatcherTask::Run()
|
||||
{
|
||||
// look up hash table for the watcher corresponding to |mRes|
|
||||
SocketMessageWatcherWrapper* wrapper = sWatcherHashtable.Get(mRes);
|
||||
if (!wrapper) {
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// stop the watcher if it exists
|
||||
SocketMessageWatcher* watcher = wrapper->GetSocketMessageWatcher();
|
||||
watcher->StopWatching();
|
||||
watcher->Proceed(STATUS_DONE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
||||
@@ -84,12 +84,12 @@ private:
|
||||
/* |SocketMessageWatcherTask| starts a SocketMessageWatcher
|
||||
* on the I/O task
|
||||
*/
|
||||
class SocketMessageWatcherTask final : public Task
|
||||
class SocketMessageWatcherTask final : public Runnable
|
||||
{
|
||||
public:
|
||||
SocketMessageWatcherTask(SocketMessageWatcher* aWatcher);
|
||||
|
||||
void Run() override;
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
private:
|
||||
SocketMessageWatcher* mWatcher;
|
||||
@@ -98,12 +98,12 @@ private:
|
||||
/* |DeleteSocketMessageWatcherTask| deletes a watching SocketMessageWatcher
|
||||
* on the I/O task
|
||||
*/
|
||||
class DeleteSocketMessageWatcherTask final : public Task
|
||||
class DeleteSocketMessageWatcherTask final : public Runnable
|
||||
{
|
||||
public:
|
||||
DeleteSocketMessageWatcherTask(BluetoothSocketResultHandler* aRes);
|
||||
|
||||
void Run() override;
|
||||
NS_IMETHOD Run() override;
|
||||
|
||||
private:
|
||||
BluetoothSocketResultHandler* mRes;
|
||||
|
||||
@@ -108,17 +108,18 @@ protected:
|
||||
~GetVolumeTask() { }
|
||||
};
|
||||
|
||||
class BluetoothHfpManager::CloseScoTask : public Task
|
||||
class BluetoothHfpManager::CloseScoTask : public Runnable
|
||||
{
|
||||
private:
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(sBluetoothHfpManager);
|
||||
sBluetoothHfpManager->DisconnectSco();
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class BluetoothHfpManager::CloseScoRunnable : public nsRunnable
|
||||
class BluetoothHfpManager::CloseScoRunnable : public Runnable
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD Run() override
|
||||
@@ -126,16 +127,16 @@ public:
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MessageLoop::current()->PostDelayedTask(
|
||||
FROM_HERE, new CloseScoTask(), sBusyToneInterval);
|
||||
MakeAndAddRef<CloseScoTask>(), sBusyToneInterval);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class BluetoothHfpManager::RespondToBLDNTask : public Task
|
||||
class BluetoothHfpManager::RespondToBLDNTask : public Runnable
|
||||
{
|
||||
private:
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(sBluetoothHfpManager);
|
||||
|
||||
@@ -143,6 +144,7 @@ private:
|
||||
sBluetoothHfpManager->mDialingRequestProcessed = true;
|
||||
sBluetoothHfpManager->SendResponse(HFP_AT_RESPONSE_ERROR);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -319,7 +321,7 @@ private:
|
||||
};
|
||||
|
||||
class BluetoothHfpManager::InitProfileResultHandlerRunnable final
|
||||
: public nsRunnable
|
||||
: public Runnable
|
||||
{
|
||||
public:
|
||||
InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||
@@ -355,7 +357,7 @@ BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes)
|
||||
|
||||
if (sBluetoothHfpInterface) {
|
||||
BT_LOGR("Bluetooth Handsfree interface is already initalized.");
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HFP Init runnable");
|
||||
@@ -368,7 +370,7 @@ BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!btInf)) {
|
||||
// If there's no backend interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
||||
@@ -381,7 +383,7 @@ BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!setupInterface)) {
|
||||
// If there's no Setup interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
||||
@@ -394,7 +396,7 @@ BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!interface)) {
|
||||
// If there's no HFP interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
||||
@@ -471,7 +473,7 @@ private:
|
||||
};
|
||||
|
||||
class BluetoothHfpManager::DeinitProfileResultHandlerRunnable final
|
||||
: public nsRunnable
|
||||
: public Runnable
|
||||
{
|
||||
public:
|
||||
DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||
@@ -507,7 +509,7 @@ BluetoothHfpManager::DeinitHfpInterface(BluetoothProfileResultHandler* aRes)
|
||||
|
||||
if (!sBluetoothHfpInterface) {
|
||||
BT_LOGR("Bluetooth Handsfree interface has not been initialized.");
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HFP Deinit runnable");
|
||||
@@ -520,7 +522,7 @@ BluetoothHfpManager::DeinitHfpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!btInf)) {
|
||||
// If there's no backend interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
||||
@@ -533,7 +535,7 @@ BluetoothHfpManager::DeinitHfpInterface(BluetoothProfileResultHandler* aRes)
|
||||
if (NS_WARN_IF(!setupInterface)) {
|
||||
// If there's no Setup interface, we dispatch a runnable
|
||||
// that calls the profile result handler.
|
||||
RefPtr<nsRunnable> r =
|
||||
RefPtr<Runnable> r =
|
||||
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
||||
@@ -1597,8 +1599,7 @@ void BluetoothHfpManager::DialCallNotification(const nsAString& aNumber,
|
||||
mDialingRequestProcessed = false;
|
||||
NotifyDialer(NS_LITERAL_STRING("BLDN"));
|
||||
|
||||
MessageLoop::current()->PostDelayedTask(FROM_HERE,
|
||||
new RespondToBLDNTask(),
|
||||
MessageLoop::current()->PostDelayedTask(MakeAndAddRef<RespondToBLDNTask>(),
|
||||
sWaitingForDialingInterval);
|
||||
} else if (message[0] == '>') {
|
||||
mDialingRequestProcessed = false;
|
||||
@@ -1607,8 +1608,7 @@ void BluetoothHfpManager::DialCallNotification(const nsAString& aNumber,
|
||||
newMsg += StringHead(message, message.Length() - 1);
|
||||
NotifyDialer(NS_ConvertUTF8toUTF16(newMsg));
|
||||
|
||||
MessageLoop::current()->PostDelayedTask(FROM_HERE,
|
||||
new RespondToBLDNTask(),
|
||||
MessageLoop::current()->PostDelayedTask(MakeAndAddRef<RespondToBLDNTask>(),
|
||||
sWaitingForDialingInterval);
|
||||
} else {
|
||||
SendResponse(HFP_AT_RESPONSE_OK);
|
||||
@@ -1766,8 +1766,7 @@ BluetoothHfpManager::KeyPressedNotification(const BluetoothAddress& aBdAddress)
|
||||
|
||||
NotifyDialer(NS_LITERAL_STRING("BLDN"));
|
||||
|
||||
MessageLoop::current()->PostDelayedTask(FROM_HERE,
|
||||
new RespondToBLDNTask(),
|
||||
MessageLoop::current()->PostDelayedTask(MakeAndAddRef<RespondToBLDNTask>(),
|
||||
sWaitingForDialingInterval);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -242,10 +242,10 @@ BluetoothHfpManager::Notify(const hal::BatteryInformation& aBatteryInfo)
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
class BluetoothHfpManager::RespondToBLDNTask : public Task
|
||||
class BluetoothHfpManager::RespondToBLDNTask : public Runnable
|
||||
{
|
||||
private:
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(sBluetoothHfpManager);
|
||||
|
||||
@@ -253,10 +253,11 @@ private:
|
||||
sBluetoothHfpManager->mDialingRequestProcessed = true;
|
||||
sBluetoothHfpManager->SendLine("ERROR");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class BluetoothHfpManager::SendRingIndicatorTask : public Task
|
||||
class BluetoothHfpManager::SendRingIndicatorTask : public Runnable
|
||||
{
|
||||
public:
|
||||
SendRingIndicatorTask(const nsAString& aNumber, int aType)
|
||||
@@ -266,18 +267,18 @@ public:
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Stop sending RING indicator
|
||||
if (sStopSendingRingFlag) {
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!sBluetoothHfpManager) {
|
||||
BT_WARNING("BluetoothHfpManager no longer exists, cannot send ring!");
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString ringMsg("RING");
|
||||
@@ -291,10 +292,10 @@ public:
|
||||
sBluetoothHfpManager->SendLine(clipMsg.get());
|
||||
}
|
||||
|
||||
MessageLoop::current()->
|
||||
PostDelayedTask(FROM_HERE,
|
||||
new SendRingIndicatorTask(mNumber, mType),
|
||||
sRingInterval);
|
||||
MessageLoop::current()->PostDelayedTask(
|
||||
MakeAndAddRef<SendRingIndicatorTask>(mNumber, mType), sRingInterval);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -303,14 +304,16 @@ private:
|
||||
};
|
||||
#endif // MOZ_B2G_RIL
|
||||
|
||||
class BluetoothHfpManager::CloseScoTask : public Task
|
||||
class BluetoothHfpManager::CloseScoTask : public Runnable
|
||||
{
|
||||
private:
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(sBluetoothHfpManager);
|
||||
|
||||
sBluetoothHfpManager->DisconnectSco();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -985,7 +988,7 @@ BluetoothHfpManager::ReceiveSocketData(BluetoothSocket* aSocket,
|
||||
}
|
||||
|
||||
MessageLoop::current()->
|
||||
PostDelayedTask(FROM_HERE, new RespondToBLDNTask(),
|
||||
PostDelayedTask(MakeAndAddRef<RespondToBLDNTask>(),
|
||||
sWaitingForDialingInterval);
|
||||
|
||||
// Don't send response 'OK' here because we'll respond later in either
|
||||
@@ -1490,7 +1493,7 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
|
||||
}
|
||||
mCurrentCallArray[aCallIndex].mNumber = aNumber;
|
||||
|
||||
RefPtr<nsRunnable> sendRingTask;
|
||||
RefPtr<Runnable> sendRingTask;
|
||||
nsString address;
|
||||
|
||||
switch (aCallState) {
|
||||
@@ -1576,9 +1579,8 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
|
||||
}
|
||||
|
||||
MessageLoop::current()->PostDelayedTask(
|
||||
FROM_HERE,
|
||||
new SendRingIndicatorTask(number,
|
||||
mCurrentCallArray[aCallIndex].mType),
|
||||
MakeAndAddRef<SendRingIndicatorTask>(
|
||||
number, mCurrentCallArray[aCallIndex].mType),
|
||||
sRingInterval);
|
||||
}
|
||||
break;
|
||||
@@ -1686,8 +1688,7 @@ BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
|
||||
DisconnectSco();
|
||||
} else {
|
||||
// Close Sco later since Dialer is still playing busy tone via HF.
|
||||
MessageLoop::current()->PostDelayedTask(FROM_HERE,
|
||||
new CloseScoTask(),
|
||||
MessageLoop::current()->PostDelayedTask(MakeAndAddRef<CloseScoTask>(),
|
||||
sBusyToneInterval);
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ BluetoothOppManager::Observe(nsISupports* aSubject,
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
class SendSocketDataTask : public nsRunnable
|
||||
class SendSocketDataTask : public Runnable
|
||||
{
|
||||
public:
|
||||
SendSocketDataTask(UniquePtr<uint8_t[]> aStream, uint32_t aSize)
|
||||
@@ -121,7 +121,7 @@ private:
|
||||
uint32_t mSize;
|
||||
};
|
||||
|
||||
class ReadFileTask : public nsRunnable
|
||||
class ReadFileTask : public Runnable
|
||||
{
|
||||
public:
|
||||
ReadFileTask(nsIInputStream* aInputStream,
|
||||
@@ -167,7 +167,7 @@ private:
|
||||
uint32_t mAvailablePacketSize;
|
||||
};
|
||||
|
||||
class CloseSocketTask : public Task
|
||||
class CloseSocketTask : public Runnable
|
||||
{
|
||||
public:
|
||||
CloseSocketTask(BluetoothSocket* aSocket) : mSocket(aSocket)
|
||||
@@ -175,7 +175,7 @@ public:
|
||||
MOZ_ASSERT(aSocket);
|
||||
}
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
@@ -183,6 +183,7 @@ public:
|
||||
SocketConnectionStatus::SOCKET_CONNECTED) {
|
||||
mSocket->Close();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1076,7 +1077,7 @@ BluetoothOppManager::ClientDataHandler(UnixSocketBuffer* aMessage)
|
||||
// disconnected, we will close it.
|
||||
if (mSocket) {
|
||||
MessageLoop::current()->
|
||||
PostDelayedTask(FROM_HERE, new CloseSocketTask(mSocket), 1000);
|
||||
PostDelayedTask(MakeAndAddRef<CloseSocketTask>(mSocket), 1000);
|
||||
}
|
||||
} else if (mLastCommand == ObexRequestCode::Connect) {
|
||||
MOZ_ASSERT(!mFileName.IsEmpty());
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
// Delayed-task handling
|
||||
//
|
||||
|
||||
void SetDelayedConnectTask(CancelableTask* aTask);
|
||||
void SetDelayedConnectTask(CancelableRunnable* aTask);
|
||||
void ClearDelayedConnectTask();
|
||||
void CancelDelayedConnectTask();
|
||||
|
||||
@@ -126,7 +126,7 @@ private:
|
||||
* Task member for delayed connect task. Should only be access on consumer
|
||||
* thread.
|
||||
*/
|
||||
CancelableTask* mDelayedConnectTask;
|
||||
CancelableRunnable* mDelayedConnectTask;
|
||||
|
||||
/**
|
||||
* I/O buffer for received data
|
||||
@@ -193,7 +193,7 @@ BluetoothSocket::BluetoothSocketIO::GetDataSocket()
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothSocket::BluetoothSocketIO::SetDelayedConnectTask(CancelableTask* aTask)
|
||||
BluetoothSocket::BluetoothSocketIO::SetDelayedConnectTask(CancelableRunnable* aTask)
|
||||
{
|
||||
MOZ_ASSERT(IsConsumerThread());
|
||||
|
||||
@@ -285,7 +285,7 @@ BluetoothSocket::BluetoothSocketIO::OnConnected()
|
||||
MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
|
||||
|
||||
GetConsumerThread()->PostTask(
|
||||
FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_SUCCESS));
|
||||
MakeAndAddRef<SocketEventTask>(this, SocketEventTask::CONNECT_SUCCESS));
|
||||
|
||||
AddWatchers(READ_WATCHER, true);
|
||||
if (HasPendingData()) {
|
||||
@@ -334,7 +334,7 @@ BluetoothSocket::BluetoothSocketIO::OnSocketCanAcceptWithoutBlocking()
|
||||
SetSocket(fd, SOCKET_IS_CONNECTED);
|
||||
|
||||
GetConsumerThread()->PostTask(
|
||||
FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_SUCCESS));
|
||||
MakeAndAddRef<SocketEventTask>(this, SocketEventTask::CONNECT_SUCCESS));
|
||||
|
||||
AddWatchers(READ_WATCHER, true);
|
||||
if (HasPendingData()) {
|
||||
@@ -384,7 +384,7 @@ BluetoothSocket::BluetoothSocketIO::FireSocketError()
|
||||
|
||||
// Tell the consumer thread we've errored
|
||||
GetConsumerThread()->PostTask(
|
||||
FROM_HERE, new SocketEventTask(this, SocketEventTask::CONNECT_ERROR));
|
||||
MakeAndAddRef<SocketEventTask>(this, SocketEventTask::CONNECT_ERROR));
|
||||
}
|
||||
|
||||
// |DataSocketIO|
|
||||
@@ -416,7 +416,7 @@ public:
|
||||
, mBuffer(aBuffer)
|
||||
{ }
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
BluetoothSocketIO* io = SocketTask<BluetoothSocketIO>::GetIO();
|
||||
|
||||
@@ -425,13 +425,15 @@ public:
|
||||
if (NS_WARN_IF(io->IsShutdownOnConsumerThread())) {
|
||||
// Since we've already explicitly closed and the close
|
||||
// happened before this, this isn't really an error.
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
BluetoothSocket* bluetoothSocket = io->GetBluetoothSocket();
|
||||
MOZ_ASSERT(bluetoothSocket);
|
||||
|
||||
bluetoothSocket->ReceiveSocketData(mBuffer);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -441,8 +443,8 @@ private:
|
||||
void
|
||||
BluetoothSocket::BluetoothSocketIO::ConsumeBuffer()
|
||||
{
|
||||
GetConsumerThread()->PostTask(FROM_HERE,
|
||||
new ReceiveTask(this, mBuffer.release()));
|
||||
GetConsumerThread()->PostTask(
|
||||
MakeAndAddRef<ReceiveTask>(this, mBuffer.release()));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -505,13 +507,14 @@ public:
|
||||
: SocketIOTask<BluetoothSocketIO>(aIO)
|
||||
{ }
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(!GetIO()->IsConsumerThread());
|
||||
|
||||
if (!IsCanceled()) {
|
||||
GetIO()->Listen();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -523,12 +526,14 @@ public:
|
||||
: SocketIOTask<BluetoothSocketIO>(aIO)
|
||||
{ }
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(!GetIO()->IsConsumerThread());
|
||||
MOZ_ASSERT(!IsCanceled());
|
||||
|
||||
GetIO()->Connect();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -540,21 +545,23 @@ public:
|
||||
: SocketIOTask<BluetoothSocketIO>(aIO)
|
||||
{ }
|
||||
|
||||
void Run() override
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(GetIO()->IsConsumerThread());
|
||||
|
||||
if (IsCanceled()) {
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
BluetoothSocketIO* io = GetIO();
|
||||
if (io->IsShutdownOnConsumerThread()) {
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
io->ClearDelayedConnectTask();
|
||||
io->GetIOLoop()->PostTask(FROM_HERE, new ConnectTask(io));
|
||||
io->GetIOLoop()->PostTask(MakeAndAddRef<ConnectTask>(io));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -670,11 +677,12 @@ BluetoothSocket::Connect(BluetoothUnixSocketConnector* aConnector,
|
||||
SetConnectionStatus(SOCKET_CONNECTING);
|
||||
|
||||
if (aDelayMs > 0) {
|
||||
DelayedConnectTask* connectTask = new DelayedConnectTask(mIO);
|
||||
RefPtr<DelayedConnectTask> connectTask =
|
||||
MakeAndAddRef<DelayedConnectTask>(mIO);
|
||||
mIO->SetDelayedConnectTask(connectTask);
|
||||
MessageLoop::current()->PostDelayedTask(FROM_HERE, connectTask, aDelayMs);
|
||||
MessageLoop::current()->PostDelayedTask(connectTask.forget(), aDelayMs);
|
||||
} else {
|
||||
aIOLoop->PostTask(FROM_HERE, new ConnectTask(mIO));
|
||||
aIOLoop->PostTask(MakeAndAddRef<ConnectTask>(mIO));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@@ -700,7 +708,7 @@ BluetoothSocket::Listen(BluetoothUnixSocketConnector* aConnector,
|
||||
mIO = new BluetoothSocketIO(aConsumerLoop, aIOLoop, this, aConnector);
|
||||
SetConnectionStatus(SOCKET_LISTENING);
|
||||
|
||||
aIOLoop->PostTask(FROM_HERE, new ListenTask(mIO));
|
||||
aIOLoop->PostTask(MakeAndAddRef<ListenTask>(mIO));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -733,8 +741,7 @@ BluetoothSocket::SendSocketData(UnixSocketIOBuffer* aBuffer)
|
||||
MOZ_ASSERT(!mIO->IsShutdownOnConsumerThread());
|
||||
|
||||
mIO->GetIOLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
new SocketIOSendTask<BluetoothSocketIO, UnixSocketIOBuffer>(mIO, aBuffer));
|
||||
MakeAndAddRef<SocketIOSendTask<BluetoothSocketIO, UnixSocketIOBuffer>>(mIO, aBuffer));
|
||||
}
|
||||
|
||||
// |SocketBase|
|
||||
@@ -754,7 +761,7 @@ BluetoothSocket::Close()
|
||||
// We sever the relationship here so any future calls to listen or connect
|
||||
// will create a new implementation.
|
||||
mIO->ShutdownOnConsumerThread();
|
||||
mIO->GetIOLoop()->PostTask(FROM_HERE, new SocketIOShutdownTask(mIO));
|
||||
mIO->GetIOLoop()->PostTask(MakeAndAddRef<SocketIOShutdownTask>(mIO));
|
||||
mIO = nullptr;
|
||||
|
||||
NotifyDisconnect();
|
||||
|
||||
@@ -25,7 +25,7 @@ BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothReply;
|
||||
|
||||
class BluetoothReplyRunnable : public nsRunnable
|
||||
class BluetoothReplyRunnable : public Runnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
@@ -96,7 +96,7 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
class BluetoothReplyTaskQueue : public nsRunnable
|
||||
class BluetoothReplyTaskQueue : public Runnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
@@ -434,7 +434,7 @@ BluetoothService::StartBluetooth(bool aIsStartup,
|
||||
}
|
||||
} else {
|
||||
BT_WARNING("Bluetooth has already been enabled before.");
|
||||
RefPtr<nsRunnable> runnable = new BluetoothService::ToggleBtAck(true);
|
||||
RefPtr<Runnable> runnable = new BluetoothService::ToggleBtAck(true);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
|
||||
BT_WARNING("Failed to dispatch to main thread!");
|
||||
}
|
||||
@@ -465,7 +465,7 @@ BluetoothService::StopBluetooth(bool aIsStartup,
|
||||
}
|
||||
} else {
|
||||
BT_WARNING("Bluetooth has already been enabled/disabled before.");
|
||||
RefPtr<nsRunnable> runnable = new BluetoothService::ToggleBtAck(false);
|
||||
RefPtr<Runnable> runnable = new BluetoothService::ToggleBtAck(false);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
|
||||
BT_WARNING("Failed to dispatch to main thread!");
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class BluetoothService : public nsIObserver
|
||||
friend class StartupTask;
|
||||
|
||||
public:
|
||||
class ToggleBtAck : public nsRunnable
|
||||
class ToggleBtAck : public Runnable
|
||||
{
|
||||
public:
|
||||
ToggleBtAck(bool aEnabled);
|
||||
|
||||
@@ -897,9 +897,9 @@ private:
|
||||
{
|
||||
mService->AssignAppUuid(mServer->mAppUuid);
|
||||
|
||||
RefPtr<nsRunnable> runnable = new AddServiceTaskQueue(mServer,
|
||||
mService,
|
||||
mPromise);
|
||||
RefPtr<Runnable> runnable = new AddServiceTaskQueue(mServer,
|
||||
mService,
|
||||
mPromise);
|
||||
nsresult rv = NS_DispatchToMainThread(runnable.forget());
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
||||
@@ -153,7 +153,7 @@ TestGonkCameraHardwareListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||
OnTakePictureError(mTarget);
|
||||
} else if (errorType.EqualsLiteral("system")) {
|
||||
if (!NS_WARN_IF(!mCameraThread)) {
|
||||
class DeferredSystemFailure : public nsRunnable
|
||||
class DeferredSystemFailure : public Runnable
|
||||
{
|
||||
public:
|
||||
DeferredSystemFailure(nsGonkCameraControl* aTarget)
|
||||
@@ -228,7 +228,7 @@ TestGonkCameraHardwareListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||
|
||||
NS_IMPL_ISUPPORTS(TestGonkCameraHardwareListener, nsIDOMEventListener)
|
||||
|
||||
class TestGonkCameraHardware::ControlMessage : public nsRunnable
|
||||
class TestGonkCameraHardware::ControlMessage : public Runnable
|
||||
{
|
||||
public:
|
||||
ControlMessage(TestGonkCameraHardware* aTestHw)
|
||||
|
||||
@@ -115,10 +115,9 @@ CryptoBuffer::FromJwkBase64(const nsString& aBase64)
|
||||
NS_ConvertUTF16toUTF8 temp(aBase64);
|
||||
temp.StripWhitespace();
|
||||
|
||||
Base64URLDecodeOptions options;
|
||||
// JWK prohibits padding per RFC 7515, section 2.
|
||||
options.mPadding = Base64URLDecodePadding::Reject;
|
||||
nsresult rv = Base64URLDecode(temp, options, *this);
|
||||
nsresult rv = Base64URLDecode(temp, Base64URLDecodePaddingPolicy::Reject,
|
||||
*this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
@@ -134,9 +133,8 @@ CryptoBuffer::ToJwkBase64(nsString& aBase64)
|
||||
}
|
||||
|
||||
nsAutoCString base64;
|
||||
Base64URLEncodeOptions options;
|
||||
options.mPad = false;
|
||||
nsresult rv = Base64URLEncode(Length(), Elements(), options, base64);
|
||||
nsresult rv = Base64URLEncode(Length(), Elements(),
|
||||
Base64URLEncodePaddingPolicy::Omit, base64);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
CopyASCIItoUTF16(base64, aBase64);
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
/* -*- 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 "mozilla/dom/DataStore.h"
|
||||
#include "mozilla/dom/DataStoreCursor.h"
|
||||
#include "mozilla/dom/DataStoreBinding.h"
|
||||
#include "mozilla/dom/DataStoreImplBinding.h"
|
||||
#include "mozilla/dom/Navigator.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "AccessCheck.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(DataStore, DOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(DataStore, DOMEventTargetHelper)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DataStore)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(DataStore, DOMEventTargetHelper, mStore)
|
||||
|
||||
DataStore::DataStore(nsPIDOMWindowInner* aWindow)
|
||||
: DOMEventTargetHelper(aWindow)
|
||||
{
|
||||
}
|
||||
|
||||
DataStore::~DataStore()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<DataStore>
|
||||
DataStore::Constructor(GlobalObject& aGlobal, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowInner> window =
|
||||
do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<DataStore> store = new DataStore(window);
|
||||
return store.forget();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
DataStore::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return DataStoreBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
/*static*/ bool
|
||||
DataStore::EnabledForScope(JSContext* aCx, JS::Handle<JSObject*> aObj)
|
||||
{
|
||||
// Only expose the interface when it is:
|
||||
// 1. enabled by the preference and
|
||||
// 2. accessed by the chrome codes in Gecko.
|
||||
return (Navigator::HasDataStoreSupport(aCx, aObj) &&
|
||||
nsContentUtils::ThreadsafeIsCallerChrome());
|
||||
}
|
||||
|
||||
void
|
||||
DataStore::GetName(nsAString& aName, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mStore);
|
||||
|
||||
nsAutoString name;
|
||||
mStore->GetName(name, aRv);
|
||||
aName.Assign(name);
|
||||
}
|
||||
|
||||
void
|
||||
DataStore::GetOwner(nsAString& aOwner, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mStore);
|
||||
|
||||
nsAutoString owner;
|
||||
mStore->GetOwner(owner, aRv);
|
||||
aOwner.Assign(owner);
|
||||
}
|
||||
|
||||
bool
|
||||
DataStore::GetReadOnly(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mStore);
|
||||
|
||||
return mStore->GetReadOnly(aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
DataStore::Get(const Sequence<OwningStringOrUnsignedLong>& aId,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mStore);
|
||||
|
||||
return mStore->Get(aId, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
DataStore::Put(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aObj,
|
||||
const StringOrUnsignedLong& aId,
|
||||
const nsAString& aRevisionId,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mStore);
|
||||
|
||||
return mStore->Put(aObj, aId, aRevisionId, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
DataStore::Add(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aObj,
|
||||
const Optional<StringOrUnsignedLong>& aId,
|
||||
const nsAString& aRevisionId,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mStore);
|
||||
|
||||
return mStore->Add(aObj, aId, aRevisionId, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
DataStore::Remove(const StringOrUnsignedLong& aId,
|
||||
const nsAString& aRevisionId,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mStore);
|
||||
|
||||
return mStore->Remove(aId, aRevisionId, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
DataStore::Clear(const nsAString& aRevisionId, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mStore);
|
||||
|
||||
return mStore->Clear(aRevisionId, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
DataStore::GetRevisionId(nsAString& aRevisionId, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mStore);
|
||||
|
||||
nsAutoString revisionId;
|
||||
mStore->GetRevisionId(revisionId, aRv);
|
||||
aRevisionId.Assign(revisionId);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
DataStore::GetLength(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mStore);
|
||||
|
||||
return mStore->GetLength(aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<DataStoreCursor>
|
||||
DataStore::Sync(const nsAString& aRevisionId, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mStore);
|
||||
|
||||
return mStore->Sync(aRevisionId, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
DataStore::SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mStore);
|
||||
|
||||
mStore = &aStore;
|
||||
mStore->SetEventTarget(*this, aRv);
|
||||
}
|
||||
|
||||
} //namespace dom
|
||||
} //namespace mozilla
|
||||
@@ -1,96 +0,0 @@
|
||||
/* -*- 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_DataStore_h
|
||||
#define mozilla_dom_DataStore_h
|
||||
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class Promise;
|
||||
class DataStoreCursor;
|
||||
class DataStoreImpl;
|
||||
class StringOrUnsignedLong;
|
||||
class OwningStringOrUnsignedLong;
|
||||
|
||||
class DataStore final : public DOMEventTargetHelper
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DataStore,
|
||||
DOMEventTargetHelper)
|
||||
|
||||
explicit DataStore(nsPIDOMWindowInner* aWindow);
|
||||
|
||||
// WebIDL (internal functions)
|
||||
|
||||
static already_AddRefed<DataStore> Constructor(GlobalObject& aGlobal,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
static bool EnabledForScope(JSContext* aCx, JS::Handle<JSObject*> aObj);
|
||||
|
||||
// WebIDL (public APIs)
|
||||
|
||||
void GetName(nsAString& aName, ErrorResult& aRv);
|
||||
|
||||
void GetOwner(nsAString& aOwner, ErrorResult& aRv);
|
||||
|
||||
bool GetReadOnly(ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> Get(const Sequence<OwningStringOrUnsignedLong>& aId,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> Put(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aObj,
|
||||
const StringOrUnsignedLong& aId,
|
||||
const nsAString& aRevisionId,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> Add(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aObj,
|
||||
const Optional<StringOrUnsignedLong>& aId,
|
||||
const nsAString& aRevisionId,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> Remove(const StringOrUnsignedLong& aId,
|
||||
const nsAString& aRevisionId,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> Clear(const nsAString& aRevisionId,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void GetRevisionId(nsAString& aRevisionId, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> GetLength(ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<DataStoreCursor> Sync(const nsAString& aRevisionId,
|
||||
ErrorResult& aRv);
|
||||
|
||||
IMPL_EVENT_HANDLER(change)
|
||||
|
||||
// This internal function (ChromeOnly) is aimed to make the DataStore keep a
|
||||
// reference to the DataStoreImpl which really implements the API's logic in
|
||||
// JS. We also need to let the DataStoreImpl implementation keep the event
|
||||
// target of DataStore, so that it can know where to fire the events.
|
||||
void SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
~DataStore();
|
||||
|
||||
RefPtr<DataStoreImpl> mStore;
|
||||
};
|
||||
|
||||
} //namespace dom
|
||||
} //namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -1,2 +0,0 @@
|
||||
component {db5c9602-030f-4bff-a3de-881a8de370f2} DataStoreImpl.js
|
||||
contract @mozilla.org/dom/datastore;1 {db5c9602-030f-4bff-a3de-881a8de370f2}
|
||||
@@ -1,54 +0,0 @@
|
||||
/* -*- 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_DataStoreCallbacks_h
|
||||
#define mozilla_dom_DataStoreCallbacks_h
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class DataStoreDB;
|
||||
|
||||
class DataStoreDBCallback
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
|
||||
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
|
||||
|
||||
enum RunStatus {
|
||||
Success,
|
||||
CreatedSchema,
|
||||
Error
|
||||
};
|
||||
|
||||
virtual void Run(DataStoreDB* aDb, RunStatus aStatus) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~DataStoreDBCallback()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DataStoreRevisionCallback
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
|
||||
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
|
||||
|
||||
virtual void Run(const nsAString& aRevisionID) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~DataStoreRevisionCallback()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_DataStoreCallbacks_h
|
||||
@@ -1,223 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict"
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["DataStoreChangeNotifier"];
|
||||
|
||||
function debug(s) {
|
||||
//dump('DEBUG DataStoreChangeNotifier: ' + s + '\n');
|
||||
}
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageBroadcaster");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "dataStoreService",
|
||||
"@mozilla.org/datastore-service;1",
|
||||
"nsIDataStoreService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "systemMessenger",
|
||||
"@mozilla.org/system-message-internal;1",
|
||||
"nsISystemMessagesInternal");
|
||||
|
||||
var kSysMsgOnChangeShortTimeoutSec =
|
||||
Services.prefs.getIntPref("dom.datastore.sysMsgOnChangeShortTimeoutSec");
|
||||
var kSysMsgOnChangeLongTimeoutSec =
|
||||
Services.prefs.getIntPref("dom.datastore.sysMsgOnChangeLongTimeoutSec");
|
||||
|
||||
this.DataStoreChangeNotifier = {
|
||||
children: [],
|
||||
messages: [ "DataStore:Changed", "DataStore:RegisterForMessages",
|
||||
"DataStore:UnregisterForMessages",
|
||||
"child-process-shutdown" ],
|
||||
|
||||
// These hashes are used for storing the mapping between the datastore
|
||||
// identifiers (name | owner manifest URL) and their correspondent timers.
|
||||
// The object literal is defined as below:
|
||||
//
|
||||
// {
|
||||
// "datastore name 1|owner manifest URL 1": timer1,
|
||||
// "datastore name 2|owner manifest URL 2": timer2,
|
||||
// ...
|
||||
// }
|
||||
sysMsgOnChangeShortTimers: {},
|
||||
sysMsgOnChangeLongTimers: {},
|
||||
|
||||
init: function() {
|
||||
debug("init");
|
||||
|
||||
this.messages.forEach((function(msgName) {
|
||||
ppmm.addMessageListener(msgName, this);
|
||||
}).bind(this));
|
||||
|
||||
Services.obs.addObserver(this, 'xpcom-shutdown', false);
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
debug("observe");
|
||||
|
||||
switch (aTopic) {
|
||||
case 'xpcom-shutdown':
|
||||
this.messages.forEach((function(msgName) {
|
||||
ppmm.removeMessageListener(msgName, this);
|
||||
}).bind(this));
|
||||
|
||||
Services.obs.removeObserver(this, 'xpcom-shutdown');
|
||||
ppmm = null;
|
||||
break;
|
||||
|
||||
default:
|
||||
debug("Wrong observer topic: " + aTopic);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
broadcastMessage: function broadcastMessage(aData) {
|
||||
debug("broadcast");
|
||||
|
||||
this.children.forEach(function(obj) {
|
||||
if (obj.store == aData.store && obj.owner == aData.owner) {
|
||||
obj.mm.sendAsyncMessage("DataStore:Changed:Return:OK", aData);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
broadcastSystemMessage: function(aStore, aOwner) {
|
||||
debug("broadcastSystemMessage");
|
||||
|
||||
// Clear relevant timers.
|
||||
var storeKey = aStore + "|" + aOwner;
|
||||
var shortTimer = this.sysMsgOnChangeShortTimers[storeKey];
|
||||
if (shortTimer) {
|
||||
shortTimer.cancel();
|
||||
delete this.sysMsgOnChangeShortTimers[storeKey];
|
||||
}
|
||||
var longTimer = this.sysMsgOnChangeLongTimers[storeKey];
|
||||
if (longTimer) {
|
||||
longTimer.cancel();
|
||||
delete this.sysMsgOnChangeLongTimers[storeKey];
|
||||
}
|
||||
|
||||
systemMessenger.broadcastMessage("datastore-update-" + aStore,
|
||||
{ owner: aOwner });
|
||||
},
|
||||
|
||||
// Use the following logic to broadcast system messages in a moderate pattern.
|
||||
// 1. When an entry is changed, start a short timer and a long timer.
|
||||
// 2. If an entry is changed while the short timer is running, reset it.
|
||||
// Do not reset the long timer.
|
||||
// 3. Once either fires, broadcast the system message and cancel both timers.
|
||||
setSystemMessageTimeout: function(aStore, aOwner) {
|
||||
debug("setSystemMessageTimeout");
|
||||
|
||||
var storeKey = aStore + "|" + aOwner;
|
||||
|
||||
// Reset the short timer.
|
||||
var shortTimer = this.sysMsgOnChangeShortTimers[storeKey];
|
||||
if (!shortTimer) {
|
||||
shortTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this.sysMsgOnChangeShortTimers[storeKey] = shortTimer;
|
||||
} else {
|
||||
shortTimer.cancel();
|
||||
}
|
||||
shortTimer.initWithCallback({ notify: this.broadcastSystemMessage.bind(this, aStore, aOwner) },
|
||||
kSysMsgOnChangeShortTimeoutSec * 1000,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
|
||||
// Set the long timer if necessary.
|
||||
if (!this.sysMsgOnChangeLongTimers[storeKey]) {
|
||||
var longTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this.sysMsgOnChangeLongTimers[storeKey] = longTimer;
|
||||
longTimer.initWithCallback({ notify: this.broadcastSystemMessage.bind(this, aStore, aOwner) },
|
||||
kSysMsgOnChangeLongTimeoutSec * 1000,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
debug("receiveMessage ");
|
||||
|
||||
// No check has to be done when the message is 'child-process-shutdown'.
|
||||
if (aMessage.name != "child-process-shutdown") {
|
||||
let principal = aMessage.principal;
|
||||
if (!principal || !dataStoreService.checkPermission(principal)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "DataStore:Changed":
|
||||
this.broadcastMessage(aMessage.data);
|
||||
if (Services.prefs.getBoolPref("dom.sysmsg.enabled")) {
|
||||
this.setSystemMessageTimeout(aMessage.data.store, aMessage.data.owner);
|
||||
}
|
||||
break;
|
||||
|
||||
case "DataStore:RegisterForMessages":
|
||||
debug("Register!");
|
||||
|
||||
for (let i = 0; i < this.children.length; ++i) {
|
||||
if (this.children[i].mm == aMessage.target &&
|
||||
this.children[i].store == aMessage.data.store &&
|
||||
this.children[i].owner == aMessage.data.owner) {
|
||||
debug("Register on existing index: " + i);
|
||||
this.children[i].windows.push(aMessage.data.innerWindowID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.children.push({ mm: aMessage.target,
|
||||
store: aMessage.data.store,
|
||||
owner: aMessage.data.owner,
|
||||
windows: [ aMessage.data.innerWindowID ]});
|
||||
break;
|
||||
|
||||
case "DataStore:UnregisterForMessages":
|
||||
debug("Unregister");
|
||||
|
||||
for (let i = 0; i < this.children.length; ++i) {
|
||||
if (this.children[i].mm == aMessage.target) {
|
||||
debug("Unregister index: " + i);
|
||||
|
||||
var pos = this.children[i].windows.indexOf(aMessage.data.innerWindowID);
|
||||
if (pos != -1) {
|
||||
this.children[i].windows.splice(pos, 1);
|
||||
}
|
||||
|
||||
if (this.children[i].windows.length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
debug("Unregister delete index: " + i);
|
||||
this.children.splice(i, 1);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "child-process-shutdown":
|
||||
debug("Child process shutdown");
|
||||
|
||||
for (let i = 0; i < this.children.length; ++i) {
|
||||
if (this.children[i].mm == aMessage.target) {
|
||||
debug("Unregister index: " + i);
|
||||
this.children.splice(i, 1);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
debug("Wrong message: " + aMessage.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DataStoreChangeNotifier.init();
|
||||
@@ -1,79 +0,0 @@
|
||||
/* -*- 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 "mozilla/dom/DataStore.h"
|
||||
#include "mozilla/dom/DataStoreCursor.h"
|
||||
#include "mozilla/dom/DataStoreBinding.h"
|
||||
#include "mozilla/dom/DataStoreImplBinding.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(DataStoreCursor)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(DataStoreCursor)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataStoreCursor)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(DataStoreCursor, mCursor)
|
||||
|
||||
already_AddRefed<DataStoreCursor>
|
||||
DataStoreCursor::Constructor(GlobalObject& aGlobal, ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<DataStoreCursor> cursor = new DataStoreCursor();
|
||||
return cursor.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
DataStoreCursor::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto,
|
||||
JS::MutableHandle<JSObject*> aReflector)
|
||||
{
|
||||
return DataStoreCursorBinding::Wrap(aCx, this, aGivenProto, aReflector);
|
||||
}
|
||||
|
||||
already_AddRefed<DataStore>
|
||||
DataStoreCursor::GetStore(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mCursor);
|
||||
|
||||
return mCursor->GetStore(aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
DataStoreCursor::Next(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mCursor);
|
||||
|
||||
return mCursor->Next(aRv);
|
||||
}
|
||||
|
||||
void
|
||||
DataStoreCursor::Close(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mCursor);
|
||||
|
||||
mCursor->Close(aRv);
|
||||
}
|
||||
|
||||
void
|
||||
DataStoreCursor::SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mCursor);
|
||||
|
||||
mCursor = &aCursor;
|
||||
}
|
||||
|
||||
} //namespace dom
|
||||
} //namespace mozilla
|
||||
@@ -1,59 +0,0 @@
|
||||
/* -*- 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_DataStoreCursor_h
|
||||
#define mozilla_dom_DataStoreCursor_h
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class Promise;
|
||||
class DataStore;
|
||||
class GlobalObject;
|
||||
class DataStoreCursorImpl;
|
||||
|
||||
class DataStoreCursor final : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(DataStoreCursor)
|
||||
|
||||
// WebIDL (internal functions)
|
||||
|
||||
static already_AddRefed<DataStoreCursor> Constructor(GlobalObject& aGlobal,
|
||||
ErrorResult& aRv);
|
||||
|
||||
bool WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector);
|
||||
|
||||
// WebIDL (public APIs)
|
||||
|
||||
already_AddRefed<DataStore> GetStore(ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise> Next(ErrorResult& aRv);
|
||||
|
||||
void Close(ErrorResult& aRv);
|
||||
|
||||
// This internal function (ChromeOnly) is aimed to make the DataStoreCursor
|
||||
// keep a reference to the DataStoreCursorImpl which really implements the
|
||||
// API's logic in JS.
|
||||
void SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor);
|
||||
|
||||
private:
|
||||
~DataStoreCursor() {}
|
||||
RefPtr<DataStoreCursorImpl> mCursor;
|
||||
};
|
||||
|
||||
} //namespace dom
|
||||
} //namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -1,444 +0,0 @@
|
||||
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
|
||||
/* vim: set ft=javascript 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/. */
|
||||
|
||||
'use strict'
|
||||
|
||||
this.EXPORTED_SYMBOLS = ['DataStoreCursor'];
|
||||
|
||||
function debug(s) {
|
||||
//dump('DEBUG DataStoreCursor: ' + s + '\n');
|
||||
}
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
const STATE_INIT = 0;
|
||||
const STATE_REVISION_INIT = 1;
|
||||
const STATE_REVISION_CHECK = 2;
|
||||
const STATE_SEND_ALL = 3;
|
||||
const STATE_REVISION_SEND = 4;
|
||||
const STATE_DONE = 5;
|
||||
|
||||
const REVISION_ADDED = 'added';
|
||||
const REVISION_UPDATED = 'updated';
|
||||
const REVISION_REMOVED = 'removed';
|
||||
const REVISION_VOID = 'void';
|
||||
const REVISION_SKIP = 'skip'
|
||||
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
|
||||
/**
|
||||
* legend:
|
||||
* - RID = revision ID
|
||||
* - R = revision object (with the internalRevisionId that is a number)
|
||||
* - X = current object ID.
|
||||
* - L = the list of revisions that we have to send
|
||||
*
|
||||
* State: init: do you have RID ?
|
||||
* YES: state->initRevision; loop
|
||||
* NO: get R; X=0; state->sendAll; send a 'clear'
|
||||
*
|
||||
* State: initRevision. Get R from RID. Done?
|
||||
* YES: state->revisionCheck; loop
|
||||
* NO: RID = null; state->init; loop
|
||||
*
|
||||
* State: revisionCheck: get all the revisions between R and NOW. Done?
|
||||
* YES and R == NOW: state->done; loop
|
||||
* YES and R != NOW: Store this revisions in L; state->revisionSend; loop
|
||||
* NO: R = NOW; X=0; state->sendAll; send a 'clear'
|
||||
*
|
||||
* State: sendAll: is R still the last revision?
|
||||
* YES get the first object with id > X. Done?
|
||||
* YES: X = object.id; send 'add'
|
||||
* NO: state->revisionCheck; loop
|
||||
* NO: R = NOW; X=0; send a 'clear'
|
||||
*
|
||||
* State: revisionSend: do you have something from L to send?
|
||||
* YES and L[0] == 'removed': R=L[0]; send 'remove' with ID
|
||||
* YES and L[0] == 'added': R=L[0]; get the object; found?
|
||||
* NO: loop
|
||||
* YES: send 'add' with ID and object
|
||||
* YES and L[0] == 'updated': R=L[0]; get the object; found?
|
||||
* NO: loop
|
||||
* YES and object.R > R: continue
|
||||
* YES and object.R <= R: send 'update' with ID and object
|
||||
* YES L[0] == 'void': R=L[0]; state->init; loop
|
||||
* NO: state->revisionCheck; loop
|
||||
*
|
||||
* State: done: send a 'done' with R
|
||||
*/
|
||||
|
||||
/* Helper functions */
|
||||
function createDOMError(aWindow, aEvent) {
|
||||
return new aWindow.DOMError(aEvent);
|
||||
}
|
||||
|
||||
/* DataStoreCursor object */
|
||||
this.DataStoreCursor = function(aWindow, aDataStore, aRevisionId) {
|
||||
debug("DataStoreCursor created");
|
||||
this.init(aWindow, aDataStore, aRevisionId);
|
||||
}
|
||||
|
||||
this.DataStoreCursor.prototype = {
|
||||
classDescription: 'DataStoreCursor XPCOM Component',
|
||||
classID: Components.ID('{b6d14349-1eab-46b8-8513-584a7328a26b}'),
|
||||
contractID: '@mozilla.org/dom/datastore-cursor-impl;1',
|
||||
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsISupports]),
|
||||
|
||||
_shuttingdown: false,
|
||||
|
||||
_window: null,
|
||||
_dataStore: null,
|
||||
_revisionId: null,
|
||||
_revision: null,
|
||||
_revisionsList: null,
|
||||
_objectId: 0,
|
||||
|
||||
_state: STATE_INIT,
|
||||
|
||||
init: function(aWindow, aDataStore, aRevisionId) {
|
||||
debug('DataStoreCursor init');
|
||||
|
||||
this._window = aWindow;
|
||||
this._dataStore = aDataStore;
|
||||
this._revisionId = aRevisionId;
|
||||
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
||||
|
||||
let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
this._innerWindowID = util.currentInnerWindowID;
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
if (wId == this._innerWindowID) {
|
||||
Services.obs.removeObserver(this, "inner-window-destroyed");
|
||||
this._shuttingdown = true;
|
||||
}
|
||||
},
|
||||
|
||||
// This is the implementation of the state machine.
|
||||
// Read the comments at the top of this file in order to follow what it does.
|
||||
stateMachine: function(aStore, aRevisionStore, aResolve, aReject) {
|
||||
debug('StateMachine: ' + this._state);
|
||||
|
||||
// If the window has been destroyed we cannot create the Promise object.
|
||||
if (this._shuttingdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (this._state) {
|
||||
case STATE_INIT:
|
||||
this.stateMachineInit(aStore, aRevisionStore, aResolve, aReject);
|
||||
break;
|
||||
|
||||
case STATE_REVISION_INIT:
|
||||
this.stateMachineRevisionInit(aStore, aRevisionStore, aResolve, aReject);
|
||||
break;
|
||||
|
||||
case STATE_REVISION_CHECK:
|
||||
this.stateMachineRevisionCheck(aStore, aRevisionStore, aResolve, aReject);
|
||||
break;
|
||||
|
||||
case STATE_SEND_ALL:
|
||||
this.stateMachineSendAll(aStore, aRevisionStore, aResolve, aReject);
|
||||
break;
|
||||
|
||||
case STATE_REVISION_SEND:
|
||||
this.stateMachineRevisionSend(aStore, aRevisionStore, aResolve, aReject);
|
||||
break;
|
||||
|
||||
case STATE_DONE:
|
||||
this.stateMachineDone(aStore, aRevisionStore, aResolve, aReject);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
stateMachineInit: function(aStore, aRevisionStore, aResolve, aReject) {
|
||||
debug('StateMachineInit');
|
||||
|
||||
if (this._revisionId) {
|
||||
this._state = STATE_REVISION_INIT;
|
||||
this.stateMachine(aStore, aRevisionStore, aResolve, aReject);
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
let request = aRevisionStore.openCursor(null, 'prev');
|
||||
request.onsuccess = function(aEvent) {
|
||||
if (aEvent.target.result === undefined) {
|
||||
aReject(self._window.DOMError("InvalidRevision",
|
||||
"The DataStore is corrupted"));
|
||||
return;
|
||||
}
|
||||
|
||||
self._revision = aEvent.target.result.value;
|
||||
self._objectId = 0;
|
||||
self._state = STATE_SEND_ALL;
|
||||
aResolve(self.createTask('clear', null, '', null));
|
||||
}
|
||||
},
|
||||
|
||||
stateMachineRevisionInit: function(aStore, aRevisionStore, aResolve, aReject) {
|
||||
debug('StateMachineRevisionInit');
|
||||
|
||||
let self = this;
|
||||
let request = this._dataStore._db.getInternalRevisionId(
|
||||
self._revisionId,
|
||||
aRevisionStore,
|
||||
function(aInternalRevisionId) {
|
||||
// This revision doesn't exist.
|
||||
if (aInternalRevisionId == undefined) {
|
||||
self._revisionId = null;
|
||||
self._objectId = 0;
|
||||
self._state = STATE_INIT;
|
||||
self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
|
||||
return;
|
||||
}
|
||||
|
||||
self._revision = { revisionId: self._revisionId,
|
||||
internalRevisionId: aInternalRevisionId };
|
||||
self._state = STATE_REVISION_CHECK;
|
||||
self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
stateMachineRevisionCheck: function(aStore, aRevisionStore, aResolve, aReject) {
|
||||
debug('StateMachineRevisionCheck');
|
||||
|
||||
let changes = {
|
||||
addedIds: {},
|
||||
updatedIds: {},
|
||||
removedIds: {}
|
||||
};
|
||||
|
||||
let self = this;
|
||||
let request = aRevisionStore.mozGetAll(
|
||||
self._window.IDBKeyRange.lowerBound(this._revision.internalRevisionId, true));
|
||||
request.onsuccess = function(aEvent) {
|
||||
|
||||
// Optimize the operations.
|
||||
for (let i = 0; i < aEvent.target.result.length; ++i) {
|
||||
let data = aEvent.target.result[i];
|
||||
|
||||
switch (data.operation) {
|
||||
case REVISION_ADDED:
|
||||
changes.addedIds[data.objectId] = data.internalRevisionId;
|
||||
break;
|
||||
|
||||
case REVISION_UPDATED:
|
||||
// We don't consider an update if this object has been added
|
||||
// or if it has been already modified by a previous
|
||||
// operation.
|
||||
if (!(data.objectId in changes.addedIds) &&
|
||||
!(data.objectId in changes.updatedIds)) {
|
||||
changes.updatedIds[data.objectId] = data.internalRevisionId;
|
||||
}
|
||||
break;
|
||||
|
||||
case REVISION_REMOVED:
|
||||
let id = data.objectId;
|
||||
|
||||
// If the object has been added in this range of revisions
|
||||
// we can ignore it and remove it from the list.
|
||||
if (id in changes.addedIds) {
|
||||
delete changes.addedIds[id];
|
||||
} else {
|
||||
changes.removedIds[id] = data.internalRevisionId;
|
||||
}
|
||||
|
||||
if (id in changes.updatedIds) {
|
||||
delete changes.updatedIds[id];
|
||||
}
|
||||
break;
|
||||
|
||||
case REVISION_VOID:
|
||||
if (i != 0) {
|
||||
dump('Internal error: Revision "' + REVISION_VOID + '" should not be found!!!\n');
|
||||
return;
|
||||
}
|
||||
|
||||
self._revisionId = null;
|
||||
self._objectId = 0;
|
||||
self._state = STATE_INIT;
|
||||
self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// From changes to a map of internalRevisionId.
|
||||
let revisions = {};
|
||||
function addRevisions(obj) {
|
||||
for (let key in obj) {
|
||||
revisions[obj[key]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
addRevisions(changes.addedIds);
|
||||
addRevisions(changes.updatedIds);
|
||||
addRevisions(changes.removedIds);
|
||||
|
||||
// Create the list of revisions.
|
||||
let list = [];
|
||||
for (let i = 0; i < aEvent.target.result.length; ++i) {
|
||||
let data = aEvent.target.result[i];
|
||||
|
||||
// If this revision doesn't contain useful data, we still need to keep
|
||||
// it in the list because we need to update the internal revision ID.
|
||||
if (!(data.internalRevisionId in revisions)) {
|
||||
data.operation = REVISION_SKIP;
|
||||
}
|
||||
|
||||
list.push(data);
|
||||
}
|
||||
|
||||
if (list.length == 0) {
|
||||
self._state = STATE_DONE;
|
||||
self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
|
||||
return;
|
||||
}
|
||||
|
||||
// Some revision has to be sent.
|
||||
self._revisionsList = list;
|
||||
self._state = STATE_REVISION_SEND;
|
||||
self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
|
||||
};
|
||||
},
|
||||
|
||||
stateMachineSendAll: function(aStore, aRevisionStore, aResolve, aReject) {
|
||||
debug('StateMachineSendAll');
|
||||
|
||||
let self = this;
|
||||
let request = aRevisionStore.openCursor(null, 'prev');
|
||||
request.onsuccess = function(aEvent) {
|
||||
if (self._revision.revisionId != aEvent.target.result.value.revisionId) {
|
||||
self._revision = aEvent.target.result.value;
|
||||
self._objectId = 0;
|
||||
aResolve(self.createTask('clear', null, '', null));
|
||||
return;
|
||||
}
|
||||
|
||||
let request = aStore.openCursor(self._window.IDBKeyRange.lowerBound(self._objectId, true));
|
||||
request.onsuccess = function(aEvent) {
|
||||
let cursor = aEvent.target.result;
|
||||
if (!cursor) {
|
||||
self._state = STATE_REVISION_CHECK;
|
||||
self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
|
||||
return;
|
||||
}
|
||||
|
||||
self._objectId = cursor.key;
|
||||
aResolve(self.createTask('add', self._objectId, '', cursor.value));
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
stateMachineRevisionSend: function(aStore, aRevisionStore, aResolve, aReject) {
|
||||
debug('StateMachineRevisionSend');
|
||||
|
||||
if (!this._revisionsList.length) {
|
||||
this._state = STATE_REVISION_CHECK;
|
||||
this.stateMachine(aStore, aRevisionStore, aResolve, aReject);
|
||||
return;
|
||||
}
|
||||
|
||||
this._revision = this._revisionsList.shift();
|
||||
|
||||
switch (this._revision.operation) {
|
||||
case REVISION_REMOVED:
|
||||
aResolve(this.createTask('remove', this._revision.objectId, '', null));
|
||||
break;
|
||||
|
||||
case REVISION_ADDED: {
|
||||
let request = aStore.get(this._revision.objectId);
|
||||
let self = this;
|
||||
request.onsuccess = function(aEvent) {
|
||||
if (aEvent.target.result == undefined) {
|
||||
self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
|
||||
return;
|
||||
}
|
||||
|
||||
aResolve(self.createTask('add', self._revision.objectId, '',
|
||||
aEvent.target.result));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case REVISION_UPDATED: {
|
||||
let request = aStore.get(this._revision.objectId);
|
||||
let self = this;
|
||||
request.onsuccess = function(aEvent) {
|
||||
if (aEvent.target.result == undefined) {
|
||||
self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aEvent.target.result.revisionId > self._revision.internalRevisionId) {
|
||||
self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
|
||||
return;
|
||||
}
|
||||
|
||||
aResolve(self.createTask('update', self._revision.objectId, '',
|
||||
aEvent.target.result));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case REVISION_VOID:
|
||||
// Internal error!
|
||||
dump('Internal error: Revision "' + REVISION_VOID + '" should not be found!!!\n');
|
||||
break;
|
||||
|
||||
case REVISION_SKIP:
|
||||
// This revision contains data that has already been sent by another one.
|
||||
this.stateMachine(aStore, aRevisionStore, aResolve, aReject);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
stateMachineDone: function(aStore, aRevisionStore, aResolve, aReject) {
|
||||
this.close();
|
||||
aResolve(this.createTask('done', null, this._revision.revisionId, null));
|
||||
},
|
||||
|
||||
// public interface
|
||||
|
||||
get store() {
|
||||
return this._dataStore.exposedObject;
|
||||
},
|
||||
|
||||
next: function() {
|
||||
debug('Next');
|
||||
|
||||
// If the window has been destroyed we cannot create the Promise object.
|
||||
if (this._shuttingdown) {
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
return new this._window.Promise(function(aResolve, aReject) {
|
||||
self._dataStore._db.cursorTxn(
|
||||
function(aTxn, aStore, aRevisionStore) {
|
||||
self.stateMachine(aStore, aRevisionStore, aResolve, aReject);
|
||||
},
|
||||
function(aEvent) {
|
||||
aReject(createDOMError(self._window, aEvent));
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
close: function() {
|
||||
this._dataStore.syncTerminated(this);
|
||||
},
|
||||
|
||||
createTask: function(aOperation, aId, aRevisionId, aData) {
|
||||
return Cu.cloneInto({ operation: aOperation, id: aId,
|
||||
revisionId: aRevisionId, data: aData }, this._window);
|
||||
}
|
||||
};
|
||||
@@ -1,442 +0,0 @@
|
||||
/* -*- 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 "DataStoreDB.h"
|
||||
|
||||
#include "DataStoreCallbacks.h"
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/dom/IDBDatabaseBinding.h"
|
||||
#include "mozilla/dom/IDBDatabase.h"
|
||||
#include "mozilla/dom/IDBEvents.h"
|
||||
#include "mozilla/dom/IDBFactory.h"
|
||||
#include "mozilla/dom/IDBFactoryBinding.h"
|
||||
#include "mozilla/dom/IDBIndex.h"
|
||||
#include "mozilla/dom/IDBObjectStore.h"
|
||||
#include "mozilla/dom/IDBObjectStoreBinding.h"
|
||||
#include "mozilla/dom/IDBRequest.h"
|
||||
#include "mozilla/dom/IDBTransaction.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsNullPrincipal.h"
|
||||
|
||||
#define DATASTOREDB_VERSION 1
|
||||
#define DATASTOREDB_NAME "DataStoreDB"
|
||||
#define DATASTOREDB_REVISION_INDEX "revisionIndex"
|
||||
|
||||
using namespace mozilla::dom::indexedDB;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class VersionChangeListener final : public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit VersionChangeListener(IDBDatabase* aDatabase)
|
||||
: mDatabase(aDatabase)
|
||||
{}
|
||||
|
||||
// nsIDOMEventListener
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override
|
||||
{
|
||||
nsString type;
|
||||
nsresult rv = aEvent->GetType(type);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!type.EqualsASCII("versionchange")) {
|
||||
MOZ_ASSERT_UNREACHABLE("Expected a versionchange event");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = mDatabase->RemoveEventListener(NS_LITERAL_STRING("versionchange"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<IDBVersionChangeEvent> event = do_QueryInterface(aEvent);
|
||||
MOZ_ASSERT(event);
|
||||
|
||||
Nullable<uint64_t> version = event->GetNewVersion();
|
||||
MOZ_ASSERT(version.IsNull());
|
||||
#endif
|
||||
|
||||
mDatabase->Close();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
IDBDatabase* mDatabase;
|
||||
|
||||
~VersionChangeListener() {}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(VersionChangeListener, nsIDOMEventListener)
|
||||
|
||||
NS_IMPL_ISUPPORTS(DataStoreDB, nsIDOMEventListener)
|
||||
|
||||
DataStoreDB::DataStoreDB(const nsAString& aManifestURL, const nsAString& aName)
|
||||
: mState(Inactive)
|
||||
, mCreatedSchema(false)
|
||||
{
|
||||
mDatabaseName.Assign(aName);
|
||||
mDatabaseName.Append('|');
|
||||
mDatabaseName.Append(aManifestURL);
|
||||
}
|
||||
|
||||
DataStoreDB::~DataStoreDB()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::CreateFactoryIfNeeded()
|
||||
{
|
||||
if (!mFactory) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrincipal> principal = nsNullPrincipal::Create();
|
||||
if (!principal) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsIXPConnect* xpc = nsContentUtils::XPConnect();
|
||||
MOZ_ASSERT(xpc);
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> global(cx);
|
||||
rv = xpc->CreateSandbox(cx, principal, global.address());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// The CreateSandbox call returns a proxy to the actual sandbox object. We
|
||||
// don't need a proxy here.
|
||||
global = js::UncheckedUnwrap(global);
|
||||
|
||||
JSAutoCompartment ac(cx, global);
|
||||
|
||||
rv = IDBFactory::CreateForDatastore(cx, global, getter_AddRefs(mFactory));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::Open(IDBTransactionMode aMode, const Sequence<nsString>& aDbs,
|
||||
DataStoreDBCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(mState == Inactive);
|
||||
|
||||
nsresult rv = CreateFactoryIfNeeded();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We only need a JSContext here to get a stack from, so just init our
|
||||
// AutoJSAPI without a global.
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
ErrorResult error;
|
||||
mRequest = mFactory->Open(jsapi.cx(), mDatabaseName, DATASTOREDB_VERSION,
|
||||
error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
rv = AddEventListeners();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mState = Active;
|
||||
mTransactionMode = aMode;
|
||||
mObjectStores = aDbs;
|
||||
mCallback = aCallback;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataStoreDB::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsString type;
|
||||
nsresult rv = aEvent->GetType(type);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (type.EqualsASCII("success")) {
|
||||
RemoveEventListeners();
|
||||
mState = Inactive;
|
||||
|
||||
rv = DatabaseOpened();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mCallback->Run(this, DataStoreDBCallback::Error);
|
||||
} else {
|
||||
mCallback->Run(this, mCreatedSchema
|
||||
? DataStoreDBCallback::CreatedSchema :
|
||||
DataStoreDBCallback::Success);
|
||||
}
|
||||
|
||||
mRequest = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (type.EqualsASCII("upgradeneeded")) {
|
||||
return UpgradeSchema(aEvent);
|
||||
}
|
||||
|
||||
if (type.EqualsASCII("error") || type.EqualsASCII("blocked")) {
|
||||
RemoveEventListeners();
|
||||
mState = Inactive;
|
||||
mCallback->Run(this, DataStoreDBCallback::Error);
|
||||
mRequest = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_CRASH("This should not happen");
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::UpgradeSchema(nsIDOMEvent* aEvent)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// This DB has been just created and we have to inform the callback about
|
||||
// this.
|
||||
mCreatedSchema = true;
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<IDBVersionChangeEvent> event = do_QueryInterface(aEvent);
|
||||
MOZ_ASSERT(event);
|
||||
|
||||
Nullable<uint64_t> version = event->GetNewVersion();
|
||||
MOZ_ASSERT(!version.IsNull());
|
||||
MOZ_ASSERT(version.Value() == DATASTOREDB_VERSION);
|
||||
#endif
|
||||
|
||||
ErrorResult error;
|
||||
JS::Rooted<JS::Value> result(nsContentUtils::RootingCx());
|
||||
mRequest->GetResult(&result, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(result.isObject());
|
||||
|
||||
IDBDatabase* database = nullptr;
|
||||
nsresult rv = UNWRAP_OBJECT(IDBDatabase, &result.toObject(), database);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Didn't get the object we expected!");
|
||||
return rv;
|
||||
}
|
||||
|
||||
{
|
||||
IDBObjectStoreParameters params;
|
||||
params.Init(NS_LITERAL_STRING("{ \"autoIncrement\": true }"));
|
||||
RefPtr<IDBObjectStore> store =
|
||||
database->CreateObjectStore(NS_LITERAL_STRING(DATASTOREDB_NAME),
|
||||
params, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<IDBObjectStore> store;
|
||||
|
||||
{
|
||||
IDBObjectStoreParameters params;
|
||||
params.Init(NS_LITERAL_STRING("{ \"autoIncrement\": true, \"keyPath\": \"internalRevisionId\" }"));
|
||||
|
||||
store =
|
||||
database->CreateObjectStore(NS_LITERAL_STRING(DATASTOREDB_REVISION),
|
||||
params, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
IDBIndexParameters params;
|
||||
params.Init(NS_LITERAL_STRING("{ \"unique\": true }"));
|
||||
RefPtr<IDBIndex> index =
|
||||
store->CreateIndex(NS_LITERAL_STRING(DATASTOREDB_REVISION_INDEX),
|
||||
NS_LITERAL_STRING("revisionId"), params, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::DatabaseOpened()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
ErrorResult error;
|
||||
JS::Rooted<JS::Value> result(nsContentUtils::RootingCx());
|
||||
mRequest->GetResult(&result, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(result.isObject());
|
||||
|
||||
nsresult rv = UNWRAP_OBJECT(IDBDatabase, &result.toObject(), mDatabase);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Didn't get the object we expected!");
|
||||
return rv;
|
||||
}
|
||||
|
||||
RefPtr<VersionChangeListener> listener =
|
||||
new VersionChangeListener(mDatabase);
|
||||
rv = mDatabase->EventTarget::AddEventListener(
|
||||
NS_LITERAL_STRING("versionchange"), listener, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
StringOrStringSequence objectStores;
|
||||
if (!objectStores.RawSetAsStringSequence().AppendElements(mObjectStores,
|
||||
fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// We init with the global of our result, just for consistency.
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(&result.toObject())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
RefPtr<IDBTransaction> txn;
|
||||
error = mDatabase->Transaction(jsapi.cx(),
|
||||
objectStores,
|
||||
mTransactionMode,
|
||||
getter_AddRefs(txn));
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
mTransaction = txn.forget();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::Delete()
|
||||
{
|
||||
MOZ_ASSERT(mState == Inactive);
|
||||
|
||||
nsresult rv = CreateFactoryIfNeeded();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mTransaction = nullptr;
|
||||
|
||||
if (mDatabase) {
|
||||
mDatabase->Close();
|
||||
mDatabase = nullptr;
|
||||
}
|
||||
|
||||
// We only need a JSContext here to get a stack from, so just init our
|
||||
// AutoJSAPI without a global.
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
ErrorResult error;
|
||||
RefPtr<IDBOpenDBRequest> request =
|
||||
mFactory->DeleteDatabase(jsapi.cx(), mDatabaseName, IDBOpenDBOptions(),
|
||||
error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
IDBTransaction*
|
||||
DataStoreDB::Transaction() const
|
||||
{
|
||||
MOZ_ASSERT(mTransaction);
|
||||
MOZ_ASSERT(mTransaction->IsOpen());
|
||||
return mTransaction;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::AddEventListeners()
|
||||
{
|
||||
nsresult rv;
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("success"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("upgradeneeded"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("error"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("blocked"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataStoreDB::RemoveEventListeners()
|
||||
{
|
||||
nsresult rv;
|
||||
rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("success"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("upgradeneeded"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("error"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mRequest->RemoveEventListener(NS_LITERAL_STRING("blocked"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -1,80 +0,0 @@
|
||||
/* -*- 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_DataStoreDB_h
|
||||
#define mozilla_dom_DataStoreDB_h
|
||||
|
||||
#include "mozilla/dom/IDBTransactionBinding.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#define DATASTOREDB_REVISION "revision"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class DataStoreDBCallback;
|
||||
class IDBDatabase;
|
||||
class IDBFactory;
|
||||
class IDBOpenDBRequest;
|
||||
class IDBTransaction;
|
||||
|
||||
class DataStoreDB final : public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
DataStoreDB(const nsAString& aManifestURL, const nsAString& aName);
|
||||
|
||||
nsresult Open(IDBTransactionMode aMode, const Sequence<nsString>& aDb,
|
||||
DataStoreDBCallback* aCallback);
|
||||
|
||||
nsresult Delete();
|
||||
|
||||
IDBTransaction* Transaction() const;
|
||||
|
||||
// nsIDOMEventListener
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override;
|
||||
|
||||
private:
|
||||
~DataStoreDB();
|
||||
|
||||
nsresult CreateFactoryIfNeeded();
|
||||
|
||||
nsresult UpgradeSchema(nsIDOMEvent* aEvent);
|
||||
|
||||
nsresult DatabaseOpened();
|
||||
|
||||
nsresult AddEventListeners();
|
||||
|
||||
nsresult RemoveEventListeners();
|
||||
|
||||
nsString mDatabaseName;
|
||||
|
||||
RefPtr<IDBFactory> mFactory;
|
||||
RefPtr<IDBOpenDBRequest> mRequest;
|
||||
RefPtr<IDBDatabase> mDatabase;
|
||||
RefPtr<IDBTransaction> mTransaction;
|
||||
|
||||
RefPtr<DataStoreDBCallback> mCallback;
|
||||
|
||||
// Internal state to avoid strange use of this class.
|
||||
enum StateType {
|
||||
Inactive,
|
||||
Active
|
||||
} mState;
|
||||
|
||||
IDBTransactionMode mTransactionMode;
|
||||
Sequence<nsString> mObjectStores;
|
||||
bool mCreatedSchema;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_DataStoreDB_h
|
||||
@@ -1,118 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
this.EXPORTED_SYMBOLS = ['DataStoreDB'];
|
||||
|
||||
function debug(s) {
|
||||
//dump('DEBUG DataStoreDB: ' + s + '\n');
|
||||
}
|
||||
|
||||
const DATASTOREDB_VERSION = 1;
|
||||
const DATASTOREDB_OBJECTSTORE_NAME = 'DataStoreDB';
|
||||
const DATASTOREDB_REVISION = 'revision';
|
||||
const DATASTOREDB_REVISION_INDEX = 'revisionIndex';
|
||||
|
||||
Cu.import('resource://gre/modules/IndexedDBHelper.jsm');
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.importGlobalProperties(["indexedDB"]);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator");
|
||||
|
||||
this.DataStoreDB = function DataStoreDB() {}
|
||||
|
||||
DataStoreDB.prototype = {
|
||||
|
||||
__proto__: IndexedDBHelper.prototype,
|
||||
|
||||
upgradeSchema: function(aTransaction, aDb, aOldVersion, aNewVersion) {
|
||||
debug('updateSchema');
|
||||
aDb.createObjectStore(DATASTOREDB_OBJECTSTORE_NAME, { autoIncrement: true });
|
||||
let store = aDb.createObjectStore(DATASTOREDB_REVISION,
|
||||
{ autoIncrement: true,
|
||||
keyPath: 'internalRevisionId' });
|
||||
store.createIndex(DATASTOREDB_REVISION_INDEX, 'revisionId', { unique: true });
|
||||
},
|
||||
|
||||
init: function(aOwner, aName) {
|
||||
let dbName = aName + '|' + aOwner;
|
||||
this.initDBHelper(dbName, DATASTOREDB_VERSION,
|
||||
[DATASTOREDB_OBJECTSTORE_NAME, DATASTOREDB_REVISION]);
|
||||
},
|
||||
|
||||
txn: function(aType, aCallback, aErrorCb) {
|
||||
debug('Transaction request');
|
||||
this.newTxn(
|
||||
aType,
|
||||
aType == 'readonly'
|
||||
? [ DATASTOREDB_OBJECTSTORE_NAME ] : [ DATASTOREDB_OBJECTSTORE_NAME, DATASTOREDB_REVISION ],
|
||||
function(aTxn, aStores) {
|
||||
aType == 'readonly' ? aCallback(aTxn, aStores[0], null) : aCallback(aTxn, aStores[0], aStores[1]);
|
||||
},
|
||||
function() {},
|
||||
aErrorCb
|
||||
);
|
||||
},
|
||||
|
||||
cursorTxn: function(aCallback, aErrorCb) {
|
||||
debug('Cursor transaction request');
|
||||
this.newTxn(
|
||||
'readonly',
|
||||
[ DATASTOREDB_OBJECTSTORE_NAME, DATASTOREDB_REVISION ],
|
||||
function(aTxn, aStores) {
|
||||
aCallback(aTxn, aStores[0], aStores[1]);
|
||||
},
|
||||
function() {},
|
||||
aErrorCb
|
||||
);
|
||||
},
|
||||
|
||||
revisionTxn: function(aType, aCallback, aErrorCb) {
|
||||
debug("Transaction request");
|
||||
this.newTxn(
|
||||
aType,
|
||||
DATASTOREDB_REVISION,
|
||||
aCallback,
|
||||
function() {},
|
||||
aErrorCb
|
||||
);
|
||||
},
|
||||
|
||||
addRevision: function(aStore, aKey, aType, aSuccessCb) {
|
||||
debug("AddRevision: " + aKey + " - " + aType);
|
||||
let revisionId = uuidgen.generateUUID().toString();
|
||||
let request = aStore.put({ revisionId: revisionId, objectId: aKey, operation: aType });
|
||||
request.onsuccess = function() {
|
||||
aSuccessCb(revisionId);
|
||||
}
|
||||
},
|
||||
|
||||
getInternalRevisionId: function(aRevisionId, aStore, aSuccessCb) {
|
||||
debug('GetInternalRevisionId');
|
||||
let request = aStore.index(DATASTOREDB_REVISION_INDEX).getKey(aRevisionId);
|
||||
request.onsuccess = function(aEvent) {
|
||||
aSuccessCb(aEvent.target.result);
|
||||
}
|
||||
},
|
||||
|
||||
clearRevisions: function(aStore, aSuccessCb) {
|
||||
debug("ClearRevisions");
|
||||
let request = aStore.clear();
|
||||
request.onsuccess = function() {
|
||||
aSuccessCb();
|
||||
}
|
||||
},
|
||||
|
||||
delete: function() {
|
||||
debug('delete');
|
||||
this.close();
|
||||
indexedDB.deleteDatabase(this.dbName);
|
||||
debug('database deleted');
|
||||
}
|
||||
}
|
||||
@@ -1,549 +0,0 @@
|
||||
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
|
||||
/* vim: set ft=javascript 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/. */
|
||||
|
||||
'use strict'
|
||||
|
||||
function debug(s) {
|
||||
//dump('DEBUG DataStore: ' + s + '\n');
|
||||
}
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
const REVISION_ADDED = "added";
|
||||
const REVISION_UPDATED = "updated";
|
||||
const REVISION_REMOVED = "removed";
|
||||
const REVISION_VOID = "void";
|
||||
|
||||
// This value has to be tuned a bit. Currently it's just a guess
|
||||
// and yet we don't know if it's too low or too high.
|
||||
const MAX_REQUESTS = 25;
|
||||
|
||||
Cu.import("resource://gre/modules/DataStoreCursorImpl.jsm");
|
||||
Cu.import("resource://gre/modules/DataStoreDB.jsm");
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.importGlobalProperties(["indexedDB"]);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsIMessageSender");
|
||||
|
||||
/* Helper functions */
|
||||
function createDOMError(aWindow, aEvent) {
|
||||
return new aWindow.DOMError(aEvent);
|
||||
}
|
||||
|
||||
function throwInvalidArg(aWindow) {
|
||||
return aWindow.Promise.reject(
|
||||
new aWindow.DOMError("SyntaxError", "Non-numeric or invalid id"));
|
||||
}
|
||||
|
||||
function throwReadOnly(aWindow) {
|
||||
return aWindow.Promise.reject(
|
||||
new aWindow.DOMError("ReadOnlyError", "DataStore in readonly mode"));
|
||||
}
|
||||
|
||||
function validateId(aId) {
|
||||
// If string, it cannot be empty.
|
||||
if (typeof(aId) == 'string') {
|
||||
return aId.length;
|
||||
}
|
||||
|
||||
aId = parseInt(aId);
|
||||
return (!isNaN(aId) && aId > 0);
|
||||
}
|
||||
|
||||
/* DataStore object */
|
||||
function DataStore() {
|
||||
debug("DataStore created");
|
||||
}
|
||||
|
||||
DataStore.prototype = {
|
||||
classDescription: "DataStore XPCOM Component",
|
||||
classID: Components.ID("{db5c9602-030f-4bff-a3de-881a8de370f2}"),
|
||||
contractID: "@mozilla.org/dom/datastore-impl;1",
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataStore, Ci.nsISupports,
|
||||
Ci.nsIObserver]),
|
||||
|
||||
callbacks: [],
|
||||
|
||||
_window: null,
|
||||
_name: null,
|
||||
_owner: null,
|
||||
_readOnly: null,
|
||||
_revisionId: null,
|
||||
_exposedObject: null,
|
||||
_cursor: null,
|
||||
_shuttingdown: false,
|
||||
_eventTarget: null,
|
||||
|
||||
init: function(aWindow, aName, aOwner, aReadOnly) {
|
||||
debug("DataStore init");
|
||||
|
||||
this._window = aWindow;
|
||||
this._name = aName;
|
||||
this._owner = aOwner;
|
||||
this._readOnly = aReadOnly;
|
||||
|
||||
this._db = new DataStoreDB();
|
||||
this._db.init(aOwner, aName);
|
||||
|
||||
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
||||
|
||||
let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
this._innerWindowID = util.currentInnerWindowID;
|
||||
|
||||
cpmm.addMessageListener("DataStore:Changed:Return:OK", this);
|
||||
cpmm.sendAsyncMessage("DataStore:RegisterForMessages",
|
||||
{ store: this._name, owner: this._owner,
|
||||
innerWindowID: this._innerWindowID },
|
||||
null,
|
||||
this._window.document.nodePrincipal);
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
if (wId == this._innerWindowID) {
|
||||
Services.obs.removeObserver(this, "inner-window-destroyed");
|
||||
|
||||
cpmm.removeMessageListener("DataStore:Changed:Return:OK", this);
|
||||
cpmm.sendAsyncMessage("DataStore:UnregisterForMessages",
|
||||
{ innerWindowID: this._innerWindowID },
|
||||
null,
|
||||
this._window.document.nodePrincipal);
|
||||
this._shuttingdown = true;
|
||||
this._db.close();
|
||||
}
|
||||
},
|
||||
|
||||
setEventTarget: function(aEventTarget) {
|
||||
this._eventTarget = aEventTarget;
|
||||
},
|
||||
|
||||
newDBPromise: function(aTxnType, aFunction) {
|
||||
let self = this;
|
||||
return new this._window.Promise(function(aResolve, aReject) {
|
||||
debug("DBPromise started");
|
||||
self._db.txn(
|
||||
aTxnType,
|
||||
function(aTxn, aStore, aRevisionStore) {
|
||||
debug("DBPromise success");
|
||||
aFunction(aResolve, aReject, aTxn, aStore, aRevisionStore);
|
||||
},
|
||||
function(aEvent) {
|
||||
debug("DBPromise error");
|
||||
aReject(createDOMError(self._window, aEvent));
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
checkRevision: function(aReject, aRevisionStore, aRevisionId, aCallback) {
|
||||
if (!aRevisionId) {
|
||||
aCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
|
||||
let request = aRevisionStore.openCursor(null, 'prev');
|
||||
request.onsuccess = function(aEvent) {
|
||||
let cursor = aEvent.target.result;
|
||||
if (!cursor) {
|
||||
dump("This cannot really happen.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cursor.value.revisionId != aRevisionId) {
|
||||
aReject(new self._window.DOMError("ConstraintError",
|
||||
"RevisionId is not up-to-date"));
|
||||
return;
|
||||
}
|
||||
|
||||
aCallback();
|
||||
}
|
||||
},
|
||||
|
||||
getInternal: function(aStore, aIds, aCallback) {
|
||||
debug("GetInternal: " + aIds.toSource());
|
||||
|
||||
// Creation of the results array.
|
||||
let results = new this._window.Array(aIds.length);
|
||||
|
||||
// We're going to create this amount of requests.
|
||||
let pendingIds = aIds.length;
|
||||
let indexPos = 0;
|
||||
|
||||
let self = this;
|
||||
|
||||
function getInternalSuccess(aEvent, aPos) {
|
||||
debug("GetInternal success. Record: " + aEvent.target.result);
|
||||
results[aPos] = Cu.cloneInto(aEvent.target.result, self._window);
|
||||
if (!--pendingIds) {
|
||||
aCallback(results);
|
||||
return;
|
||||
}
|
||||
|
||||
if (indexPos < aIds.length) {
|
||||
// Just MAX_REQUESTS requests at the same time.
|
||||
let count = 0;
|
||||
while (indexPos < aIds.length && ++count < MAX_REQUESTS) {
|
||||
getInternalRequest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getInternalRequest() {
|
||||
let currentPos = indexPos++;
|
||||
let request = aStore.get(aIds[currentPos]);
|
||||
request.onsuccess = function(aEvent) {
|
||||
getInternalSuccess(aEvent, currentPos);
|
||||
}
|
||||
}
|
||||
|
||||
getInternalRequest();
|
||||
},
|
||||
|
||||
putInternal: function(aResolve, aStore, aRevisionStore, aObj, aId) {
|
||||
debug("putInternal " + aId);
|
||||
|
||||
let self = this;
|
||||
let request = aStore.put(aObj, aId);
|
||||
request.onsuccess = function(aEvent) {
|
||||
debug("putInternal success");
|
||||
|
||||
self.addRevision(aRevisionStore, aId, REVISION_UPDATED,
|
||||
function() {
|
||||
debug("putInternal - revisionId increased");
|
||||
// No wrap here because the result is always a int.
|
||||
aResolve(aEvent.target.result);
|
||||
}
|
||||
);
|
||||
};
|
||||
},
|
||||
|
||||
addInternal: function(aResolve, aStore, aRevisionStore, aObj, aId) {
|
||||
debug("AddInternal");
|
||||
|
||||
let self = this;
|
||||
let request = aStore.add(aObj, aId);
|
||||
request.onsuccess = function(aEvent) {
|
||||
debug("Request successful. Id: " + aEvent.target.result);
|
||||
self.addRevision(aRevisionStore, aEvent.target.result, REVISION_ADDED,
|
||||
function() {
|
||||
debug("AddInternal - revisionId increased");
|
||||
// No wrap here because the result is always a int.
|
||||
aResolve(aEvent.target.result);
|
||||
}
|
||||
);
|
||||
};
|
||||
},
|
||||
|
||||
removeInternal: function(aResolve, aStore, aRevisionStore, aId) {
|
||||
debug("RemoveInternal");
|
||||
|
||||
let self = this;
|
||||
let request = aStore.get(aId);
|
||||
request.onsuccess = function(aEvent) {
|
||||
debug("RemoveInternal success. Record: " + aEvent.target.result);
|
||||
if (aEvent.target.result === undefined) {
|
||||
aResolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let deleteRequest = aStore.delete(aId);
|
||||
deleteRequest.onsuccess = function() {
|
||||
debug("RemoveInternal success");
|
||||
self.addRevision(aRevisionStore, aId, REVISION_REMOVED,
|
||||
function() {
|
||||
aResolve(true);
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
},
|
||||
|
||||
clearInternal: function(aResolve, aStore, aRevisionStore) {
|
||||
debug("ClearInternal");
|
||||
|
||||
let self = this;
|
||||
let request = aStore.clear();
|
||||
request.onsuccess = function() {
|
||||
debug("ClearInternal success");
|
||||
self._db.clearRevisions(aRevisionStore,
|
||||
function() {
|
||||
debug("Revisions cleared");
|
||||
|
||||
self.addRevision(aRevisionStore, null, REVISION_VOID,
|
||||
function() {
|
||||
debug("ClearInternal - revisionId increased");
|
||||
aResolve();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
},
|
||||
|
||||
getLengthInternal: function(aResolve, aStore) {
|
||||
debug("GetLengthInternal");
|
||||
|
||||
let request = aStore.count();
|
||||
request.onsuccess = function(aEvent) {
|
||||
debug("GetLengthInternal success: " + aEvent.target.result);
|
||||
// No wrap here because the result is always a int.
|
||||
aResolve(aEvent.target.result);
|
||||
};
|
||||
},
|
||||
|
||||
addRevision: function(aRevisionStore, aId, aType, aSuccessCb) {
|
||||
let self = this;
|
||||
this._db.addRevision(aRevisionStore, aId, aType,
|
||||
function(aRevisionId) {
|
||||
self._revisionId = aRevisionId;
|
||||
self.sendNotification(aId, aType, aRevisionId);
|
||||
aSuccessCb();
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
retrieveRevisionId: function(aSuccessCb) {
|
||||
let self = this;
|
||||
this._db.revisionTxn(
|
||||
'readonly',
|
||||
function(aTxn, aRevisionStore) {
|
||||
debug("RetrieveRevisionId transaction success");
|
||||
|
||||
let request = aRevisionStore.openCursor(null, 'prev');
|
||||
request.onsuccess = function(aEvent) {
|
||||
let cursor = aEvent.target.result;
|
||||
if (cursor) {
|
||||
self._revisionId = cursor.value.revisionId;
|
||||
}
|
||||
|
||||
aSuccessCb(self._revisionId);
|
||||
};
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
sendNotification: function(aId, aOperation, aRevisionId) {
|
||||
debug("SendNotification");
|
||||
if (aOperation == REVISION_VOID) {
|
||||
aOperation = "cleared";
|
||||
}
|
||||
|
||||
cpmm.sendAsyncMessage("DataStore:Changed",
|
||||
{ store: this.name, owner: this._owner,
|
||||
message: { revisionId: aRevisionId, id: aId,
|
||||
operation: aOperation, owner: this._owner } },
|
||||
null,
|
||||
this._window.document.nodePrincipal);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
debug("receiveMessage");
|
||||
|
||||
if (aMessage.name != "DataStore:Changed:Return:OK") {
|
||||
debug("Wrong message: " + aMessage.name);
|
||||
return;
|
||||
}
|
||||
|
||||
// If this message is not for this DataStore, let's ignore it.
|
||||
if (aMessage.data.owner != this._owner ||
|
||||
aMessage.data.store != this._name) {
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
|
||||
this.retrieveRevisionId(
|
||||
function() {
|
||||
// If the window has been destroyed we don't emit the events.
|
||||
if (self._shuttingdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have an active cursor we don't emit events.
|
||||
if (self._cursor) {
|
||||
return;
|
||||
}
|
||||
|
||||
let event = new self._window.DataStoreChangeEvent('change',
|
||||
aMessage.data.message);
|
||||
self._eventTarget.dispatchEvent(event);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
get exposedObject() {
|
||||
debug("get exposedObject");
|
||||
return this._exposedObject;
|
||||
},
|
||||
|
||||
set exposedObject(aObject) {
|
||||
debug("set exposedObject");
|
||||
this._exposedObject = aObject;
|
||||
},
|
||||
|
||||
syncTerminated: function(aCursor) {
|
||||
// This checks is to avoid that an invalid cursor stops a sync.
|
||||
if (this._cursor == aCursor) {
|
||||
this._cursor = null;
|
||||
}
|
||||
},
|
||||
|
||||
// Public interface :
|
||||
|
||||
get name() {
|
||||
return this._name;
|
||||
},
|
||||
|
||||
get owner() {
|
||||
return this._owner;
|
||||
},
|
||||
|
||||
get readOnly() {
|
||||
return this._readOnly;
|
||||
},
|
||||
|
||||
get: function() {
|
||||
let ids = Array.prototype.slice.call(arguments);
|
||||
for (let i = 0; i < ids.length; ++i) {
|
||||
if (!validateId(ids[i])) {
|
||||
return throwInvalidArg(this._window);
|
||||
}
|
||||
}
|
||||
|
||||
if (ids.length == 0) {
|
||||
return this._window.Promise.resolve(new this._window.Array());
|
||||
}
|
||||
|
||||
let self = this;
|
||||
|
||||
// Promise<Object>
|
||||
return this.newDBPromise("readonly",
|
||||
function(aResolve, aReject, aTxn, aStore, aRevisionStore) {
|
||||
self.getInternal(aStore, ids,
|
||||
function(aResults) {
|
||||
aResolve(ids.length > 1 ? aResults : aResults[0]);
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
put: function(aObj, aId, aRevisionId) {
|
||||
if (!validateId(aId)) {
|
||||
return throwInvalidArg(this._window);
|
||||
}
|
||||
|
||||
if (this._readOnly) {
|
||||
return throwReadOnly(this._window);
|
||||
}
|
||||
|
||||
let self = this;
|
||||
|
||||
// Promise<void>
|
||||
return this.newDBPromise("readwrite",
|
||||
function(aResolve, aReject, aTxn, aStore, aRevisionStore) {
|
||||
self.checkRevision(aReject, aRevisionStore, aRevisionId, function() {
|
||||
self.putInternal(aResolve, aStore, aRevisionStore, aObj, aId);
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
add: function(aObj, aId, aRevisionId) {
|
||||
if (aId) {
|
||||
if (!validateId(aId)) {
|
||||
return throwInvalidArg(this._window);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._readOnly) {
|
||||
return throwReadOnly(this._window);
|
||||
}
|
||||
|
||||
let self = this;
|
||||
|
||||
// Promise<int>
|
||||
return this.newDBPromise("readwrite",
|
||||
function(aResolve, aReject, aTxn, aStore, aRevisionStore) {
|
||||
self.checkRevision(aReject, aRevisionStore, aRevisionId, function() {
|
||||
self.addInternal(aResolve, aStore, aRevisionStore, aObj, aId);
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
remove: function(aId, aRevisionId) {
|
||||
if (!validateId(aId)) {
|
||||
return throwInvalidArg(this._window);
|
||||
}
|
||||
|
||||
if (this._readOnly) {
|
||||
return throwReadOnly(this._window);
|
||||
}
|
||||
|
||||
let self = this;
|
||||
|
||||
// Promise<void>
|
||||
return this.newDBPromise("readwrite",
|
||||
function(aResolve, aReject, aTxn, aStore, aRevisionStore) {
|
||||
self.checkRevision(aReject, aRevisionStore, aRevisionId, function() {
|
||||
self.removeInternal(aResolve, aStore, aRevisionStore, aId);
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
clear: function(aRevisionId) {
|
||||
if (this._readOnly) {
|
||||
return throwReadOnly(this._window);
|
||||
}
|
||||
|
||||
let self = this;
|
||||
|
||||
// Promise<void>
|
||||
return this.newDBPromise("readwrite",
|
||||
function(aResolve, aReject, aTxn, aStore, aRevisionStore) {
|
||||
self.checkRevision(aReject, aRevisionStore, aRevisionId, function() {
|
||||
self.clearInternal(aResolve, aStore, aRevisionStore);
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
get revisionId() {
|
||||
return this._revisionId;
|
||||
},
|
||||
|
||||
getLength: function() {
|
||||
let self = this;
|
||||
|
||||
// Promise<int>
|
||||
return this.newDBPromise("readonly",
|
||||
function(aResolve, aReject, aTxn, aStore, aRevisionStore) {
|
||||
self.getLengthInternal(aResolve, aStore);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
sync: function(aRevisionId) {
|
||||
debug("Sync");
|
||||
this._cursor = new DataStoreCursor(this._window, this, aRevisionId);
|
||||
|
||||
let cursorImpl = this._window.DataStoreCursorImpl.
|
||||
_create(this._window, this._cursor);
|
||||
|
||||
let exposedCursor = new this._window.DataStoreCursor();
|
||||
exposedCursor.setDataStoreCursorImpl(cursorImpl);
|
||||
return exposedCursor;
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataStore]);
|
||||
@@ -1,100 +0,0 @@
|
||||
/* -*- 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 "DataStoreRevision.h"
|
||||
|
||||
#include "DataStoreCallbacks.h"
|
||||
#include "DataStoreService.h"
|
||||
#include "mozilla/dom/DataStoreBinding.h"
|
||||
#include "mozilla/dom/IDBObjectStore.h"
|
||||
#include "mozilla/dom/IDBRequest.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS(DataStoreRevision, nsIDOMEventListener)
|
||||
|
||||
// Note: this code in it must not assume anything about the compartment cx is
|
||||
// in.
|
||||
nsresult
|
||||
DataStoreRevision::AddRevision(JSContext* aCx,
|
||||
IDBObjectStore* aStore,
|
||||
uint32_t aObjectId,
|
||||
RevisionType aRevisionType,
|
||||
DataStoreRevisionCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(aStore);
|
||||
MOZ_ASSERT(aCallback);
|
||||
|
||||
RefPtr<DataStoreService> service = DataStoreService::Get();
|
||||
if (!service) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsString id;
|
||||
nsresult rv = service->GenerateUUID(mRevisionID);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
DataStoreRevisionData data;
|
||||
data.mRevisionId = mRevisionID;
|
||||
data.mObjectId = aObjectId;
|
||||
|
||||
switch (aRevisionType) {
|
||||
case RevisionVoid:
|
||||
data.mOperation = NS_LITERAL_STRING("void");
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("This should not happen");
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
if (!ToJSValue(aCx, data, &value)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
mRequest = aStore->Put(aCx, value, JS::UndefinedHandleValue, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
rv = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("success"),
|
||||
this, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mCallback = aCallback;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DataStoreRevision::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsString type;
|
||||
nsresult rv = aEvent->GetType(type);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!type.EqualsASCII("success")) {
|
||||
MOZ_CRASH("This should not happen");
|
||||
}
|
||||
|
||||
mRequest->RemoveEventListener(NS_LITERAL_STRING("success"), this, false);
|
||||
mRequest = nullptr;
|
||||
|
||||
mCallback->Run(mRevisionID);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -1,50 +0,0 @@
|
||||
/* -*- 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_DataStoreRevision_h
|
||||
#define mozilla_dom_DataStoreRevision_h
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class DataStoreRevisionCallback;
|
||||
class IDBObjectStore;
|
||||
class IDBRequest;
|
||||
|
||||
class DataStoreRevision final : public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
enum RevisionType {
|
||||
RevisionVoid
|
||||
};
|
||||
|
||||
nsresult AddRevision(JSContext* aCx,
|
||||
IDBObjectStore* aStore,
|
||||
uint32_t aObjectId,
|
||||
RevisionType aRevisionType,
|
||||
DataStoreRevisionCallback* aCallback);
|
||||
|
||||
// nsIDOMEventListener
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override;
|
||||
|
||||
private:
|
||||
~DataStoreRevision() {}
|
||||
RefPtr<DataStoreRevisionCallback> mCallback;
|
||||
RefPtr<IDBRequest> mRequest;
|
||||
nsString mRevisionID;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_DataStoreRevision_h
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,119 +0,0 @@
|
||||
/* -*- 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_DataStoreService_h
|
||||
#define mozilla_dom_DataStoreService_h
|
||||
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsIDataStoreService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
class nsIUUIDGenerator;
|
||||
class nsPIDOMWindowInner;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class DataStoreInfo;
|
||||
class FirstRevisionIdCallback;
|
||||
class PendingRequest;
|
||||
class Promise;
|
||||
class RetrieveRevisionsCounter;
|
||||
class RevisionAddedEnableStoreCallback;
|
||||
|
||||
class DataStoreService final : public nsIDataStoreService
|
||||
, public nsIObserver
|
||||
{
|
||||
friend class ContentChild;
|
||||
friend class FirstRevisionIdCallback;
|
||||
friend class RetrieveRevisionsCounter;
|
||||
friend class RevisionAddedEnableStoreCallback;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIDATASTORESERVICE
|
||||
|
||||
// Returns the DataStoreService singleton. Only to be called from main
|
||||
// thread.
|
||||
static already_AddRefed<DataStoreService> GetOrCreate();
|
||||
|
||||
static already_AddRefed<DataStoreService> Get();
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
static bool CheckPermission(nsIPrincipal* principal);
|
||||
|
||||
nsresult GenerateUUID(nsAString& aID);
|
||||
|
||||
nsresult GetDataStoresFromIPC(const nsAString& aName,
|
||||
const nsAString& aOwner,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsTArray<DataStoreSetting>* aValue);
|
||||
|
||||
void HomeScreenPrefChanged();
|
||||
|
||||
private:
|
||||
DataStoreService();
|
||||
~DataStoreService();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
typedef nsClassHashtable<nsUint32HashKey, DataStoreInfo> HashApp;
|
||||
|
||||
nsresult AddPermissions(uint32_t aAppId, const nsAString& aName,
|
||||
const nsAString& aOriginURL,
|
||||
const nsAString& aManifestURL,
|
||||
bool aReadOnly);
|
||||
|
||||
nsresult AddAccessPermissions(uint32_t aAppId, const nsAString& aName,
|
||||
const nsAString& aOriginURL,
|
||||
const nsAString& aManifestURL,
|
||||
bool aReadOnly);
|
||||
|
||||
nsresult CreateFirstRevisionId(uint32_t aAppId, const nsAString& aName,
|
||||
const nsAString& aManifestURL);
|
||||
|
||||
void GetDataStoresCreate(nsPIDOMWindowInner* aWindow, Promise* aPromise,
|
||||
const nsTArray<DataStoreInfo>& aStores);
|
||||
|
||||
void GetDataStoresResolve(nsPIDOMWindowInner* aWindow, Promise* aPromise,
|
||||
const nsTArray<DataStoreInfo>& aStores);
|
||||
|
||||
nsresult GetDataStoreInfos(const nsAString& aName, const nsAString& aOwner,
|
||||
uint32_t aAppId, nsIPrincipal* aPrincipal,
|
||||
nsTArray<DataStoreInfo>& aStores);
|
||||
|
||||
void DeleteDataStores(uint32_t aAppId);
|
||||
|
||||
nsresult EnableDataStore(uint32_t aAppId, const nsAString& aName,
|
||||
const nsAString& aManifestURL);
|
||||
|
||||
already_AddRefed<RetrieveRevisionsCounter> GetCounter(uint32_t aId) const;
|
||||
|
||||
void RemoveCounter(uint32_t aId);
|
||||
|
||||
void DeleteDataStoresIfNotAllowed(const nsAString& aManifestURL);
|
||||
void AddDataStoresIfAllowed(const nsAString& aManifestURL);
|
||||
|
||||
nsClassHashtable<nsStringHashKey, HashApp> mStores;
|
||||
nsClassHashtable<nsStringHashKey, HashApp> mAccessStores;
|
||||
|
||||
typedef nsTArray<PendingRequest> PendingRequests;
|
||||
nsClassHashtable<nsStringHashKey, PendingRequests> mPendingRequests;
|
||||
|
||||
nsRefPtrHashtable<nsUint32HashKey, RetrieveRevisionsCounter> mPendingCounters;
|
||||
|
||||
nsCOMPtr<nsIUUIDGenerator> mUUIDGenerator;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_DataStoreService_h
|
||||
@@ -1,50 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIDataStore.idl',
|
||||
'nsIDataStoreService.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'dom_datastore'
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'DataStore.h',
|
||||
'DataStoreCursor.h',
|
||||
'DataStoreService.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'DataStore.cpp',
|
||||
'DataStoreCursor.cpp',
|
||||
'DataStoreDB.cpp',
|
||||
'DataStoreRevision.cpp',
|
||||
'DataStoreService.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/js/xpconnect/wrappers',
|
||||
]
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'DataStore.manifest',
|
||||
'DataStoreImpl.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'DataStoreChangeNotifier.jsm',
|
||||
'DataStoreCursorImpl.jsm',
|
||||
'DataStoreDB.jsm',
|
||||
]
|
||||
|
||||
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wshadow']
|
||||
@@ -1,23 +0,0 @@
|
||||
/* -*- 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 "nsISupports.idl"
|
||||
|
||||
interface mozIDOMWindow;
|
||||
|
||||
// NOTE: This is a temporary interface.
|
||||
// It will be removed in the next patches for rewriting DataStore in C++.
|
||||
[scriptable, uuid(14f4bae7-dd01-4d1d-81e1-f8fd1e463b5f)]
|
||||
interface nsIDataStore : nsISupports
|
||||
{
|
||||
void init(in mozIDOMWindow window,
|
||||
in DOMString name,
|
||||
in DOMString manifestURL,
|
||||
in boolean readOnly);
|
||||
|
||||
attribute jsval exposedObject;
|
||||
|
||||
void retrieveRevisionId(in jsval cb);
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
/* -*- 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 "nsISupports.idl"
|
||||
|
||||
interface mozIDOMWindow;
|
||||
interface nsIPrincipal;
|
||||
interface nsIArray;
|
||||
|
||||
[scriptable, uuid(44a8de94-d3dd-4a3a-a582-41027d36ceb5)]
|
||||
interface nsIDataStoreService : nsISupports
|
||||
{
|
||||
void installDataStore(in unsigned long appId,
|
||||
in DOMString name,
|
||||
in DOMString originURL,
|
||||
in DOMString manifestURL,
|
||||
in boolean readOnly);
|
||||
|
||||
void installAccessDataStore(in unsigned long appId,
|
||||
in DOMString name,
|
||||
in DOMString originURL,
|
||||
in DOMString manifestURL,
|
||||
in boolean readOnly);
|
||||
|
||||
nsISupports getDataStores(in mozIDOMWindow window,
|
||||
in DOMString name,
|
||||
in DOMString owner);
|
||||
|
||||
nsIArray getAppManifestURLsForDataStore(in DOMString name);
|
||||
|
||||
boolean checkPermission(in nsIPrincipal principal);
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
var gBasePath = "tests/dom/datastore/tests/";
|
||||
|
||||
function handleRequest(request, response) {
|
||||
var query = getQuery(request);
|
||||
|
||||
var testToken = '';
|
||||
if ('testToken' in query) {
|
||||
testToken = query.testToken;
|
||||
}
|
||||
|
||||
var template = 'file_app.template.webapp';
|
||||
if ('template' in query) {
|
||||
template = query.template;
|
||||
}
|
||||
var template = gBasePath + template;
|
||||
response.setHeader("Content-Type", "application/x-web-app-manifest+json", false);
|
||||
response.write(readTemplate(template).replace(/TESTTOKEN/g, testToken));
|
||||
}
|
||||
|
||||
// Copy-pasted incantations. There ought to be a better way to synchronously read
|
||||
// a file into a string, but I guess we're trying to discourage that.
|
||||
function readTemplate(path) {
|
||||
var file = Components.classes["@mozilla.org/file/directory_service;1"].
|
||||
getService(Components.interfaces.nsIProperties).
|
||||
get("CurWorkD", Components.interfaces.nsILocalFile);
|
||||
var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
|
||||
createInstance(Components.interfaces.nsIFileInputStream);
|
||||
var cis = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
|
||||
createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
var split = path.split("/");
|
||||
for(var i = 0; i < split.length; ++i) {
|
||||
file.append(split[i]);
|
||||
}
|
||||
fis.init(file, -1, -1, false);
|
||||
cis.init(fis, "UTF-8", 0, 0);
|
||||
|
||||
var data = "";
|
||||
let str = {};
|
||||
let read = 0;
|
||||
do {
|
||||
read = cis.readString(0xffffffff, str); // read as much as we can and put it in str.value
|
||||
data += str.value;
|
||||
} while (read != 0);
|
||||
cis.close();
|
||||
return data;
|
||||
}
|
||||
|
||||
function getQuery(request) {
|
||||
var query = {};
|
||||
request.queryString.split('&').forEach(function (val) {
|
||||
var [name, value] = val.split('=');
|
||||
query[name] = unescape(value);
|
||||
});
|
||||
return query;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "Really Rapid Release (hosted)",
|
||||
"description": "Updated even faster than <a href='http://mozilla.org'>Firefox</a>, just to annoy slashdotters.",
|
||||
"launch_path": "/tests/dom/datastore/tests/TESTTOKEN",
|
||||
"icons": { "128": "default_icon" },
|
||||
"datastores-owned" : {
|
||||
"foo" : { "access": "readwrite", "description" : "This store is called foo" },
|
||||
"bar" : { "access": "readonly", "description" : "This store is called bar" }
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "Really Rapid Release (hosted) - app 2",
|
||||
"description": "Updated even faster than <a href='http://mozilla.org'>Firefox</a>, just to annoy slashdotters.",
|
||||
"launch_path": "/tests/dom/datastore/tests/TESTTOKEN",
|
||||
"icons": { "128": "default_icon" },
|
||||
"datastores-access" : {
|
||||
"foo" : { "readonly": false, "description" : "This store is called foo" },
|
||||
"bar" : { "readonly": true, "description" : "This store is called bar" }
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - install/uninstall apps</title>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var gHostedManifestURL = 'http://test/tests/dom/datastore/tests/file_app.sjs?testToken=file_app_install.html';
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
var tests = [
|
||||
// Get datastore with name 'foo'
|
||||
function() {
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo') returns 1 element");
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
ok(stores[0].owner, 'The dataStore.owner exists');
|
||||
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
runTest();
|
||||
}, cbError);
|
||||
},
|
||||
|
||||
// Get datastore with name 'bar'
|
||||
function() {
|
||||
navigator.getDataStores('bar').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('bar') returns 1 element");
|
||||
is(stores[0].name, 'bar', 'The dataStore.name is bar');
|
||||
ok(stores[0].owner, 'The dataStore.owner exists');
|
||||
is(stores[0].readOnly, false, 'The dataStore bar is in readonly');
|
||||
runTest();
|
||||
}, cbError);
|
||||
},
|
||||
|
||||
// Get datastore with name 'foo' and a specified owner
|
||||
function() {
|
||||
navigator.getDataStores('foo', gHostedManifestURL).then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo','" + gHostedManifestURL +
|
||||
"') returns 1 element");
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
ok(stores[0].owner, 'The dataStore.owner exists');
|
||||
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
runTest();
|
||||
}, cbError);
|
||||
},
|
||||
|
||||
// Get datastore with name 'foo' and an arbitrary non-existent owner
|
||||
function() {
|
||||
navigator.getDataStores('foo', 'non-existent').then(function(stores) {
|
||||
is(stores.length, 0, "getDataStores('foo','non-existent') returns 0 element");
|
||||
runTest();
|
||||
}, cbError);
|
||||
},
|
||||
|
||||
// Get datastore with an arbitrary non-existent name
|
||||
function() {
|
||||
navigator.getDataStores('non-existent').then(function(stores) {
|
||||
is(stores.length, 0, "getDataStores('non-existent') returns 0 element");
|
||||
runTest();
|
||||
}, cbError);
|
||||
},
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</html>
|
||||
@@ -1,110 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - add([array]) remove([array])</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var gStore;
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
function testGetDataStores() {
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo') returns 1 element");
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
|
||||
var store = stores[0];
|
||||
ok("get" in store, "store.get exists");
|
||||
ok("put" in store, "store.put exists");
|
||||
ok("add" in store, "store.add exists");
|
||||
ok("remove" in store, "store.remove exists");
|
||||
ok("clear" in store, "store.clear exists");
|
||||
|
||||
gStore = stores[0];
|
||||
|
||||
runTest();
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
var itemNumber = 60;
|
||||
|
||||
function testStoreAdd() {
|
||||
var objects = [];
|
||||
for (var i = 0; i < itemNumber; ++i) {
|
||||
objects.push(i);
|
||||
}
|
||||
|
||||
function testStoreAddInternal() {
|
||||
if (!objects.length) {
|
||||
ok(true, "We inserted " + itemNumber + " items");
|
||||
runTest();
|
||||
return;
|
||||
}
|
||||
|
||||
var obj = objects.shift();
|
||||
gStore.add(obj).then(function() {
|
||||
ok(true, "We inserted a new item!");
|
||||
testStoreAddInternal();
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
testStoreAddInternal();
|
||||
}
|
||||
|
||||
function testStoreGet() {
|
||||
var objects = [];
|
||||
for (var i = 1; i <= itemNumber; ++i) {
|
||||
objects.push(i);
|
||||
}
|
||||
|
||||
gStore.get.apply(gStore, objects).then(function(data) {
|
||||
is(data.length, objects.length, "Get - Data matches");
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
is(data[i], objects[i] - 1, "Get - Data matches: " + i + " " + data[i] + " == " + objects[i]);
|
||||
}
|
||||
runTest();
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
// Test for GetDataStore
|
||||
testGetDataStores,
|
||||
|
||||
// Add many items
|
||||
function() { testStoreAdd() },
|
||||
function() { testStoreGet() },
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,31 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - basic operation on a readonly db</title>
|
||||
<script type="text/javascript" src="file_basic_common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,119 +0,0 @@
|
||||
var gStore;
|
||||
|
||||
function testGetDataStores() {
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo') returns 1 element");
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
|
||||
var store = stores[0];
|
||||
ok("get" in store, "store.get exists");
|
||||
ok("put" in store, "store.put exists");
|
||||
ok("add" in store, "store.add exists");
|
||||
ok("remove" in store, "store.remove exists");
|
||||
ok("clear" in store, "store.clear exists");
|
||||
ok("revisionId" in store, "store.revisionId exists");
|
||||
ok("getLength" in store, "store.getLength exists");
|
||||
ok("sync" in store, "store.sync exists");
|
||||
|
||||
gStore = stores[0];
|
||||
|
||||
runTest();
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testStoreGet(id, value) {
|
||||
gStore.get(id).then(function(what) {
|
||||
ok(true, "store.get() retrieves data");
|
||||
is(what, value, "store.get(" + id + ") returns " + value);
|
||||
}, function() {
|
||||
ok(false, "store.get(" + id + ") retrieves data");
|
||||
}).then(runTest, cbError);
|
||||
}
|
||||
|
||||
function testStoreAdd(value) {
|
||||
return gStore.add(value).then(function(what) {
|
||||
ok(true, "store.add() is called");
|
||||
ok(what > 0, "store.add() returns something");
|
||||
return what;
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testStorePut(value, id) {
|
||||
return gStore.put(value, id).then(function() {
|
||||
ok(true, "store.put() is called");
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testStoreGetLength(number) {
|
||||
return gStore.getLength().then(function(n) {
|
||||
is(number, n, "store.getLength() returns the right number");
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testStoreRemove(id) {
|
||||
return gStore.remove(id).then(function() {
|
||||
ok(true, "store.remove() is called");
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testStoreClear() {
|
||||
return gStore.clear().then(function() {
|
||||
ok(true, "store.clear() is called");
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
// Test for GetDataStore
|
||||
testGetDataStores,
|
||||
|
||||
// Unknown ID
|
||||
function() { testStoreGet(42, undefined); },
|
||||
function() { testStoreGet(42, undefined); }, // twice
|
||||
|
||||
// Add + Get - number
|
||||
function() { testStoreAdd(42).then(function(id) {
|
||||
gId = id; runTest(); }, cbError); },
|
||||
function() { testStoreGet(gId, 42); },
|
||||
|
||||
// Add + Get - boolean
|
||||
function() { testStoreAdd(true).then(function(id) {
|
||||
gId = id; runTest(); }, cbError); },
|
||||
function() { testStoreGet(gId, true); },
|
||||
|
||||
// Add + Get - string
|
||||
function() { testStoreAdd("hello world").then(function(id) {
|
||||
gId = id; runTest(); }, cbError); },
|
||||
function() { testStoreGet(gId, "hello world"); },
|
||||
|
||||
// Put + Get - string
|
||||
function() { testStorePut("hello world 2", gId).then(function() {
|
||||
runTest(); }, cbError); },
|
||||
function() { testStoreGet(gId, "hello world 2"); },
|
||||
|
||||
// getLength
|
||||
function() { testStoreGetLength(3).then(function() { runTest(); }, cbError); },
|
||||
|
||||
// Remove
|
||||
function() { testStoreRemove(gId).then(function(what) {
|
||||
runTest(); }, cbError); },
|
||||
function() { testStoreGet(gId, undefined); },
|
||||
|
||||
// Remove - wrong ID
|
||||
function() { testStoreRemove(gId).then(function(what) {
|
||||
runTest(); }, cbError); },
|
||||
|
||||
// Clear
|
||||
function() { testStoreClear().then(function(what) {
|
||||
runTest(); }, cbError); },
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - basic operation on a readonly db</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var messages = [];
|
||||
var worker = new Worker("file_basic_worker.js");
|
||||
|
||||
worker.onmessage = function(event) {
|
||||
messages.push(event.data)
|
||||
|
||||
if (event.data == 'DONE') {
|
||||
// Free the worker when all the tests are done.
|
||||
worker.terminate();
|
||||
|
||||
// Fire message to the test_basic_worker.html.
|
||||
for (var i = 0; i < messages.length; i++) {
|
||||
alert(messages[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,19 +0,0 @@
|
||||
function is(a, b, msg) {
|
||||
postMessage((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
postMessage((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
postMessage('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
postMessage('DONE');
|
||||
}
|
||||
|
||||
importScripts("file_basic_common.js");
|
||||
|
||||
runTest();
|
||||
@@ -1,46 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - bug 1008044</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((!!a ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
if (stores[0].name != 'foo') {
|
||||
ok(false, "Wrong name is received! Expected 'foo'");
|
||||
}
|
||||
runTest();
|
||||
});
|
||||
|
||||
navigator.getDataStores('bar').then(function(stores) {
|
||||
if (stores[0].name != 'bar') {
|
||||
ok(false, "Wrong name is received! Expected 'bar'");
|
||||
}
|
||||
runTest();
|
||||
});
|
||||
|
||||
var pending = 2;
|
||||
function runTest() {
|
||||
if (--pending == 0) {
|
||||
ok(true, "Test passed!");
|
||||
finish();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,40 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - basic operation on a readonly db</title>
|
||||
<script type="text/javascript" src="file_basic_common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function is(a, b, msg) {
|
||||
ok(a === b, msg);
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo') returns 1 element");
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
|
||||
var store = stores[0];
|
||||
store.get.apply(store, []).then(function(a) {
|
||||
ok(Array.isArray(a), "bug 1058108");
|
||||
is(a.length, 0, "bug 1058108");
|
||||
finish();
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for bug 924104</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var gStore;
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
function testGetDataStores() {
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
gStore = stores[0];
|
||||
runTest();
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testBug924104() {
|
||||
gStore
|
||||
.add({})
|
||||
.then(
|
||||
function(index) {
|
||||
ok(index, "store.add() created item" + index);
|
||||
return gStore.get(index);
|
||||
},
|
||||
cbError)
|
||||
.then(
|
||||
function(obj) {
|
||||
ok(true, "store.get() works");
|
||||
var status = false;
|
||||
try {
|
||||
obj['foobar'] = 42;
|
||||
status = true;
|
||||
} catch(e) {}
|
||||
ok(status, "Object is editable");
|
||||
runTest();
|
||||
},
|
||||
cbError);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
testGetDataStores,
|
||||
testBug924104
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,34 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - bug 1008044</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a == b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is (stores.length, 1, "Correct number of Stores");
|
||||
is (stores[0].name, 'foo', "Correct name is received!");
|
||||
stores[0].get(42).then(function(something) {
|
||||
is (something, null, "Correct value");
|
||||
finish();
|
||||
}, cbError);
|
||||
}, cbError);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,88 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - bug 976311 app1</title>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var gStores = [];
|
||||
var expectedWhere;
|
||||
|
||||
function is(a, b, msg) {
|
||||
ok(a === b, msg);
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
function checkEvent(id) {
|
||||
is(expectedWhere, id, "Message on the correct DS: " + id + " " + expectedWhere);
|
||||
runTest();
|
||||
}
|
||||
|
||||
function testGetDataStores() {
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is(stores.length, 2, "getDataStores('foo') returns 1 element");
|
||||
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
stores[0].onchange = function(evt) { checkEvent(0); }
|
||||
gStores.push(stores[0]);
|
||||
|
||||
is(stores[1].name, 'foo', 'The dataStore.name is foo');
|
||||
is(stores[1].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
stores[1].onchange = function(evt) { checkEvent(1); }
|
||||
gStores.push(stores[1]);
|
||||
|
||||
runTest();
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testStoreAdd(where, value) {
|
||||
expectedWhere = where;
|
||||
dump("ADD TO: " + gStores[where].owner + "\n");
|
||||
gStores[where].add({ a: value });
|
||||
}
|
||||
|
||||
var tests = [
|
||||
// Test for GetDataStore
|
||||
testGetDataStores,
|
||||
|
||||
function() { testStoreAdd(0, 1); },
|
||||
function() { testStoreAdd(1, 2); },
|
||||
function() { testStoreAdd(0, 3); },
|
||||
function() { testStoreAdd(1, 4); }
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "Really Rapid Release (hosted)",
|
||||
"description": "Updated even faster than <a href='http://mozilla.org'>Firefox</a>, just to annoy slashdotters.",
|
||||
"launch_path": "/tests/dom/datastore/tests/TESTTOKEN",
|
||||
"icons": { "128": "default_icon" },
|
||||
"datastores-owned" : {
|
||||
"foo" : { "access": "readwrite", "description" : "This store is called foo" }
|
||||
},
|
||||
"datastores-access" : {
|
||||
"foo" : { "readonly": false, "description" : "This store is called foo" }
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - bug 986056 app</title>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
alert("OK " + stores.length);
|
||||
}, cbError);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "Really Rapid Release (hosted)",
|
||||
"description": "Updated even faster than <a href='http://mozilla.org'>Firefox</a>, just to annoy slashdotters.",
|
||||
"launch_path": "/tests/dom/datastore/tests/TESTTOKEN",
|
||||
"icons": { "128": "default_icon" },
|
||||
"datastores-owned" : {
|
||||
"foo" : { "access": "readwrite", "description" : "This store is called foo" }
|
||||
},
|
||||
"datastores-access" : {
|
||||
"foo" : { "readonly": false, "description" : "This store is called foo" }
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore just for certified Apps</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
ok(!("DataStore" in window), "DataStore is not an available interface");
|
||||
ok(!("DataStoreChangeEvent" in window), "DataStore is not an available interface");
|
||||
ok(!("getDataStores" in navigator), "DataStore not available");
|
||||
finish();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,148 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - basic operation on a readonly db</title>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var gStore;
|
||||
var gChangeId = null;
|
||||
var gChangeOperation = null;
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
function testGetDataStores() {
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo') returns 1 element");
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
|
||||
gStore = stores[0];
|
||||
runTest();
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testStoreAdd(value, expectedId) {
|
||||
gStore.add(value).then(function(id) {
|
||||
is(id, expectedId, "store.add() is called");
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testStorePut(value, id) {
|
||||
gStore.put(value, id).then(function(retId) {
|
||||
is(id, retId, "store.put() is called with the right id");
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testStoreRemove(id, expectedSuccess) {
|
||||
gStore.remove(id).then(function(success) {
|
||||
is(success, expectedSuccess, "store.remove() returns the right value");
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testStoreClear() {
|
||||
gStore.clear().catch(cbError);
|
||||
}
|
||||
|
||||
function eventListener(evt) {
|
||||
ok(evt instanceof DataStoreChangeEvent, "DataStoreChangeEvent has been received");
|
||||
ok(evt, "OnChangeListener is called with data");
|
||||
is(/[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}/.test(evt.revisionId), true, "event.revisionId returns something");
|
||||
is(evt.id, gChangeId, "OnChangeListener is called with the right ID: " + evt.id);
|
||||
is(evt.operation, gChangeOperation, "OnChangeListener is called with the right operation:" + evt.operation + " " + gChangeOperation);
|
||||
runTest();
|
||||
}
|
||||
|
||||
var tests = [
|
||||
// Test for GetDataStore
|
||||
testGetDataStores,
|
||||
|
||||
// Add onchange = function
|
||||
function() {
|
||||
gStore.onchange = eventListener;
|
||||
is(gStore.onchange, eventListener, "onChange is set");
|
||||
runTest();
|
||||
},
|
||||
|
||||
// Add
|
||||
function() { gChangeId = 1; gChangeOperation = 'added';
|
||||
testStoreAdd({ number: 42 }, 1); },
|
||||
|
||||
// Put
|
||||
function() { gChangeId = 1; gChangeOperation = 'updated';
|
||||
testStorePut({ number: 43 }, 1); },
|
||||
|
||||
// Remove
|
||||
function() { gChangeId = 1; gChangeOperation = 'removed';
|
||||
testStoreRemove(1, true); },
|
||||
|
||||
// Clear
|
||||
function() { gChangeId = null; gChangeOperation = 'cleared';
|
||||
testStoreClear(); },
|
||||
|
||||
// Remove onchange function and replace it with addEventListener
|
||||
function() {
|
||||
gStore.onchange = null;
|
||||
gStore.addEventListener('change', eventListener);
|
||||
runTest();
|
||||
},
|
||||
|
||||
// Add
|
||||
function() { gChangeId = 2; gChangeOperation = 'added';
|
||||
testStoreAdd({ number: 42 }, 2); },
|
||||
|
||||
// Put
|
||||
function() { gChangeId = 2; gChangeOperation = 'updated';
|
||||
testStorePut({ number: 43 }, 2); },
|
||||
|
||||
// Remove
|
||||
function() { gChangeId = 2; gChangeOperation = 'removed';
|
||||
testStoreRemove(2, true); },
|
||||
|
||||
// Clear
|
||||
function() { gChangeId = null; gChangeOperation = 'cleared';
|
||||
testStoreClear(); },
|
||||
|
||||
// Remove event listener
|
||||
function() {
|
||||
gStore.removeEventListener('change', eventListener);
|
||||
runTest();
|
||||
},
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,51 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - basic operation on a readonly db</title>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
function eventListener(obj) {
|
||||
ok(obj, "OnChangeListener is called with data");
|
||||
ok("revisionId" in obj, "the event contains a revisionId");
|
||||
ok("id" in obj, "the event contains a id");
|
||||
ok("operation" in obj, "the event contains a operation");
|
||||
ok("owner" in obj, "the event contains a owner");
|
||||
is(obj.owner, 'http://test/tests/dom/datastore/tests/file_app.sjs?testToken=file_changes.html', 'Owner matches');
|
||||
finish();
|
||||
}
|
||||
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo') returns 1 element");
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
|
||||
stores[0].onchange = eventListener;
|
||||
alert('READY');
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,75 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - duplicate keys</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var gStore;
|
||||
var gEvent;
|
||||
var gChangeId;
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
ok(a === b, msg);
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
function testGetDataStores() {
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
gStore = stores[0];
|
||||
runTest();
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testAdd(success) {
|
||||
gStore.add({ a: 42 }, 'test').then(function() {
|
||||
is(success, true, "Record added");
|
||||
runTest();
|
||||
}, function(e) {
|
||||
is(success, false, "Record failed");
|
||||
ok(e instanceof DOMError, "DOMError received");
|
||||
is(e.name, 'ConstraintError', 'e.name: ConstraintError');
|
||||
is(e.message, '', 'e.message');
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
var tests = [
|
||||
// Test for GetDataStore
|
||||
testGetDataStores,
|
||||
|
||||
// add
|
||||
function() { testAdd(true); },
|
||||
|
||||
// add duplicate
|
||||
function() { testAdd(false); }
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,32 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - event maker</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo') returns 1 element");
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
stores[0].add({a: 42}).then(finish, cbError);
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - event receiver</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
ok(a === b, msg);
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
function eventListener(evt) {
|
||||
ok(evt, "OnChangeListener is called with data");
|
||||
finish();
|
||||
}
|
||||
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo') returns 1 element");
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
|
||||
var store = stores[0];
|
||||
store.onchange = eventListener;
|
||||
alert("READY");
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - string or unsigned long keys</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var gStore;
|
||||
var gEvent;
|
||||
var gChangeId;
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
function testGetDataStores() {
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
gStore = stores[0];
|
||||
runTest();
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testAdd_noKey(key) {
|
||||
gEvent = 'added';
|
||||
gChangeId = key;
|
||||
|
||||
gStore.add({ a: 42 }).then(function(id) {
|
||||
is(id, key, "Id must be " + key + " received: " + id);
|
||||
});
|
||||
}
|
||||
|
||||
function testAdd_withKey(key) {
|
||||
gEvent = 'added';
|
||||
gChangeId = key;
|
||||
|
||||
gStore.add({ a: 42 }, key).then(function(id) {
|
||||
is(id, key, "Id must be " + key + " received: " + id);
|
||||
});
|
||||
}
|
||||
|
||||
function testPut(key) {
|
||||
gEvent = 'updated';
|
||||
gChangeId = key;
|
||||
|
||||
gStore.put({ a: 42 }, key).then(function(id) {
|
||||
is(id, key, "Id must be " + key + " received: " + id);
|
||||
});
|
||||
}
|
||||
|
||||
function testGet(key) {
|
||||
gStore.get(key).then(function(value) {
|
||||
ok(value, "Object received!");
|
||||
is(value.a, 42, "Object received with right value!");
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
function testArrayGet(key) {
|
||||
gStore.get.apply(gStore, key).then(function(values) {
|
||||
is(values.length, key.length, "Object received!");
|
||||
for (var i = 0; i < values.length; ++i) {
|
||||
is(values[i].a, 42, "Object received with right value!");
|
||||
}
|
||||
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
function testRemove(key, success) {
|
||||
gEvent = 'removed';
|
||||
gChangeId = key;
|
||||
|
||||
gStore.remove(key).then(function(value) {
|
||||
is(value, success, "Status must be " + success + " received: " + value);
|
||||
if (value == false) {
|
||||
runTest();
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function eventListener() {
|
||||
gStore.onchange = function(e) {
|
||||
is(e.operation, gEvent, "Operation matches: " + e.operation + " " + gEvent);
|
||||
ok(e.id === gChangeId, "Operation id matches");
|
||||
runTest();
|
||||
};
|
||||
|
||||
runTest();
|
||||
}
|
||||
|
||||
var tests = [
|
||||
// Test for GetDataStore
|
||||
testGetDataStores,
|
||||
|
||||
// Event listener
|
||||
eventListener,
|
||||
|
||||
// add
|
||||
function() { testAdd_noKey(1); },
|
||||
function() { testAdd_withKey(123); },
|
||||
function() { testAdd_noKey(124); },
|
||||
function() { testAdd_withKey('foobar'); },
|
||||
function() { testAdd_noKey(125); },
|
||||
function() { testAdd_withKey('125'); },
|
||||
function() { testAdd_withKey('126'); },
|
||||
function() { testAdd_noKey(126); },
|
||||
|
||||
// put
|
||||
function() { testPut(42); },
|
||||
function() { testPut('42'); },
|
||||
|
||||
// get
|
||||
function() { testGet('42'); },
|
||||
function() { testGet(42); },
|
||||
function() { testGet(1); },
|
||||
function() { testGet(123); },
|
||||
function() { testGet(124); },
|
||||
function() { testGet('foobar'); },
|
||||
function() { testGet(125); },
|
||||
function() { testGet('125'); },
|
||||
function() { testGet('126'); },
|
||||
function() { testGet(126); },
|
||||
function() { testArrayGet(['42', 42, 1, 123, 124, 'foobar', 125, '125', '126', 126]); },
|
||||
|
||||
// remove
|
||||
function() { testRemove(42, true); },
|
||||
function() { testRemove('42', true); },
|
||||
function() { testRemove('43', false); },
|
||||
function() { testRemove(43, false); },
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,120 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - notify updates with system messages</title>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var gStore;
|
||||
var gChangeId = null;
|
||||
var gChangeOperation = null;
|
||||
var gIsSystemMessageFired = false;
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
function testGetDataStores() {
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo') returns 1 element");
|
||||
is(stores[0].name, 'foo', 'The dataStore.name is foo');
|
||||
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
|
||||
|
||||
gStore = stores[0];
|
||||
runTest();
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testStoreAdd(value, expectedId) {
|
||||
gStore.add(value).then(function(id) {
|
||||
is(id, expectedId, "store.add() is called");
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function eventListener(evt) {
|
||||
ok(evt instanceof DataStoreChangeEvent, "DataStoreChangeEvent has been received");
|
||||
ok(evt, "OnChangeListener is called with data");
|
||||
is(/[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}/.test(evt.revisionId), true, "event.revisionId returns something");
|
||||
is(evt.id, gChangeId, "OnChangeListener is called with the right ID: " + evt.id);
|
||||
is(evt.operation, gChangeOperation, "OnChangeListener is called with the right operation:" + evt.operation + " " + gChangeOperation);
|
||||
runTest();
|
||||
}
|
||||
|
||||
function onDatastoreUpdateFoo(message) {
|
||||
gIsSystemMessageFired = true;
|
||||
ok(true, "System message 'datastore-update-foo' has been received");
|
||||
runTest();
|
||||
}
|
||||
|
||||
var tests = [
|
||||
// Test for GetDataStore.
|
||||
testGetDataStores,
|
||||
|
||||
// Add onchange = function.
|
||||
function() {
|
||||
gStore.onchange = eventListener;
|
||||
is(gStore.onchange, eventListener, "onChange is set");
|
||||
runTest();
|
||||
},
|
||||
|
||||
// Set system message handler.
|
||||
function() {
|
||||
navigator.mozSetMessageHandler('datastore-update-foo', onDatastoreUpdateFoo);
|
||||
runTest();
|
||||
},
|
||||
|
||||
// Add.
|
||||
function() { gChangeId = 1; gChangeOperation = 'added';
|
||||
testStoreAdd({ number: 42 }, 1); },
|
||||
|
||||
// Remove event listener.
|
||||
function() {
|
||||
gStore.removeEventListener('change', eventListener);
|
||||
runTest();
|
||||
},
|
||||
|
||||
// Ensure the system message has fired and no more pending ones.
|
||||
function() {
|
||||
// Periodically check whether the system message has fired.
|
||||
var timer = setInterval(function() {
|
||||
if (gIsSystemMessageFired) {
|
||||
clearInterval(timer);
|
||||
ok(true, "The system message has fired");
|
||||
ok(!navigator.mozHasPendingMessage('datastore-update-foo'), "No more pending system message");
|
||||
finish();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (tests.length) {
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,72 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - basic operation on a readonly db</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function is(a, b, msg) {
|
||||
dump((a === b ? 'OK' : 'KO') + ' ' + msg + "\n")
|
||||
alert((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
navigator.getDataStores('bar').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('bar') returns 1 element");
|
||||
is(stores[0].name, 'bar', 'The dataStore.name is bar');
|
||||
is(stores[0].readOnly, true, 'The dataStore bar is eadonly');
|
||||
|
||||
var store = stores[0];
|
||||
ok("get" in store, "store.get exists");
|
||||
ok("put" in store, "store.put exists");
|
||||
ok("add" in store, "store.add exists");
|
||||
ok("remove" in store, "store.remove exists");
|
||||
ok("clear" in store, "store.clear exists");
|
||||
|
||||
var f = store.clear();
|
||||
f = f.then(cbError, function() {
|
||||
ok(true, "store.clear() fails because the db is readonly");
|
||||
return store.remove(123);
|
||||
});
|
||||
|
||||
f = f.then(cbError, function() {
|
||||
ok(true, "store.remove() fails because the db is readonly");
|
||||
return store.add(123, true);
|
||||
});
|
||||
|
||||
f = f.then(cbError, function() {
|
||||
ok(true, "store.add() fails because the db is readonly");
|
||||
return store.put({}, 123);
|
||||
})
|
||||
|
||||
f = f.then(cbError, function() {
|
||||
ok(true, "store.put() fails because the db is readonly");
|
||||
})
|
||||
|
||||
f.then(function() {
|
||||
// All done.
|
||||
ok(true, "All done");
|
||||
finish();
|
||||
});
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,31 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - sync</title>
|
||||
<script type="text/javascript" src="file_sync_common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function is(a, b, msg) {
|
||||
alert((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
alert((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
alert('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
alert('DONE');
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,461 +0,0 @@
|
||||
var gStore;
|
||||
var gRevisions = [];
|
||||
var gCursor;
|
||||
var gExpectedEvents = true;
|
||||
|
||||
function testGetDataStores() {
|
||||
navigator.getDataStores('foo').then(function(stores) {
|
||||
is(stores.length, 1, "getDataStores('foo') returns 1 element");
|
||||
|
||||
gStore = stores[0];
|
||||
gRevisions.push(gStore.revisionId);
|
||||
|
||||
gStore.onchange = function(aEvent) {
|
||||
ok(gExpectedEvents, "Events received!");
|
||||
runTest();
|
||||
}
|
||||
|
||||
runTest();
|
||||
}, cbError);
|
||||
}
|
||||
|
||||
function testBasicInterface() {
|
||||
var cursor = gStore.sync();
|
||||
ok(cursor, "Cursor is created");
|
||||
is(cursor.store, gStore, "Cursor.store is the store");
|
||||
|
||||
ok("next" in cursor, "Cursor.next exists");
|
||||
ok("close" in cursor, "Cursor.close exists");
|
||||
|
||||
cursor.close();
|
||||
|
||||
runTest();
|
||||
}
|
||||
|
||||
function testCursor(cursor, steps) {
|
||||
if (!steps.length) {
|
||||
runTest();
|
||||
return;
|
||||
}
|
||||
|
||||
var step = steps.shift();
|
||||
cursor.next().then(function(data) {
|
||||
ok(!!data, "Cursor.next returns data");
|
||||
is(data.operation, step.operation, "Waiting for operation: '" + step.operation + "' received '" + data.operation + "'");
|
||||
|
||||
|
||||
switch (data.operation) {
|
||||
case 'clear':
|
||||
is (data.id, null, "'clear' operation wants a null id");
|
||||
break;
|
||||
|
||||
case 'done':
|
||||
is(/[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}/.test(data.revisionId), true, "done has a valid revisionId");
|
||||
is (data.revisionId, gRevisions[gRevisions.length-1], "Last revision matches");
|
||||
is (data.id, null, "'done' operation wants a null id");
|
||||
break;
|
||||
|
||||
case 'add':
|
||||
case 'update':
|
||||
if ('id' in step) {
|
||||
is(data.id, step.id, "next() add: id matches: " + data.id + " " + step.id);
|
||||
}
|
||||
|
||||
if ('data' in step) {
|
||||
is(data.data, step.data, "next() add: data matches: " + data.data + " " + step.data);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'remove':
|
||||
if ('id' in step) {
|
||||
is(data.id, step.id, "next() add: id matches: " + data.id + " " + step.id);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
testCursor(cursor, steps);
|
||||
});
|
||||
}
|
||||
|
||||
var tests = [
|
||||
// Test for GetDataStore
|
||||
testGetDataStores,
|
||||
|
||||
// interface test
|
||||
testBasicInterface,
|
||||
|
||||
// empty DataStore
|
||||
function() {
|
||||
var cursor = gStore.sync();
|
||||
var steps = [ { operation: 'clear' },
|
||||
{ operation: 'done' },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
gExpectedEvents = false;
|
||||
var cursor = gStore.sync('wrong revision ID');
|
||||
var steps = [ { operation: 'clear' },
|
||||
{ operation: 'done' },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[0]);
|
||||
var steps = [ { operation: 'done' },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
// Test add from scratch
|
||||
function() {
|
||||
gExpectedEvents = true;
|
||||
|
||||
gStore.add(1).then(function(id) {
|
||||
gRevisions.push(gStore.revisionId);
|
||||
ok(true, "Item: " + id + " added");
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
gStore.add(2,"foobar").then(function(id) {
|
||||
gRevisions.push(gStore.revisionId);
|
||||
ok(true, "Item: " + id + " added");
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
gStore.add(3,3).then(function(id) {
|
||||
gRevisions.push(gStore.revisionId);
|
||||
ok(true, "Item: " + id + " added");
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
gExpectedEvents = false;
|
||||
var cursor = gStore.sync();
|
||||
var steps = [ { operation: 'clear', },
|
||||
{ operation: 'add', id: 1, data: 1 },
|
||||
{ operation: 'add', id: 3, data: 3 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync('wrong revision ID');
|
||||
var steps = [ { operation: 'clear', },
|
||||
{ operation: 'add', id: 1, data: 1 },
|
||||
{ operation: 'add', id: 3, data: 3 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[0]);
|
||||
var steps = [ { operation: 'add', id: 1, data: 1 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 },
|
||||
{ operation: 'add', id: 3, data: 3 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[1]);
|
||||
var steps = [ { operation: 'add', id: 'foobar', data: 2 },
|
||||
{ operation: 'add', id: 3, data: 3 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[2]);
|
||||
var steps = [ { operation: 'add', id: 3, data: 3 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[3]);
|
||||
var steps = [ { operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
// Test after an update
|
||||
function() {
|
||||
gExpectedEvents = true;
|
||||
gStore.put(123, 1).then(function() {
|
||||
gRevisions.push(gStore.revisionId);
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
gExpectedEvents = false;
|
||||
var cursor = gStore.sync();
|
||||
var steps = [ { operation: 'clear', },
|
||||
{ operation: 'add', id: 1, data: 123 },
|
||||
{ operation: 'add', id: 3, data: 3 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync('wrong revision ID');
|
||||
var steps = [ { operation: 'clear', },
|
||||
{ operation: 'add', id: 1, data: 123 },
|
||||
{ operation: 'add', id: 3, data: 3 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[0]);
|
||||
var steps = [ { operation: 'add', id: 1, data: 123 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 },
|
||||
{ operation: 'add', id: 3, data: 3 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[1]);
|
||||
var steps = [ { operation: 'add', id: 'foobar', data: 2 },
|
||||
{ operation: 'add', id: 3, data: 3 },
|
||||
{ operation: 'update', id: 1, data: 123 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[2]);
|
||||
var steps = [ { operation: 'add', id: 3, data: 3 },
|
||||
{ operation: 'update', id: 1, data: 123 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[3]);
|
||||
var steps = [ { operation: 'update', id: 1, data: 123 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[4]);
|
||||
var steps = [ { operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
// Test after a remove
|
||||
function() {
|
||||
gExpectedEvents = true;
|
||||
gStore.remove(3).then(function() {
|
||||
gRevisions.push(gStore.revisionId);
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
gExpectedEvents = false;
|
||||
var cursor = gStore.sync();
|
||||
var steps = [ { operation: 'clear', },
|
||||
{ operation: 'add', id: 1, data: 123 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync('wrong revision ID');
|
||||
var steps = [ { operation: 'clear', },
|
||||
{ operation: 'add', id: 1, data: 123 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[0]);
|
||||
var steps = [ { operation: 'add', id: 1, data: 123 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[1]);
|
||||
var steps = [ { operation: 'add', id: 'foobar', data: 2 },
|
||||
{ operation: 'update', id: 1, data: 123 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[2]);
|
||||
var steps = [ { operation: 'update', id: 1, data: 123 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[3]);
|
||||
var steps = [ { operation: 'update', id: 1, data: 123 },
|
||||
{ operation: 'remove', id: 3 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[4]);
|
||||
var steps = [ { operation: 'remove', id: 3 },
|
||||
{ operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
var cursor = gStore.sync(gRevisions[5]);
|
||||
var steps = [ { operation: 'done' }];
|
||||
testCursor(cursor, steps);
|
||||
},
|
||||
|
||||
// New events when the cursor is active
|
||||
function() {
|
||||
gCursor = gStore.sync();
|
||||
var steps = [ { operation: 'clear', },
|
||||
{ operation: 'add', id: 1, data: 123 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 } ];
|
||||
testCursor(gCursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
gStore.add(42, 2).then(function(id) {
|
||||
ok(true, "Item: " + id + " added");
|
||||
gRevisions.push(gStore.revisionId);
|
||||
runTest();
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
var steps = [ { operation: 'clear', },
|
||||
{ operation: 'add', id: 1, data: 123 },
|
||||
{ operation: 'add', id: 2, data: 42 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 } ]
|
||||
testCursor(gCursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
gStore.put(43, 2).then(function(id) {
|
||||
gRevisions.push(gStore.revisionId);
|
||||
runTest();
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
var steps = [ { operation: 'clear', },
|
||||
{ operation: 'add', id: 1, data: 123 },
|
||||
{ operation: 'add', id: 2, data: 43 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 } ]
|
||||
testCursor(gCursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
gStore.remove(2).then(function(id) {
|
||||
gRevisions.push(gStore.revisionId);
|
||||
runTest();
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
var steps = [ { operation: 'clear', },
|
||||
{ operation: 'add', id: 1, data: 123 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 } ]
|
||||
testCursor(gCursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
gStore.add(42).then(function(id) {
|
||||
ok(true, "Item: " + id + " added");
|
||||
gRevisions.push(gStore.revisionId);
|
||||
runTest();
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
var steps = [ { operation: 'clear', },
|
||||
{ operation: 'add', id: 1, data: 123 },
|
||||
{ operation: 'add', id: 4, data: 42 },
|
||||
{ operation: 'add', id: 'foobar', data: 2 } ]
|
||||
testCursor(gCursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
gStore.clear().then(function() {
|
||||
gRevisions.push(gStore.revisionId);
|
||||
runTest();
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
var steps = [ { operation: 'clear' } ];
|
||||
testCursor(gCursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
gStore.add(42).then(function(id) {
|
||||
ok(true, "Item: " + id + " added");
|
||||
gRevisions.push(gStore.revisionId);
|
||||
runTest();
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
var steps = [ { operation: 'clear', },
|
||||
{ operation: 'add', id: 5, data: 42 } ];
|
||||
testCursor(gCursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
gStore.clear().then(function() {
|
||||
gRevisions.push(gStore.revisionId);
|
||||
runTest();
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
gStore.add(42).then(function(id) {
|
||||
ok(true, "Item: " + id + " added");
|
||||
gRevisions.push(gStore.revisionId);
|
||||
runTest();
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
var steps = [ { operation: 'clear' },
|
||||
{ operation: 'add', id: 6, data: 42 },
|
||||
{ operation: 'done'} ];
|
||||
testCursor(gCursor, steps);
|
||||
},
|
||||
|
||||
function() {
|
||||
gExpectedEvents = true;
|
||||
gStore.add(42).then(function(id) {
|
||||
});
|
||||
}
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - sync</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var messages = [];
|
||||
var worker = new Worker("file_sync_worker.js");
|
||||
|
||||
worker.onmessage = function(event) {
|
||||
messages.push(event.data)
|
||||
|
||||
if (event.data == 'DONE') {
|
||||
// Free the worker when all the tests are done.
|
||||
worker.terminate();
|
||||
|
||||
// Fire message to the test_sync_worker.html.
|
||||
for (var i = 0; i < messages.length; i++) {
|
||||
alert(messages[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,19 +0,0 @@
|
||||
function is(a, b, msg) {
|
||||
postMessage((a === b ? 'OK' : 'KO') + ' ' + msg)
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
postMessage((a ? 'OK' : 'KO')+ ' ' + msg)
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
postMessage('KO error');
|
||||
}
|
||||
|
||||
function finish() {
|
||||
postMessage('DONE');
|
||||
}
|
||||
|
||||
importScripts("file_sync_common.js");
|
||||
|
||||
runTest();
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user