mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1120715 - Part 6: Remove the dom.requestcache.enabled pref; r=bkelly (800c996a96) - Bug 1143222 - Put the DOM Cache tests in sequential mode again until we fix the rest of the intermittent failures; a=RyanVM (2ebdd659a1) - Bug 1255636 - Give a better error message when the Request constructor fails because of a cross-origin referrer URL; r=bkelly (d81a21c0bb) - Bug 1265056 - don't needlessly construct nsAutoCString temporaries in dom/; r=baku (3be49ca3fc) - Bug 1243849 - Restore support for accessing the Cache API from app:// URLs and also for storing requests/responses with app:// URLs within it; r=bkelly (eb56fa564c) - Bug 1263235, part 1 - Move PBrowser::AsyncMessage's data argument last. r=smaug (6852b87c22) - Bug 1263235, part 2 - Make PContent::AsyncMessage and PContentBridge::AsyncMessage's data argument last. r=smaug (9e8cd94461) - Bug 1263028 - send HTTP data to the content process in smaller chunks, r=michal (c0da548157) - Bug 1263235, part 3 - Move PHttpChannel::OnTransportAndData's data argument last. r=mayhemer (e1bf4f430f) - Bug 1263235, part 4 - Make PBrowserStream::Write's data argument last. r=jimm (8bcec4d541) - Bug 1260876 - Remove process switch code for signed package code (added by Bug 1186290). r=valentin. (cef270b44c) - Bug 1234575 - Empty fragment is ignored in URI of location header r=mcmanus (db68f102d8) - Bug 1262506 - Unused variable in a runnable in BackgroundParentImpl, r=ehsan (9288f0a111) - bug 1239166 - platform work to support Microsoft Family Safety functionality r=froydnj,mgoodwin,mhowell,rbarnes,vladan (adc357f3b3) - Bug 842818 - Make Crypto::GetRandomValues() work off the main thread r=baku,keeler,mt (533f8942c4) - Bug 1247089 - Add a mode to ReportToConsoleNonLocalized that ignores the calling location. r=bkelly (4be23e0869) - Bug 1258883 - Add a way to replace the entire Push service in tests. r=wchen (06a5f27016) - Bug 1243856 - Remove alarms from the Push H2 backend. r=dragana (60d146dc73) - Bug 1246066 - Clear PushService timeout tasks on uninitialization. r=itcambridge (461276a972) - Bug 1214338 - Implement Android GCM-based PushService protocol. r=rnewman r=kitcambridge (f2bb78994a) - Bug 1257821 - Support the new aesgcm content encoding scheme. r=mt (1da653c14a) - Bug 1243856 - Remove alarms from the Push WebSocket backend. r=dragana (43f74c4999) - Bug 1258145 - Remove waitForPromise from the xpcshell tests. r=wchen (cdd1aff2f6) - Bug 1253831 - Don't check actual intervals in the Push backoff test. r=wchen (859fa0bba3) - Bug 1246341 - Include status codes in "ack" and "unregister" requests. r=dragana (a62d0daf9b) - Bug 1246341 - Add a test for push event error reporting. r=dragana (013bc814e4) - Bug 1247089 - Log Web Push decryption errors. r=bkelly (ffc093dc2f) - Bug 1258221 - patch 2 - Port FileSystem API and DeviceStorage API to PBackground, r=smaug (c1c0e08bc0) - Bug 1258221 - patch 3 - Rename FileSystemTaskBase to FileSystemTaskChildBase, r=smaug (867a0e65fd) - Bug 1251032 - Don't return layersId or textureFactoryIdentifier as outparams in RenderFrameParent constructor. r=kanru (198ddff7fc) - Bug 1251032 - Send RenderFrame info down to child in CreateWindow message. r=kanru (87e9001088) - Bug 1251032 - Make it possible to assign a frameloader to RenderFrameParent after construction. r=kanru (96483d1282) - Bug 1254865 - Send disableglobalhistory state down to TabChild after construction asynchronously. r=smaug (3949285b62) - Bug 1238707 Release the window immediately in TabParent::Destroy() to avoid leaks. r=smaug (fc612485d7) - Bug 1256589 part.1 Move the implementation of StopPropagation() from dom::Event to WidgetEvent r=smaug (181721b64c) - Bug 1256589 part.2 Move the implementation of StopImmediatePropagation() from dom::Event to WidgetEvent r=smaug (554a0dc5b5) - Bug 1203059 part.1 nsXBLWincowKeyHandler mark WidgetEvent::mFlags if it's reserved by chrome before the event is dispatched into the content r=smaug (9162dd68cb) - Bug 1203059 part.2 When an event is reserved by chrome, it should be fired only on chrome r=smaug (35f082ca5f) - Bug 1203059 part.3 Installing and removing keyboard event listeners of nsXBLWindowKeyHandler should be done by the class itself r=smaug (1e06c2d0bc) - Bug 1203059 part.4 Update test_keycodes.xul for the new behavior r=smaug (3014d21c75) - Bug 1256589 part.3 Move the implementation of StopCrossProcessForwarding() from dom::Event to WidgetEvent r=smaug (96db915b51) - Bug 1257180 - patch 1 - Directory clonable to workers, r=smaug (5634acb08d) - Bug 1257180 - patch 2 - Directory can be sent via postMessage(), r=smaug (82ada39ae3) - Bug 1263311: Part 3 - s/nsCancelableRunnable/CancelableRunnable/g. r=froydnj (79d0a6c81f) - Bug 1253198: add WebRtcIce prefix to all ICE unit tests. r=bwc (9c18f5fd56) - Bug 1244926: added TCP socket filter to only allow outgoing STUN. r=jesup (75debfdc84) - Bug 1257405 - Increase auth secret length to 16 octets. r=mt (b1e000c331) - Bug 1257401 - Remove the worker descriptor for PushSubscription. r=khuey (5791fb69ef) - Bug 1257401 - Remove the worker descriptor for PushManager. r=khuey (e2c75903a9) - Bug 1257821 - Remove the authenticated aesgcm128 content coding scheme. r=mt,marco (64a2917910) - Bug 1256488 - Add a Base64 URL-decoder for C++ and chrome JS callers. r=mt,baku (0bbb250298) - Bug 1247685 - Validate and store app server keys in the Push service. r=mt (c3c026ccb1) - Bug 1252650 - Support loading PushService immediately on Android; r=kitcambridge (d59a37fec4) - Bug 1258595 - Shut down the Push service if errors occur at startup. r=wchen (eef1805652) - Bug 1258595 - Wait for the Push service to shut down between tests. r=wchen (c30cf92ce6) - Bug 1262618 - Fix an unchained promise and a couple of non-promise returns in the push service. r=wchen (8eadab5706) - Bug 1263747 - Log error messages when stringifying errors. r=bgrins (edffd0074e) - Bug 1265705 - Silence startup JavaScript strict warning in resource://gre/modules/PushService.jsm. r=kitcambridge (e7e210fb61) - Bug 1264062 - Don't bother checking which accelerated layer types are available if they're all disabled by pref r=milan (0d3208ad59) - Bug 1263346. Remove wrong Ivy Bridge device id. r=Bas (7e39e7f370) - fix misspatch (a67a111b2c) - Bug 1251334 - Create a disposable pref to force-disable e10s in an emergency. r=jimm (ef892d4474) - Bug 1254774 - error: member access into incomplete type 'nsIUUIDGenerator' after bug 1237847. r=aklotz (c1f334609f) - Bug 1257242 - Split the ::BrowserTabsRemoteAutostart() function into two parts, to allow for the blocking policies to be checked independently from the prefs checks. r=jimm (1babda578f) - Bug 1260190 - Disable e10s for accessibility users on OS X. r=jimm (219e5b1f19) - Bug 1237769 - Disable e10s on Windows XP if layers acceleration is requested r=milan (60f2434e9f) - Bug 1232911 - [3.2] Block VPX support in ADM on unsupported devices. r=snorp (6924aa073a) - Bug 1263249 - Bubble up unique failureId in GetFeatureStatus. r=mconley,milan (cd56eeab3c) - Bug 1219296 - Split fields not needed for repaints out from FrameMetrics. r=kats (9003ca634a) - Bug 1219296 - Factor out scroll snap information into a form that's usable by the compositor. r=kats (23d3e619a1) - Bug 1219296 - Make ScrollMetadata::sNullMetadata a StaticAutoPtr so that ScrollMetadata can admit nsTArray members. r=kats (1729ff7d93) - Bug 1257641 - Replace the mUpdateScrollOffset bool with an enum, needed in the next patch. r=botond (f9d546f8e8) - Bug 1257641 - Use empty transactions to carry scroll offset updates to APZ that don't require a repaint. r=mattwoodrow,mstange,botond (ba4a8a8c29) - Bug 1246290 - Add a bit to FrameMetrics to indicate if APZ-scrolling should be disabled on that APZC. r=botond (af2067137f) - Bug 1256589 part.4 Move the implementation of PreventDefault() and add PreventDefaultBeforeDispatch() from dom::Event to WidgetEvent r=smaug (e7828f2d8f) - Bug 1256589 part.5 Add DefaultPrevented() and DefaultPreventedByContent() to WidgetEvent r=smaug (e65cdd9127) - Bug 1249915 - Fix missing MOZ_COUNT_CTOR and some misc cleanup. r=karlt (d2f26cf971) - Bug 1154183 part.1 Move shortcut/access key candidate list creators from nsContentUtils to WidgetKeyboardEvent r=smaug (40b0b11a5a) - Bug 1154183 part.2 eKeyDown event should have charCode value of following keypress event r=smaug (28c1443ba3) - Bug 1154183 part.3 Clean up some variable names in nsXBLWindowKeyHandler::WalkHandlersAndExecute() r=smaug (81e25023d8) - Bug 1154183 part.4 Implement nsXBLWindowKeyHandler::GetElementForHandler() r=smaug (b5605d5c83) - Bug 1154183 part.5 Make nsXBLWindowKeyHandler::GetElementForHandler() use early return style r=smaug (017467204f) - Bug 1154183 part.6 Add nsXBLWindowKeyHandler::IsExecuteableElement() r=smaug (1fda349113) - Bug 1154183 part.7 Don't dispatch preceding keydown events of reserved keypress events on content in the default event group r=smaug (15b9e8c9d2) - Bug 1256589 part.6 Move the implementation of IsTrusted() from dom::Event to WidgetEvent r=smaug (ec79520fd3) - Bug 1253044. Fix fall through of observer topics when other conditions aren't met in PresShell::Observe. r=dholbert (dcc36884aa) - Bug 1157546 - Replace the image visibility API with a more general API that tracks visibility for any kind of frame. r=mstange (d6ea061614) - Bug 1219296 - Factor out the algorithm that computes a scroll snap destination into a reusable form. r=kats (296cbe9e49) - Bug 1254275 - Inspect the event queue to find out whether momentum events are following. r=kats (b2bb8a26b9) - Bug 1219296 - Scroll snap directly in APZ instead of going through the main thread. r=kats (0a30b550f9) - Bug 1219296 - Fix an include-what-you-use error. r=kats (4a128ae98e) - Bug 1260588 - C++ APZ should only allow handoff to ancestor APZC r=botond (9856ab5160) - Bug 1257269 - Panning up in a scrollable element should not hide the toolbar r=kats,jchen (1036ffc9e3) - Bug 1219296 - Ship scroll snap information to the compositor. r=kats (0e920f02a1) - Bug 1219296 - Move the layout.css.scroll-snap.proximity-threshold pref to gfxPrefs, so it can be queried on the compositor thread. r=kats (2e3e1ec16e) - Bug 1219296 - Remove StartSmoothScroll()'s argument, which is no longer used. r=kats (12efcd9c79) - Bug 1219296 - Light refactoring to how a smooth scroll is launched inside APZC. r=kats (ba6a9ed9a2) - Bug 1219296 - Followup to fix stale code comments. r=me and DONTBUILD (fec5f65988) - Bug 1257641 - Remove now-unused code for the lightweight scroll offset update message. r=botond (d449e45d6d) - Bug 1236680 Part 1: Add new WinUtils function to Resolve moved Users folder. r=jimm (51d12f856c) - Bug 1236680 Part 2: Resolve GMP path for moved Users folder. r=cpearce (e568217b78) - Bug 1236680 Part 3: Add #ifs to include to fix bustage. r=me (40c38680ea) - Bug 1240315: Add startup crash report annotation for AppInit_DLLs; r=jimm (aa2040baae) - Bug 1253446 - patch 2 - Return the proper scaling factor when querying the primary screen on Windows. r=emk (9765e4f7ca) - Bug 1251624 - patch 1 - The desktop to device scaling in WinUtils::MonitorFromRect should not depend on custom CSS pixel scaling (devPixelsPerPx setting). r=emk (788b4ad5db) - Bug 1251624 - patch 2 - Check for scaling override (devPixelsPerPx setting) in nsScreenWin::GetDefaultCSSScaleFactor, for proper window positioning when a custom scale factor is used. r=emk (2843a3fe70) - Bug 1222149 - delete unused fields from AsyncEncodeAndWriteIcon; r=roc clang-cl says these are unused, so let's delete them. (62cf7f8f47) - Bug 1204809 - Notify (don't hang) third party windows when adding shortcut icon. r=jmathies (7e4058a0f8) - Bug 1253566 - Deal with char16_t/wchar_t mismatch. r=aklotz (1c6cf160c7) - Bug 1211941 - Let nsICacheStorage.openTruncate impl return an HTTP cache entry write handle, r=michal (6a5796fb93) - Bug 1050613 - Make sure force-valid for HTTP cache entries is removed when entries are removed, r=michal (9efb91eefc) - Bug 1248389 - Cache index causing CPU loops, r=honzab (175b5b27f2) - Bug 1066970 - Show 'calculating' during HTTP cache cleaning process in preferences window, r=michal (db722000d8) - Bug 1248958 - CacheIndex mRWBuf ownership too fragile, read-after-free, r=honzab (66ee3d1d0d) - Bug 1248003 - Purge from HTTP cache memory pool only in reasonable intervals, r=michal (1cd6cb5983) - Bug 1068674 - Don't turn off e10s if hardware acceleration is disabled. r=jimm (dfbef44278)
This commit is contained in:
+2
-2
@@ -855,8 +855,8 @@ pref("memory.system_memory_reporter", true);
|
||||
// Don't dump memory reports on OOM, by default.
|
||||
pref("memory.dump_reports_on_oom", false);
|
||||
|
||||
pref("layout.imagevisibility.numscrollportwidths", 1);
|
||||
pref("layout.imagevisibility.numscrollportheights", 1);
|
||||
pref("layout.framevisibility.numscrollportwidths", 1);
|
||||
pref("layout.framevisibility.numscrollportheights", 1);
|
||||
|
||||
// Enable native identity (persona/browserid)
|
||||
pref("dom.identity.enabled", true);
|
||||
|
||||
@@ -4370,10 +4370,12 @@ this.DOMApplicationRegistry = {
|
||||
return "INVALID_SEGMENTS_NUMBER";
|
||||
}
|
||||
|
||||
// We need to translate the base64 alphabet used in JWT to our base64 alphabet
|
||||
// before calling atob.
|
||||
let decodedReceipt = JSON.parse(atob(segments[1].replace(/-/g, '+')
|
||||
.replace(/_/g, '/')));
|
||||
let jwtBuffer = ChromeUtils.base64URLDecode(segments[1], {
|
||||
// JWT/JWS prohibits padding per RFC 7515, section 2.
|
||||
padding: "reject",
|
||||
});
|
||||
let textDecoder = new TextDecoder("utf-8");
|
||||
let decodedReceipt = JSON.parse(textDecoder.decode(jwtBuffer));
|
||||
if (!decodedReceipt) {
|
||||
return "INVALID_RECEIPT_ENCODING";
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "ChromeUtils.h"
|
||||
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
|
||||
namespace mozilla {
|
||||
@@ -50,6 +51,61 @@ ThreadSafeChromeUtils::NondeterministicGetWeakSetKeys(GlobalObject& aGlobal,
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ThreadSafeChromeUtils::Base64URLEncode(GlobalObject& aGlobal,
|
||||
const ArrayBufferViewOrArrayBuffer& aSource,
|
||||
const Base64URLEncodeOptions& aOptions,
|
||||
nsACString& aResult,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
size_t length = 0;
|
||||
uint8_t* data = nullptr;
|
||||
if (aSource.IsArrayBuffer()) {
|
||||
const ArrayBuffer& buffer = aSource.GetAsArrayBuffer();
|
||||
buffer.ComputeLengthAndData();
|
||||
length = buffer.Length();
|
||||
data = buffer.Data();
|
||||
} else if (aSource.IsArrayBufferView()) {
|
||||
const ArrayBufferView& view = aSource.GetAsArrayBufferView();
|
||||
view.ComputeLengthAndData();
|
||||
length = view.Length();
|
||||
data = view.Data();
|
||||
} else {
|
||||
MOZ_CRASH("Uninitialized union: expected buffer or view");
|
||||
}
|
||||
|
||||
nsresult rv = mozilla::Base64URLEncode(length, data, aOptions, aResult);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aResult.Truncate();
|
||||
aRv.Throw(rv);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ThreadSafeChromeUtils::Base64URLDecode(GlobalObject& aGlobal,
|
||||
const nsACString& aString,
|
||||
const Base64URLDecodeOptions& aOptions,
|
||||
JS::MutableHandle<JSObject*> aRetval,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
FallibleTArray<uint8_t> data;
|
||||
nsresult rv = mozilla::Base64URLDecode(aString, aOptions, data);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> buffer(aGlobal.Context(),
|
||||
ArrayBuffer::Create(aGlobal.Context(),
|
||||
data.Length(),
|
||||
data.Elements()));
|
||||
if (NS_WARN_IF(!buffer)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
aRetval.set(buffer);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ChromeUtils::OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
|
||||
const dom::OriginAttributesDictionary& aAttrs,
|
||||
|
||||
@@ -20,6 +20,8 @@ class HeapSnapshot;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class ArrayBufferViewOrArrayBuffer;
|
||||
|
||||
class ThreadSafeChromeUtils
|
||||
{
|
||||
public:
|
||||
@@ -43,6 +45,18 @@ public:
|
||||
JS::Handle<JS::Value> aSet,
|
||||
JS::MutableHandle<JS::Value> aRetval,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static void Base64URLEncode(GlobalObject& aGlobal,
|
||||
const ArrayBufferViewOrArrayBuffer& aSource,
|
||||
const Base64URLEncodeOptions& aOptions,
|
||||
nsACString& aResult,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static void Base64URLDecode(GlobalObject& aGlobal,
|
||||
const nsACString& aString,
|
||||
const Base64URLDecodeOptions& aOptions,
|
||||
JS::MutableHandle<JSObject*> aRetval,
|
||||
ErrorResult& aRv);
|
||||
};
|
||||
|
||||
class ChromeUtils : public ThreadSafeChromeUtils
|
||||
|
||||
+16
-42
@@ -58,8 +58,6 @@ Crypto::GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
|
||||
JS::MutableHandle<JSObject*> aRetval,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Called on the wrong thread");
|
||||
|
||||
JS::Rooted<JSObject*> view(aCx, aArray.Obj());
|
||||
|
||||
if (JS_IsTypedArrayObject(view) && JS_GetTypedArraySharedness(view)) {
|
||||
@@ -95,32 +93,24 @@ Crypto::GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t* data = aArray.Data();
|
||||
|
||||
if (!XRE_IsParentProcess()) {
|
||||
InfallibleTArray<uint8_t> randomValues;
|
||||
// Tell the parent process to generate random values via PContent
|
||||
ContentChild* cc = ContentChild::GetSingleton();
|
||||
if (!cc->SendGetRandomValues(dataLen, &randomValues) ||
|
||||
randomValues.Length() == 0) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
NS_ASSERTION(dataLen == randomValues.Length(),
|
||||
"Invalid length returned from parent process!");
|
||||
memcpy(data, randomValues.Elements(), dataLen);
|
||||
} else {
|
||||
uint8_t *buf = GetRandomValues(dataLen);
|
||||
|
||||
if (!buf) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(data, buf, dataLen);
|
||||
NS_Free(buf);
|
||||
nsCOMPtr<nsIRandomGenerator> randomGenerator =
|
||||
do_GetService("@mozilla.org/security/random-generator;1");
|
||||
if (!randomGenerator) {
|
||||
aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t* buf;
|
||||
nsresult rv = randomGenerator->GenerateRandomBytes(dataLen, &buf);
|
||||
if (NS_FAILED(rv) || !buf) {
|
||||
aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy random bytes to ABV.
|
||||
memcpy(aArray.Data(), buf, dataLen);
|
||||
NS_Free(buf);
|
||||
|
||||
aRetval.set(view);
|
||||
}
|
||||
|
||||
@@ -133,21 +123,5 @@ Crypto::Subtle()
|
||||
return mSubtle;
|
||||
}
|
||||
|
||||
/* static */ uint8_t*
|
||||
Crypto::GetRandomValues(uint32_t aLength)
|
||||
{
|
||||
nsCOMPtr<nsIRandomGenerator> randomGenerator;
|
||||
nsresult rv;
|
||||
randomGenerator = do_GetService("@mozilla.org/security/random-generator;1");
|
||||
NS_ENSURE_TRUE(randomGenerator, nullptr);
|
||||
|
||||
uint8_t* buf;
|
||||
rv = randomGenerator->GenerateRandomBytes(aLength, &buf);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -54,9 +54,6 @@ public:
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
static uint8_t*
|
||||
GetRandomValues(uint32_t aLength);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIGlobalObject> mParent;
|
||||
RefPtr<SubtleCrypto> mSubtle;
|
||||
|
||||
@@ -2116,7 +2116,7 @@ Element::DispatchClickEvent(nsPresContext* aPresContext,
|
||||
NS_PRECONDITION(aSourceEvent, "Must have source event");
|
||||
NS_PRECONDITION(aStatus, "Null out param?");
|
||||
|
||||
WidgetMouseEvent event(aSourceEvent->mFlags.mIsTrusted, eMouseClick,
|
||||
WidgetMouseEvent event(aSourceEvent->IsTrusted(), eMouseClick,
|
||||
aSourceEvent->widget, WidgetMouseEvent::eReal);
|
||||
event.refPoint = aSourceEvent->refPoint;
|
||||
uint32_t clickCount = 1;
|
||||
@@ -2929,7 +2929,7 @@ Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
|
||||
nsIURI** aURI) const
|
||||
{
|
||||
if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
|
||||
(!aVisitor.mEvent->mFlags.mIsTrusted &&
|
||||
(!aVisitor.mEvent->IsTrusted() &&
|
||||
(aVisitor.mEvent->mMessage != eMouseClick) &&
|
||||
(aVisitor.mEvent->mMessage != eKeyPress) &&
|
||||
(aVisitor.mEvent->mMessage != eLegacyDOMActivate)) ||
|
||||
|
||||
@@ -115,7 +115,8 @@ bool
|
||||
FileList::ClonableToDifferentThreadOrProcess() const
|
||||
{
|
||||
for (uint32_t i = 0; i < mFilesOrDirectories.Length(); ++i) {
|
||||
if (mFilesOrDirectories[i].IsDirectory()) {
|
||||
if (mFilesOrDirectories[i].IsDirectory() &&
|
||||
!mFilesOrDirectories[i].GetAsDirectory()->ClonableToDifferentThreadOrProcess()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ GetBRGADataSourceSurfaceSync(already_AddRefed<layers::Image> aImage)
|
||||
return helper->GetDataSurfaceSafe();
|
||||
}
|
||||
|
||||
class EncodingCompleteEvent : public nsCancelableRunnable
|
||||
class EncodingCompleteEvent : public CancelableRunnable
|
||||
{
|
||||
virtual ~EncodingCompleteEvent() {}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "mozilla/dom/BlobBinding.h"
|
||||
#include "mozilla/dom/CryptoKey.h"
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/DirectoryBinding.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileList.h"
|
||||
#include "mozilla/dom/FileListBinding.h"
|
||||
@@ -663,7 +664,7 @@ ReadBlob(JSContext* aCx,
|
||||
|
||||
MOZ_ASSERT(blobImpl);
|
||||
|
||||
// RefPtr<File> needs to go out of scope before toObjectOrNull() is
|
||||
// RefPtr<File> needs to go out of scope before toObject() is
|
||||
// called because the static analysis thinks dereferencing XPCOM objects
|
||||
// can GC (because in some cases it can!), and a return statement with a
|
||||
// JSObject* type means that JSObject* is on the stack as a raw pointer
|
||||
@@ -710,6 +711,80 @@ WriteBlob(JSStructuredCloneWriter* aWriter,
|
||||
return false;
|
||||
}
|
||||
|
||||
// A directory is serialized as:
|
||||
// - pair of ints: SCTAG_DOM_DIRECTORY, 0
|
||||
// - pair of ints: type (eDOMRootDirectory/eDOMNotRootDirectory) - path length
|
||||
// - path as string
|
||||
bool
|
||||
WriteDirectory(JSStructuredCloneWriter* aWriter,
|
||||
Directory* aDirectory)
|
||||
{
|
||||
MOZ_ASSERT(aWriter);
|
||||
MOZ_ASSERT(aDirectory);
|
||||
|
||||
nsAutoString path;
|
||||
aDirectory->GetFullRealPath(path);
|
||||
|
||||
size_t charSize = sizeof(nsString::char_type);
|
||||
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DIRECTORY, 0) &&
|
||||
JS_WriteUint32Pair(aWriter, (uint32_t)aDirectory->Type(),
|
||||
path.Length()) &&
|
||||
JS_WriteBytes(aWriter, path.get(), path.Length() * charSize);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
ReadDirectory(JSContext* aCx,
|
||||
JSStructuredCloneReader* aReader,
|
||||
uint32_t aZero,
|
||||
StructuredCloneHolder* aHolder)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aReader);
|
||||
MOZ_ASSERT(aHolder);
|
||||
MOZ_ASSERT(aZero == 0);
|
||||
|
||||
uint32_t directoryType, lengthOfString;
|
||||
if (!JS_ReadUint32Pair(aReader, &directoryType, &lengthOfString)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(directoryType == Directory::eDOMRootDirectory ||
|
||||
directoryType == Directory::eNotDOMRootDirectory);
|
||||
|
||||
nsAutoString path;
|
||||
path.SetLength(lengthOfString);
|
||||
size_t charSize = sizeof(nsString::char_type);
|
||||
if (!JS_ReadBytes(aReader, (void*) path.BeginWriting(),
|
||||
lengthOfString * charSize)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
|
||||
getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// RefPtr<Directory> needs to go out of scope before toObject() is
|
||||
// called because the static analysis thinks dereferencing XPCOM objects
|
||||
// can GC (because in some cases it can!), and a return statement with a
|
||||
// JSObject* type means that JSObject* is on the stack as a raw pointer
|
||||
// while destructors are running.
|
||||
JS::Rooted<JS::Value> val(aCx);
|
||||
{
|
||||
RefPtr<Directory> directory =
|
||||
Directory::Create(aHolder->ParentDuringRead(), file,
|
||||
(Directory::DirectoryType) directoryType);
|
||||
|
||||
if (!ToJSValue(aCx, directory, &val)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return &val.toObject();
|
||||
}
|
||||
|
||||
// Read the WriteFileList for the format.
|
||||
JSObject*
|
||||
ReadFileList(JSContext* aCx,
|
||||
@@ -1007,6 +1082,10 @@ StructuredCloneHolder::CustomReadHandler(JSContext* aCx,
|
||||
return ReadBlob(aCx, aIndex, this);
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_DIRECTORY) {
|
||||
return ReadDirectory(aCx, aReader, aIndex, this);
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_FILELIST) {
|
||||
return ReadFileList(aCx, aReader, aIndex, this);
|
||||
}
|
||||
@@ -1047,6 +1126,14 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
|
||||
}
|
||||
}
|
||||
|
||||
// See if this is a Directory object.
|
||||
{
|
||||
Directory* directory = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(Directory, aObj, directory))) {
|
||||
return WriteDirectory(aWriter, directory);
|
||||
}
|
||||
}
|
||||
|
||||
// See if this is a FileList object.
|
||||
{
|
||||
FileList* fileList = nullptr;
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace dom {
|
||||
enum StructuredCloneTags {
|
||||
SCTAG_BASE = JS_SCTAG_USER_MIN,
|
||||
|
||||
// These tags are used only for main thread structured clone.
|
||||
SCTAG_DOM_BLOB,
|
||||
|
||||
// This tag is obsolete and exists only for backwards compatibility with
|
||||
@@ -53,6 +52,8 @@ enum StructuredCloneTags {
|
||||
|
||||
SCTAG_DOM_EXPANDED_PRINCIPAL,
|
||||
|
||||
SCTAG_DOM_DIRECTORY,
|
||||
|
||||
SCTAG_DOM_MAX
|
||||
};
|
||||
|
||||
|
||||
@@ -712,7 +712,8 @@ TextInputProcessor::WillDispatchKeyboardEvent(
|
||||
uint32_t aIndexOfKeypress,
|
||||
void* aData)
|
||||
{
|
||||
// TextInputProcessor doesn't set alternative char code.
|
||||
// TextInputProcessor doesn't set alternative char code nor modify charCode
|
||||
// even when Ctrl key is pressed.
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
||||
@@ -254,7 +254,7 @@ NS_IMPL_ISUPPORTS(WebSocketImpl,
|
||||
nsIRequest,
|
||||
nsIEventTarget)
|
||||
|
||||
class CallDispatchConnectionCloseEvents final : public nsCancelableRunnable
|
||||
class CallDispatchConnectionCloseEvents final : public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit CallDispatchConnectionCloseEvents(WebSocketImpl* aWebSocketImpl)
|
||||
@@ -1251,7 +1251,7 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
|
||||
|
||||
RefPtr<InitRunnable> runnable =
|
||||
new InitRunnable(webSocket->mImpl, aUrl, protocolArray,
|
||||
nsAutoCString(file.get()), lineno, column, aRv,
|
||||
nsDependentCString(file.get()), lineno, column, aRv,
|
||||
&connectionFailed);
|
||||
runnable->Dispatch(aRv);
|
||||
}
|
||||
|
||||
+8
-187
@@ -3496,7 +3496,8 @@ nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
|
||||
nsIURI* aURI,
|
||||
const nsAFlatString& aSourceLine,
|
||||
uint32_t aLineNumber,
|
||||
uint32_t aColumnNumber)
|
||||
uint32_t aColumnNumber,
|
||||
MissingErrorLocationMode aLocationMode)
|
||||
{
|
||||
uint64_t innerWindowID = 0;
|
||||
if (aDocument) {
|
||||
@@ -3513,14 +3514,15 @@ nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
|
||||
}
|
||||
|
||||
nsAutoCString spec;
|
||||
if (!aLineNumber) {
|
||||
if (!aLineNumber && aLocationMode == eUSE_CALLING_LOCATION) {
|
||||
JSContext *cx = GetCurrentJSContext();
|
||||
if (cx) {
|
||||
nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber, &aColumnNumber);
|
||||
}
|
||||
}
|
||||
if (spec.IsEmpty() && aURI)
|
||||
if (spec.IsEmpty() && aURI) {
|
||||
aURI->GetSpec(spec);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptError> errorObject =
|
||||
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
|
||||
@@ -4922,188 +4924,6 @@ nsContentUtils::GetLocalizedEllipsis()
|
||||
return nsDependentString(sBuf);
|
||||
}
|
||||
|
||||
static bool
|
||||
HasASCIIDigit(const nsTArray<nsShortcutCandidate>& aCandidates)
|
||||
{
|
||||
for (uint32_t i = 0; i < aCandidates.Length(); ++i) {
|
||||
uint32_t ch = aCandidates[i].mCharCode;
|
||||
if (ch >= '0' && ch <= '9')
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
CharsCaseInsensitiveEqual(uint32_t aChar1, uint32_t aChar2)
|
||||
{
|
||||
return aChar1 == aChar2 ||
|
||||
(IS_IN_BMP(aChar1) && IS_IN_BMP(aChar2) &&
|
||||
ToLowerCase(char16_t(aChar1)) == ToLowerCase(char16_t(aChar2)));
|
||||
}
|
||||
|
||||
static bool
|
||||
IsCaseChangeableChar(uint32_t aChar)
|
||||
{
|
||||
return IS_IN_BMP(aChar) &&
|
||||
ToLowerCase(char16_t(aChar)) != ToUpperCase(char16_t(aChar));
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsContentUtils::GetAccelKeyCandidates(nsIDOMKeyEvent* aDOMKeyEvent,
|
||||
nsTArray<nsShortcutCandidate>& aCandidates)
|
||||
{
|
||||
NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty");
|
||||
|
||||
nsAutoString eventType;
|
||||
aDOMKeyEvent->AsEvent()->GetType(eventType);
|
||||
// Don't process if aDOMKeyEvent is not a keypress event.
|
||||
if (!eventType.EqualsLiteral("keypress"))
|
||||
return;
|
||||
|
||||
WidgetKeyboardEvent* nativeKeyEvent =
|
||||
aDOMKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
|
||||
if (nativeKeyEvent) {
|
||||
NS_ASSERTION(nativeKeyEvent->mClass == eKeyboardEventClass,
|
||||
"wrong type of native event");
|
||||
// nsShortcutCandidate::mCharCode is a candidate charCode.
|
||||
// nsShoftcutCandidate::mIgnoreShift means the mCharCode should be tried to
|
||||
// execute a command with/without shift key state. If this is TRUE, the
|
||||
// shifted key state should be ignored. Otherwise, don't ignore the state.
|
||||
// the priority of the charCodes are (shift key is not pressed):
|
||||
// 0: charCode/false,
|
||||
// 1: unshiftedCharCodes[0]/false, 2: unshiftedCharCodes[1]/false...
|
||||
// the priority of the charCodes are (shift key is pressed):
|
||||
// 0: charCode/false,
|
||||
// 1: shiftedCharCodes[0]/false, 2: shiftedCharCodes[0]/true,
|
||||
// 3: shiftedCharCodes[1]/false, 4: shiftedCharCodes[1]/true...
|
||||
if (nativeKeyEvent->charCode) {
|
||||
nsShortcutCandidate key(nativeKeyEvent->charCode, false);
|
||||
aCandidates.AppendElement(key);
|
||||
}
|
||||
|
||||
uint32_t len = nativeKeyEvent->alternativeCharCodes.Length();
|
||||
if (!nativeKeyEvent->IsShift()) {
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
uint32_t ch =
|
||||
nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode;
|
||||
if (!ch || ch == nativeKeyEvent->charCode)
|
||||
continue;
|
||||
|
||||
nsShortcutCandidate key(ch, false);
|
||||
aCandidates.AppendElement(key);
|
||||
}
|
||||
// If unshiftedCharCodes doesn't have numeric but shiftedCharCode has it,
|
||||
// this keyboard layout is AZERTY or similar layout, probably.
|
||||
// In this case, Accel+[0-9] should be accessible without shift key.
|
||||
// However, the priority should be lowest.
|
||||
if (!HasASCIIDigit(aCandidates)) {
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
uint32_t ch =
|
||||
nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode;
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
nsShortcutCandidate key(ch, false);
|
||||
aCandidates.AppendElement(key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
uint32_t ch = nativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode;
|
||||
if (!ch)
|
||||
continue;
|
||||
|
||||
if (ch != nativeKeyEvent->charCode) {
|
||||
nsShortcutCandidate key(ch, false);
|
||||
aCandidates.AppendElement(key);
|
||||
}
|
||||
|
||||
// If the char is an alphabet, the shift key state should not be
|
||||
// ignored. E.g., Ctrl+Shift+C should not execute Ctrl+C.
|
||||
|
||||
// And checking the charCode is same as unshiftedCharCode too.
|
||||
// E.g., for Ctrl+Shift+(Plus of Numpad) should not run Ctrl+Plus.
|
||||
uint32_t unshiftCh =
|
||||
nativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode;
|
||||
if (CharsCaseInsensitiveEqual(ch, unshiftCh))
|
||||
continue;
|
||||
|
||||
// On the Hebrew keyboard layout on Windows, the unshifted char is a
|
||||
// localized character but the shifted char is a Latin alphabet,
|
||||
// then, we should not execute without the shift state. See bug 433192.
|
||||
if (IsCaseChangeableChar(ch))
|
||||
continue;
|
||||
|
||||
// Setting the alternative charCode candidates for retry without shift
|
||||
// key state only when the shift key is pressed.
|
||||
nsShortcutCandidate key(ch, true);
|
||||
aCandidates.AppendElement(key);
|
||||
}
|
||||
}
|
||||
|
||||
// Special case for "Space" key. With some keyboard layouts, "Space" with
|
||||
// or without Shift key causes non-ASCII space. For such keyboard layouts,
|
||||
// we should guarantee that the key press works as an ASCII white space key
|
||||
// press.
|
||||
if (nativeKeyEvent->mCodeNameIndex == CODE_NAME_INDEX_Space &&
|
||||
nativeKeyEvent->charCode != static_cast<uint32_t>(' ')) {
|
||||
nsShortcutCandidate spaceKey(static_cast<uint32_t>(' '), false);
|
||||
aCandidates.AppendElement(spaceKey);
|
||||
}
|
||||
} else {
|
||||
uint32_t charCode;
|
||||
aDOMKeyEvent->GetCharCode(&charCode);
|
||||
if (charCode) {
|
||||
nsShortcutCandidate key(charCode, false);
|
||||
aCandidates.AppendElement(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsContentUtils::GetAccessKeyCandidates(WidgetKeyboardEvent* aNativeKeyEvent,
|
||||
nsTArray<uint32_t>& aCandidates)
|
||||
{
|
||||
NS_PRECONDITION(aCandidates.IsEmpty(), "aCandidates must be empty");
|
||||
|
||||
// return the lower cased charCode candidates for access keys.
|
||||
// the priority of the charCodes are:
|
||||
// 0: charCode, 1: unshiftedCharCodes[0], 2: shiftedCharCodes[0]
|
||||
// 3: unshiftedCharCodes[1], 4: shiftedCharCodes[1],...
|
||||
if (aNativeKeyEvent->charCode) {
|
||||
uint32_t ch = aNativeKeyEvent->charCode;
|
||||
if (IS_IN_BMP(ch))
|
||||
ch = ToLowerCase(char16_t(ch));
|
||||
aCandidates.AppendElement(ch);
|
||||
}
|
||||
for (uint32_t i = 0;
|
||||
i < aNativeKeyEvent->alternativeCharCodes.Length(); ++i) {
|
||||
uint32_t ch[2] =
|
||||
{ aNativeKeyEvent->alternativeCharCodes[i].mUnshiftedCharCode,
|
||||
aNativeKeyEvent->alternativeCharCodes[i].mShiftedCharCode };
|
||||
for (uint32_t j = 0; j < 2; ++j) {
|
||||
if (!ch[j])
|
||||
continue;
|
||||
if (IS_IN_BMP(ch[j]))
|
||||
ch[j] = ToLowerCase(char16_t(ch[j]));
|
||||
// Don't append the charCode that was already appended.
|
||||
if (aCandidates.IndexOf(ch[j]) == aCandidates.NoIndex)
|
||||
aCandidates.AppendElement(ch[j]);
|
||||
}
|
||||
}
|
||||
// Special case for "Space" key. With some keyboard layouts, "Space" with
|
||||
// or without Shift key causes non-ASCII space. For such keyboard layouts,
|
||||
// we should guarantee that the key press works as an ASCII white space key
|
||||
// press.
|
||||
if (aNativeKeyEvent->mCodeNameIndex == CODE_NAME_INDEX_Space &&
|
||||
aNativeKeyEvent->charCode != static_cast<uint32_t>(' ')) {
|
||||
aCandidates.AppendElement(static_cast<uint32_t>(' '));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
nsContentUtils::AddScriptBlocker()
|
||||
@@ -5426,8 +5246,9 @@ nsContentUtils::GetDragSession()
|
||||
nsresult
|
||||
nsContentUtils::SetDataTransferInEvent(WidgetDragEvent* aDragEvent)
|
||||
{
|
||||
if (aDragEvent->dataTransfer || !aDragEvent->mFlags.mIsTrusted)
|
||||
if (aDragEvent->dataTransfer || !aDragEvent->IsTrusted()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// For draggesture and dragstart events, the data transfer object is
|
||||
// created before the event fires, so it should already be set. For other
|
||||
@@ -7951,7 +7772,7 @@ nsContentUtils::SendKeyEvent(nsIWidget* aWidget,
|
||||
}
|
||||
|
||||
if (aAdditionalFlags & nsIDOMWindowUtils::KEY_FLAG_PREVENT_DEFAULT) {
|
||||
event.mFlags.mDefaultPrevented = true;
|
||||
event.PreventDefaultBeforeDispatch();
|
||||
}
|
||||
|
||||
nsEventStatus status;
|
||||
|
||||
+11
-31
@@ -171,15 +171,6 @@ struct EventNameMapping
|
||||
mozilla::EventClassID mEventClassID;
|
||||
};
|
||||
|
||||
struct nsShortcutCandidate {
|
||||
nsShortcutCandidate(uint32_t aCharCode, bool aIgnoreShift) :
|
||||
mCharCode(aCharCode), mIgnoreShift(aIgnoreShift)
|
||||
{
|
||||
}
|
||||
uint32_t mCharCode;
|
||||
bool mIgnoreShift;
|
||||
};
|
||||
|
||||
typedef void (*CallOnRemoteChildFunction) (mozilla::dom::TabParent* aTabParent,
|
||||
void* aArg);
|
||||
|
||||
@@ -817,7 +808,15 @@ public:
|
||||
* @param [aColumnNumber=0] (Optional) Column number within resource
|
||||
containing error.
|
||||
If aURI is null, then aDocument->GetDocumentURI() is used.
|
||||
* @param [aLocationMode] (Optional) Specifies the behavior if
|
||||
error location information is omitted.
|
||||
*/
|
||||
enum MissingErrorLocationMode {
|
||||
// Don't show location information in the error console.
|
||||
eOMIT_LOCATION,
|
||||
// Get location information from the currently executing script.
|
||||
eUSE_CALLING_LOCATION
|
||||
};
|
||||
static nsresult ReportToConsoleNonLocalized(const nsAString& aErrorText,
|
||||
uint32_t aErrorFlags,
|
||||
const nsACString& aCategory,
|
||||
@@ -826,7 +825,9 @@ public:
|
||||
const nsAFlatString& aSourceLine
|
||||
= EmptyString(),
|
||||
uint32_t aLineNumber = 0,
|
||||
uint32_t aColumnNumber = 0);
|
||||
uint32_t aColumnNumber = 0,
|
||||
MissingErrorLocationMode aLocationMode
|
||||
= eUSE_CALLING_LOCATION);
|
||||
|
||||
/**
|
||||
* Report a localized error message to the error console.
|
||||
@@ -1501,27 +1502,6 @@ public:
|
||||
*/
|
||||
static const nsDependentString GetLocalizedEllipsis();
|
||||
|
||||
/**
|
||||
* Get the candidates for accelkeys for aDOMKeyEvent.
|
||||
*
|
||||
* @param aDOMKeyEvent [in] the key event for accelkey handling.
|
||||
* @param aCandidates [out] the candidate shortcut key combination list.
|
||||
* the first item is most preferred.
|
||||
*/
|
||||
static void GetAccelKeyCandidates(nsIDOMKeyEvent* aDOMKeyEvent,
|
||||
nsTArray<nsShortcutCandidate>& aCandidates);
|
||||
|
||||
/**
|
||||
* Get the candidates for accesskeys for aNativeKeyEvent.
|
||||
*
|
||||
* @param aNativeKeyEvent [in] the key event for accesskey handling.
|
||||
* @param aCandidates [out] the candidate access key list.
|
||||
* the first item is most preferred.
|
||||
*/
|
||||
static void GetAccessKeyCandidates(
|
||||
mozilla::WidgetKeyboardEvent* aNativeKeyEvent,
|
||||
nsTArray<uint32_t>& aCandidates);
|
||||
|
||||
/**
|
||||
* Hide any XUL popups associated with aDocument, including any documents
|
||||
* displayed in child frames. Does nothing if aDocument is null.
|
||||
|
||||
@@ -2573,8 +2573,8 @@ nsFrameLoader::DoSendAsyncMessage(JSContext* aCx,
|
||||
if (aCpows && (!mgr || !mgr->Wrap(aCx, aCpows, &cpows))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (tabParent->SendAsyncMessage(nsString(aMessage), data, cpows,
|
||||
IPC::Principal(aPrincipal))) {
|
||||
if (tabParent->SendAsyncMessage(nsString(aMessage), cpows,
|
||||
IPC::Principal(aPrincipal), data)) {
|
||||
return NS_OK;
|
||||
} else {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
@@ -2033,8 +2033,8 @@ public:
|
||||
if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (!cc->SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
|
||||
IPC::Principal(aPrincipal))) {
|
||||
if (!cc->SendAsyncMessage(PromiseFlatString(aMessage), cpows,
|
||||
IPC::Principal(aPrincipal), data)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
||||
@@ -306,6 +306,7 @@ GK_ATOM(directionality, "directionality")
|
||||
GK_ATOM(directory, "directory")
|
||||
GK_ATOM(disableOutputEscaping, "disable-output-escaping")
|
||||
GK_ATOM(disabled, "disabled")
|
||||
GK_ATOM(disableglobalhistory, "disableglobalhistory")
|
||||
GK_ATOM(disablehistory, "disablehistory")
|
||||
GK_ATOM(display, "display")
|
||||
GK_ATOM(displayMode, "display-mode")
|
||||
@@ -1039,6 +1040,7 @@ GK_ATOM(renderingobserverlist, "renderingobserverlist")
|
||||
GK_ATOM(repeat, "repeat")
|
||||
GK_ATOM(replace, "replace")
|
||||
GK_ATOM(required, "required")
|
||||
GK_ATOM(reserved, "reserved")
|
||||
GK_ATOM(reset, "reset")
|
||||
GK_ATOM(resizeafter, "resizeafter")
|
||||
GK_ATOM(resizebefore, "resizebefore")
|
||||
|
||||
@@ -3112,7 +3112,7 @@ nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
|
||||
sizeof(uint32_t));
|
||||
}
|
||||
} else if (msg == eResize && aVisitor.mEvent->mFlags.mIsTrusted) {
|
||||
} else if (msg == eResize && aVisitor.mEvent->IsTrusted()) {
|
||||
// QIing to window so that we can keep the old behavior also in case
|
||||
// a child window is handling resize.
|
||||
nsCOMPtr<nsPIDOMWindow> window =
|
||||
@@ -3120,10 +3120,10 @@ nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
if (window) {
|
||||
mIsHandlingResizeEvent = true;
|
||||
}
|
||||
} else if (msg == eMouseDown && aVisitor.mEvent->mFlags.mIsTrusted) {
|
||||
} else if (msg == eMouseDown && aVisitor.mEvent->IsTrusted()) {
|
||||
gMouseDown = true;
|
||||
} else if ((msg == eMouseUp || msg == eDragEnd) &&
|
||||
aVisitor.mEvent->mFlags.mIsTrusted) {
|
||||
aVisitor.mEvent->IsTrusted()) {
|
||||
gMouseDown = false;
|
||||
if (gDragServiceDisabled) {
|
||||
nsCOMPtr<nsIDragService> ds =
|
||||
@@ -3139,7 +3139,7 @@ nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
|
||||
// Handle 'active' event.
|
||||
if (!mIdleObservers.IsEmpty() &&
|
||||
aVisitor.mEvent->mFlags.mIsTrusted &&
|
||||
aVisitor.mEvent->IsTrusted() &&
|
||||
(aVisitor.mEvent->HasMouseEventMessage() ||
|
||||
aVisitor.mEvent->HasDragEventMessage())) {
|
||||
mAddActiveEventFuzzTime = false;
|
||||
@@ -3317,7 +3317,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
if (aVisitor.mEvent->mMessage == eResize) {
|
||||
mIsHandlingResizeEvent = false;
|
||||
} else if (aVisitor.mEvent->mMessage == eUnload &&
|
||||
aVisitor.mEvent->mFlags.mIsTrusted) {
|
||||
aVisitor.mEvent->IsTrusted()) {
|
||||
// Execute bindingdetached handlers before we tear ourselves
|
||||
// down.
|
||||
if (mDoc) {
|
||||
@@ -3325,7 +3325,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
}
|
||||
mIsDocumentLoaded = false;
|
||||
} else if (aVisitor.mEvent->mMessage == eLoad &&
|
||||
aVisitor.mEvent->mFlags.mIsTrusted) {
|
||||
aVisitor.mEvent->IsTrusted()) {
|
||||
// This is page load event since load events don't propagate to |window|.
|
||||
// @see nsDocument::PreHandleEvent.
|
||||
mIsDocumentLoaded = true;
|
||||
@@ -3338,7 +3338,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
// onload event for the frame element.
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetEvent event(aVisitor.mEvent->mFlags.mIsTrusted, eLoad);
|
||||
WidgetEvent event(aVisitor.mEvent->IsTrusted(), eLoad);
|
||||
event.mFlags.mBubbles = false;
|
||||
|
||||
// Most of the time we could get a pres context to pass in here,
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
|
||||
#include "imgINotificationObserver.idl"
|
||||
|
||||
%{C++
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "Visibility.h"
|
||||
%}
|
||||
|
||||
interface imgIRequest;
|
||||
interface nsIChannel;
|
||||
interface nsIStreamListener;
|
||||
@@ -12,6 +17,9 @@ interface nsIURI;
|
||||
interface nsIDocument;
|
||||
interface nsIFrame;
|
||||
|
||||
[ref] native MaybeOnNonvisible(const mozilla::Maybe<mozilla::OnNonvisible>);
|
||||
native Visibility(mozilla::Visibility);
|
||||
|
||||
/**
|
||||
* This interface represents a content node that loads images. The interface
|
||||
* exists to allow getting information on the images that the content node
|
||||
@@ -32,7 +40,7 @@ interface nsIFrame;
|
||||
* interface to mirror this interface when changing it.
|
||||
*/
|
||||
|
||||
[scriptable, builtinclass, uuid(770f7d84-c917-42d7-bf8d-d1b70649e733)]
|
||||
[scriptable, builtinclass, uuid(0357123d-9224-4d12-a47e-868c32689777)]
|
||||
interface nsIImageLoadingContent : imgINotificationObserver
|
||||
{
|
||||
/**
|
||||
@@ -169,18 +177,17 @@ interface nsIImageLoadingContent : imgINotificationObserver
|
||||
readonly attribute unsigned long naturalHeight;
|
||||
|
||||
/**
|
||||
* A visible count is stored, if it is non-zero then this image is considered
|
||||
* visible. These methods increment, decrement, or return the visible count.
|
||||
* Called by layout to announce when the frame associated with this content
|
||||
* has changed its visibility state.
|
||||
*
|
||||
* @param aNonvisibleAction What to do if the image's visibility count is now
|
||||
* zero. If ON_NONVISIBLE_NO_ACTION, nothing will be
|
||||
* done. If ON_NONVISIBLE_REQUEST_DISCARD, the image
|
||||
* will be asked to discard its surfaces if possible.
|
||||
* @param aNewVisibility The new visibility state.
|
||||
* @param aNonvisibleAction A requested action if the frame has become
|
||||
* nonvisible. If Nothing(), no action is
|
||||
* requested. If DISCARD_IMAGES is specified, the
|
||||
* frame is requested to ask any images it's
|
||||
* associated with to discard their surfaces if
|
||||
* possible.
|
||||
*/
|
||||
[noscript, notxpcom] void IncrementVisibleCount();
|
||||
[noscript, notxpcom] void DecrementVisibleCount(in uint32_t aNonvisibleAction);
|
||||
[noscript, notxpcom] uint32_t GetVisibleCount();
|
||||
|
||||
const long ON_NONVISIBLE_NO_ACTION = 0;
|
||||
const long ON_NONVISIBLE_REQUEST_DISCARD = 1;
|
||||
[noscript, notxpcom] void onVisibilityChange(in Visibility aNewVisibility,
|
||||
in MaybeOnNonvisible aNonvisibleAction);
|
||||
};
|
||||
|
||||
@@ -94,8 +94,7 @@ nsImageLoadingContent::nsImageLoadingContent()
|
||||
mStateChangerDepth(0),
|
||||
mCurrentRequestRegistered(false),
|
||||
mPendingRequestRegistered(false),
|
||||
mFrameCreateCalled(false),
|
||||
mVisibleCount(0)
|
||||
mFrameCreateCalled(false)
|
||||
{
|
||||
if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
|
||||
mLoadingEnabled = false;
|
||||
@@ -110,8 +109,8 @@ nsImageLoadingContent::DestroyImageLoadingContent()
|
||||
{
|
||||
// Cancel our requests so they won't hold stale refs to us
|
||||
// NB: Don't ask to discard the images here.
|
||||
ClearCurrentRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_NO_ACTION);
|
||||
ClearPendingRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_NO_ACTION);
|
||||
ClearCurrentRequest(NS_BINDING_ABORTED);
|
||||
ClearPendingRequest(NS_BINDING_ABORTED);
|
||||
}
|
||||
|
||||
nsImageLoadingContent::~nsImageLoadingContent()
|
||||
@@ -272,12 +271,7 @@ ImageIsAnimated(imgIRequest* aRequest)
|
||||
void
|
||||
nsImageLoadingContent::OnUnlockedDraw()
|
||||
{
|
||||
if (mVisibleCount > 0) {
|
||||
// We should already be marked as visible, there is nothing more we can do.
|
||||
return;
|
||||
}
|
||||
|
||||
// It's OK for non-animated images to wait until the next image visibility
|
||||
// It's OK for non-animated images to wait until the next frame visibility
|
||||
// update to become locked. (And that's preferable, since in the case of
|
||||
// scrolling it keeps memory usage minimal.) For animated images, though, we
|
||||
// want to mark them visible right away so we can call
|
||||
@@ -286,15 +280,27 @@ nsImageLoadingContent::OnUnlockedDraw()
|
||||
return;
|
||||
}
|
||||
|
||||
nsPresContext* presContext = GetFramePresContext();
|
||||
if (!presContext)
|
||||
nsIFrame* frame = GetOurPrimaryFrame();
|
||||
if (!frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (frame->GetVisibility() == Visibility::APPROXIMATELY_VISIBLE) {
|
||||
// This frame is already marked visible; there's nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
nsPresContext* presContext = frame->PresContext();
|
||||
if (!presContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIPresShell* presShell = presContext->PresShell();
|
||||
if (!presShell)
|
||||
if (!presShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
presShell->EnsureImageInVisibleList(this);
|
||||
presShell->EnsureFrameInApproximatelyVisibleList(frame);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@@ -478,11 +484,6 @@ nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
|
||||
|
||||
mFrameCreateCalled = true;
|
||||
|
||||
if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
|
||||
// Assume all images in popups are visible.
|
||||
IncrementVisibleCount();
|
||||
}
|
||||
|
||||
TrackImage(mCurrentRequest);
|
||||
TrackImage(mPendingRequest);
|
||||
|
||||
@@ -526,13 +527,7 @@ nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
|
||||
|
||||
nsIPresShell* presShell = presContext ? presContext->GetPresShell() : nullptr;
|
||||
if (presShell) {
|
||||
presShell->RemoveImageFromVisibleList(this);
|
||||
}
|
||||
|
||||
if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
|
||||
// We assume all images in popups are visible, so this decrement balances
|
||||
// out the increment in FrameCreated above.
|
||||
DecrementVisibleCount(ON_NONVISIBLE_NO_ACTION);
|
||||
presShell->RemoveFrameFromApproximatelyVisibleList(aFrame);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -746,34 +741,6 @@ nsImageLoadingContent::UnblockOnload(imgIRequest* aRequest)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsImageLoadingContent::IncrementVisibleCount()
|
||||
{
|
||||
mVisibleCount++;
|
||||
if (mVisibleCount == 1) {
|
||||
TrackImage(mCurrentRequest);
|
||||
TrackImage(mPendingRequest);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsImageLoadingContent::DecrementVisibleCount(uint32_t aNonvisibleAction)
|
||||
{
|
||||
NS_ASSERTION(mVisibleCount > 0, "visible count should be positive here");
|
||||
mVisibleCount--;
|
||||
|
||||
if (mVisibleCount == 0) {
|
||||
UntrackImage(mCurrentRequest, aNonvisibleAction);
|
||||
UntrackImage(mPendingRequest, aNonvisibleAction);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nsImageLoadingContent::GetVisibleCount()
|
||||
{
|
||||
return mVisibleCount;
|
||||
}
|
||||
|
||||
/*
|
||||
* Non-interface methods
|
||||
*/
|
||||
@@ -1080,8 +1047,8 @@ void
|
||||
nsImageLoadingContent::CancelImageRequests(bool aNotify)
|
||||
{
|
||||
AutoStateChanger changer(this, aNotify);
|
||||
ClearPendingRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD);
|
||||
ClearCurrentRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD);
|
||||
ClearPendingRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES));
|
||||
ClearCurrentRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES));
|
||||
}
|
||||
|
||||
nsresult
|
||||
@@ -1093,8 +1060,8 @@ nsImageLoadingContent::UseAsPrimaryRequest(imgRequestProxy* aRequest,
|
||||
AutoStateChanger changer(this, aNotify);
|
||||
|
||||
// Get rid if our existing images
|
||||
ClearPendingRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD);
|
||||
ClearCurrentRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD);
|
||||
ClearPendingRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES));
|
||||
ClearCurrentRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES));
|
||||
|
||||
// Clone the request we were given.
|
||||
RefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType);
|
||||
@@ -1221,7 +1188,9 @@ nsImageLoadingContent::SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision)
|
||||
// reason "image source changed". However, apparently there's some abuse
|
||||
// over in nsImageFrame where the displaying of the "broken" icon for the
|
||||
// next image depends on the cancel reason of the previous image. ugh.
|
||||
ClearPendingRequest(NS_ERROR_IMAGE_BLOCKED, ON_NONVISIBLE_REQUEST_DISCARD);
|
||||
// XXX(seth): So shouldn't we fix nsImageFrame?!
|
||||
ClearPendingRequest(NS_ERROR_IMAGE_BLOCKED,
|
||||
Some(OnNonvisible::DISCARD_IMAGES));
|
||||
|
||||
// For the blocked case, we only want to cancel the existing current request
|
||||
// if size is not available. bz says the web depends on this behavior.
|
||||
@@ -1229,7 +1198,8 @@ nsImageLoadingContent::SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision)
|
||||
|
||||
mImageBlockingStatus = aContentDecision;
|
||||
uint32_t keepFlags = mCurrentRequestFlags & REQUEST_IS_IMAGESET;
|
||||
ClearCurrentRequest(NS_ERROR_IMAGE_BLOCKED, ON_NONVISIBLE_REQUEST_DISCARD);
|
||||
ClearCurrentRequest(NS_ERROR_IMAGE_BLOCKED,
|
||||
Some(OnNonvisible::DISCARD_IMAGES));
|
||||
|
||||
// We still want to remember what URI we were and if it was an imageset,
|
||||
// despite not having an actual request. These are both cleared as part of
|
||||
@@ -1248,7 +1218,7 @@ nsImageLoadingContent::PrepareCurrentRequest(ImageLoadType aImageLoadType)
|
||||
|
||||
// Get rid of anything that was there previously.
|
||||
ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED,
|
||||
ON_NONVISIBLE_REQUEST_DISCARD);
|
||||
Some(OnNonvisible::DISCARD_IMAGES));
|
||||
|
||||
if (mNewRequestsWillNeedAnimationReset) {
|
||||
mCurrentRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET;
|
||||
@@ -1267,7 +1237,7 @@ nsImageLoadingContent::PreparePendingRequest(ImageLoadType aImageLoadType)
|
||||
{
|
||||
// Get rid of anything that was there previously.
|
||||
ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED,
|
||||
ON_NONVISIBLE_REQUEST_DISCARD);
|
||||
Some(OnNonvisible::DISCARD_IMAGES));
|
||||
|
||||
if (mNewRequestsWillNeedAnimationReset) {
|
||||
mPendingRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET;
|
||||
@@ -1332,7 +1302,7 @@ nsImageLoadingContent::MakePendingRequestCurrent()
|
||||
|
||||
void
|
||||
nsImageLoadingContent::ClearCurrentRequest(nsresult aReason,
|
||||
uint32_t aNonvisibleAction)
|
||||
const Maybe<OnNonvisible>& aNonvisibleAction)
|
||||
{
|
||||
if (!mCurrentRequest) {
|
||||
// Even if we didn't have a current request, we might have been keeping
|
||||
@@ -1358,7 +1328,7 @@ nsImageLoadingContent::ClearCurrentRequest(nsresult aReason,
|
||||
|
||||
void
|
||||
nsImageLoadingContent::ClearPendingRequest(nsresult aReason,
|
||||
uint32_t aNonvisibleAction)
|
||||
const Maybe<OnNonvisible>& aNonvisibleAction)
|
||||
{
|
||||
if (!mPendingRequest)
|
||||
return;
|
||||
@@ -1444,6 +1414,27 @@ nsImageLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
doc->UnblockOnload(false);
|
||||
}
|
||||
|
||||
void
|
||||
nsImageLoadingContent::OnVisibilityChange(Visibility aNewVisibility,
|
||||
const Maybe<OnNonvisible>& aNonvisibleAction)
|
||||
{
|
||||
switch (aNewVisibility) {
|
||||
case Visibility::APPROXIMATELY_VISIBLE:
|
||||
TrackImage(mCurrentRequest);
|
||||
TrackImage(mPendingRequest);
|
||||
break;
|
||||
|
||||
case Visibility::APPROXIMATELY_NONVISIBLE:
|
||||
UntrackImage(mCurrentRequest, aNonvisibleAction);
|
||||
UntrackImage(mPendingRequest, aNonvisibleAction);
|
||||
break;
|
||||
|
||||
case Visibility::UNTRACKED:
|
||||
MOZ_ASSERT_UNREACHABLE("Shouldn't notify for untracked visibility");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsImageLoadingContent::TrackImage(imgIRequest* aImage)
|
||||
{
|
||||
@@ -1454,32 +1445,34 @@ nsImageLoadingContent::TrackImage(imgIRequest* aImage)
|
||||
"Why haven't we heard of this request?");
|
||||
|
||||
nsIDocument* doc = GetOurCurrentDoc();
|
||||
if (doc && (mFrameCreateCalled || GetOurPrimaryFrame()) &&
|
||||
(mVisibleCount > 0)) {
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mVisibleCount == 1) {
|
||||
// Since we're becoming visible, request a decode.
|
||||
nsImageFrame* f = do_QueryFrame(GetOurPrimaryFrame());
|
||||
if (f) {
|
||||
f->MaybeDecodeForPredictedSize();
|
||||
}
|
||||
}
|
||||
// We only want to track this request if we're visible. Ordinarily we check
|
||||
// the visible count, but that requires a frame; in cases where
|
||||
// GetOurPrimaryFrame() cannot obtain a frame (e.g. <feImage>), we assume
|
||||
// we're visible if FrameCreated() was called.
|
||||
nsIFrame* frame = GetOurPrimaryFrame();
|
||||
if ((frame && frame->GetVisibility() == Visibility::APPROXIMATELY_NONVISIBLE) ||
|
||||
(!frame && !mFrameCreateCalled)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aImage == mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
|
||||
mCurrentRequestFlags |= REQUEST_IS_TRACKED;
|
||||
doc->AddImage(mCurrentRequest);
|
||||
}
|
||||
if (aImage == mPendingRequest && !(mPendingRequestFlags & REQUEST_IS_TRACKED)) {
|
||||
mPendingRequestFlags |= REQUEST_IS_TRACKED;
|
||||
doc->AddImage(mPendingRequest);
|
||||
}
|
||||
if (aImage == mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
|
||||
mCurrentRequestFlags |= REQUEST_IS_TRACKED;
|
||||
doc->AddImage(mCurrentRequest);
|
||||
}
|
||||
if (aImage == mPendingRequest && !(mPendingRequestFlags & REQUEST_IS_TRACKED)) {
|
||||
mPendingRequestFlags |= REQUEST_IS_TRACKED;
|
||||
doc->AddImage(mPendingRequest);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsImageLoadingContent::UntrackImage(imgIRequest* aImage,
|
||||
uint32_t aNonvisibleAction
|
||||
/* = ON_NONVISIBLE_NO_ACTION */)
|
||||
const Maybe<OnNonvisible>& aNonvisibleAction
|
||||
/* = Nothing() */)
|
||||
{
|
||||
if (!aImage)
|
||||
return;
|
||||
@@ -1496,10 +1489,10 @@ nsImageLoadingContent::UntrackImage(imgIRequest* aImage,
|
||||
if (doc && (mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
|
||||
mCurrentRequestFlags &= ~REQUEST_IS_TRACKED;
|
||||
doc->RemoveImage(mCurrentRequest,
|
||||
(aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD)
|
||||
aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)
|
||||
? nsIDocument::REQUEST_DISCARD
|
||||
: 0);
|
||||
} else if (aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD) {
|
||||
} else if (aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)) {
|
||||
// If we're not in the document we may still need to be discarded.
|
||||
aImage->RequestDiscard();
|
||||
}
|
||||
@@ -1508,10 +1501,10 @@ nsImageLoadingContent::UntrackImage(imgIRequest* aImage,
|
||||
if (doc && (mPendingRequestFlags & REQUEST_IS_TRACKED)) {
|
||||
mPendingRequestFlags &= ~REQUEST_IS_TRACKED;
|
||||
doc->RemoveImage(mPendingRequest,
|
||||
(aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD)
|
||||
aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)
|
||||
? nsIDocument::REQUEST_DISCARD
|
||||
: 0);
|
||||
} else if (aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD) {
|
||||
} else if (aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)) {
|
||||
// If we're not in the document we may still need to be discarded.
|
||||
aImage->RequestDiscard();
|
||||
}
|
||||
|
||||
@@ -41,6 +41,11 @@ class imgRequestProxy;
|
||||
class nsImageLoadingContent : public nsIImageLoadingContent,
|
||||
public imgIOnloadBlocker
|
||||
{
|
||||
template <typename T> using Maybe = mozilla::Maybe<T>;
|
||||
using Nothing = mozilla::Nothing;
|
||||
using OnNonvisible = mozilla::OnNonvisible;
|
||||
using Visibility = mozilla::Visibility;
|
||||
|
||||
/* METHODS */
|
||||
public:
|
||||
nsImageLoadingContent();
|
||||
@@ -326,8 +331,10 @@ protected:
|
||||
* @param aNonvisibleAction An action to take if the image is no longer
|
||||
* visible as a result; see |UntrackImage|.
|
||||
*/
|
||||
void ClearCurrentRequest(nsresult aReason, uint32_t aNonvisibleAction);
|
||||
void ClearPendingRequest(nsresult aReason, uint32_t aNonvisibleAction);
|
||||
void ClearCurrentRequest(nsresult aReason,
|
||||
const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
|
||||
void ClearPendingRequest(nsresult aReason,
|
||||
const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
|
||||
|
||||
/**
|
||||
* Retrieve a pointer to the 'registered with the refresh driver' flag for
|
||||
@@ -356,14 +363,16 @@ protected:
|
||||
*
|
||||
* No-op if aImage is null.
|
||||
*
|
||||
* @param aNonvisibleAction What to do if the image's visibility count is now
|
||||
* zero. If ON_NONVISIBLE_NO_ACTION, nothing will be
|
||||
* done. If ON_NONVISIBLE_REQUEST_DISCARD, the image
|
||||
* will be asked to discard its surfaces if possible.
|
||||
* @param aNonvisibleAction A requested action if the frame has become
|
||||
* nonvisible. If Nothing(), no action is
|
||||
* requested. If DISCARD_IMAGES is specified, the
|
||||
* frame is requested to ask any images it's
|
||||
* associated with to discard their surfaces if
|
||||
* possible.
|
||||
*/
|
||||
void TrackImage(imgIRequest* aImage);
|
||||
void UntrackImage(imgIRequest* aImage,
|
||||
uint32_t aNonvisibleAction = ON_NONVISIBLE_NO_ACTION);
|
||||
const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
|
||||
|
||||
/* MEMBERS */
|
||||
RefPtr<imgRequestProxy> mCurrentRequest;
|
||||
@@ -447,8 +456,6 @@ private:
|
||||
|
||||
// True when FrameCreate has been called but FrameDestroy has not.
|
||||
bool mFrameCreateCalled;
|
||||
|
||||
uint32_t mVisibleCount;
|
||||
};
|
||||
|
||||
#endif // nsImageLoadingContent_h__
|
||||
|
||||
@@ -1141,7 +1141,7 @@ PerformanceBase::CancelNotificationObservers()
|
||||
mPendingNotificationObserversTask = false;
|
||||
}
|
||||
|
||||
class NotifyObserversTask final : public nsCancelableRunnable
|
||||
class NotifyObserversTask final : public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit NotifyObserversTask(PerformanceBase* aPerformance)
|
||||
|
||||
@@ -61,15 +61,15 @@ function compare(a, b) {
|
||||
}
|
||||
|
||||
var clonableObjects = [
|
||||
{ crossThreads: true, data: 'hello world' },
|
||||
{ crossThreads: true, data: 123 },
|
||||
{ crossThreads: true, data: null },
|
||||
{ crossThreads: true, data: true },
|
||||
{ crossThreads: true, data: new Date() },
|
||||
{ crossThreads: true, data: [ 1, 'test', true, new Date() ] },
|
||||
{ crossThreads: true, data: { a: true, b: null, c: new Date(), d: [ true, false, {} ] } },
|
||||
{ crossThreads: true, data: new Blob([123], { type: 'plain/text' }) },
|
||||
{ crossThreads: true, data: new ImageData(2, 2) },
|
||||
'hello world',
|
||||
123,
|
||||
null,
|
||||
true,
|
||||
new Date(),
|
||||
[ 1, 'test', true, new Date() ],
|
||||
{ a: true, b: null, c: new Date(), d: [ true, false, {} ] },
|
||||
new Blob([123], { type: 'plain/text' }),
|
||||
new ImageData(2, 2),
|
||||
];
|
||||
|
||||
function create_fileList_forFile() {
|
||||
@@ -84,7 +84,7 @@ function create_fileList_forFile() {
|
||||
var domFile = fileList.files[0];
|
||||
is(domFile.name, "prefs.js", "fileName should be prefs.js");
|
||||
|
||||
clonableObjects.push({ crossThreads: true, data: fileList.files });
|
||||
clonableObjects.push(fileList.files);
|
||||
script.destroy();
|
||||
next();
|
||||
}
|
||||
@@ -105,7 +105,7 @@ function create_fileList_forDir() {
|
||||
is(fileList.files.length, 1, "Filelist has 1 element");
|
||||
ok(fileList.files[0] instanceof Directory, "We have a directory.");
|
||||
|
||||
clonableObjects.push({ crossThreads: false, data: fileList.files });
|
||||
clonableObjects.push(fileList.files);
|
||||
script.destroy();
|
||||
next();
|
||||
}
|
||||
@@ -114,6 +114,34 @@ function create_fileList_forDir() {
|
||||
script.sendAsyncMessage("dir.open");
|
||||
}
|
||||
|
||||
function create_directory() {
|
||||
if (navigator.userAgent.toLowerCase().indexOf('Android') != -1) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
|
||||
var script = SpecialPowers.loadChromeScript(url);
|
||||
|
||||
function onOpened(message) {
|
||||
var fileList = document.getElementById('fileList');
|
||||
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
|
||||
|
||||
fileList.getFilesAndDirectories().then(function(list) {
|
||||
// Just a simple test
|
||||
is(list.length, 1, "This list has 1 element");
|
||||
ok(list[0] instanceof Directory, "We have a directory.");
|
||||
|
||||
clonableObjects.push(list[0]);
|
||||
script.destroy();
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
script.addMessageListener("dir.opened", onOpened);
|
||||
script.sendAsyncMessage("dir.open");
|
||||
}
|
||||
|
||||
function runTests(obj) {
|
||||
ok(('clonableObjects' in obj) &&
|
||||
('transferableObjects' in obj) &&
|
||||
@@ -135,15 +163,8 @@ function runTests(obj) {
|
||||
|
||||
var object = clonableObjects[clonableObjectsId++];
|
||||
|
||||
// If this test requires a cross-thread structured clone algorithm, maybe
|
||||
// we have to skip it.
|
||||
if (!object.crossThread && obj.crossThread) {
|
||||
runClonableTest();
|
||||
return;
|
||||
}
|
||||
|
||||
obj.send(object.data, []).then(function(received) {
|
||||
compare(received.data, object.data);
|
||||
obj.send(object, []).then(function(received) {
|
||||
compare(received.data, object);
|
||||
runClonableTest();
|
||||
});
|
||||
}
|
||||
@@ -232,7 +253,6 @@ function test_windowToWindow() {
|
||||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: true,
|
||||
crossThread: false,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
resolve = r;
|
||||
@@ -286,7 +306,6 @@ function test_windowToIframeURL(url) {
|
||||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: true,
|
||||
crossThread: false,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
resolve = r;
|
||||
@@ -334,7 +353,6 @@ function test_workers() {
|
||||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: true,
|
||||
crossThread: true,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
resolve = r;
|
||||
@@ -378,7 +396,6 @@ function test_broadcastChannel() {
|
||||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: false,
|
||||
crossThread: true,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
if (ports.length) {
|
||||
@@ -424,7 +441,6 @@ function test_broadcastChannel_inWorkers() {
|
||||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: false,
|
||||
crossThread: true,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
if (ports.length) {
|
||||
@@ -466,7 +482,6 @@ function test_messagePort() {
|
||||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: true,
|
||||
crossThread: true,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
resolve = r;
|
||||
@@ -512,7 +527,6 @@ function test_messagePort_inWorkers() {
|
||||
runTests({
|
||||
clonableObjects: true,
|
||||
transferableObjects: true,
|
||||
crossThread: true,
|
||||
send: function(what, ports) {
|
||||
return new Promise(function(r, rr) {
|
||||
resolve = r;
|
||||
@@ -536,6 +550,7 @@ function test_messagePort_inWorkers() {
|
||||
var tests = [
|
||||
create_fileList_forFile,
|
||||
create_fileList_forDir,
|
||||
create_directory,
|
||||
|
||||
test_windowToWindow,
|
||||
test_windowToIframe,
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
"use strict";
|
||||
|
||||
function run_test() {
|
||||
test_base64URLEncode();
|
||||
test_base64URLDecode();
|
||||
}
|
||||
|
||||
// Test vectors from RFC 4648, section 10.
|
||||
let textTests = {
|
||||
"": "",
|
||||
"f": "Zg",
|
||||
"fo": "Zm8",
|
||||
"foo": "Zm9v",
|
||||
"foob": "Zm9vYg",
|
||||
"fooba": "Zm9vYmE",
|
||||
"foobar": "Zm9vYmFy",
|
||||
}
|
||||
|
||||
// Examples from RFC 4648, section 9.
|
||||
let binaryTests = [{
|
||||
decoded: new Uint8Array([0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e]),
|
||||
encoded: "FPucA9l-",
|
||||
}, {
|
||||
decoded: new Uint8Array([0x14, 0xfb, 0x9c, 0x03, 0xd9]),
|
||||
encoded: "FPucA9k",
|
||||
}, {
|
||||
decoded: new Uint8Array([0x14, 0xfb, 0x9c, 0x03]),
|
||||
encoded: "FPucAw",
|
||||
}];
|
||||
|
||||
function padEncodedValue(value) {
|
||||
switch (value.length % 4) {
|
||||
case 0:
|
||||
return value;
|
||||
case 2:
|
||||
return value + "==";
|
||||
case 3:
|
||||
return value + "=";
|
||||
default:
|
||||
throw new TypeError("Invalid encoded value");
|
||||
}
|
||||
}
|
||||
|
||||
function testEncode(input, encoded) {
|
||||
equal(ChromeUtils.base64URLEncode(input, { pad: false }),
|
||||
encoded, encoded + " without padding");
|
||||
equal(ChromeUtils.base64URLEncode(input, { pad: true }),
|
||||
padEncodedValue(encoded), encoded + " with padding");
|
||||
}
|
||||
|
||||
function test_base64URLEncode() {
|
||||
throws(_ => ChromeUtils.base64URLEncode(new Uint8Array(0)), /TypeError/,
|
||||
"Should require encoding options");
|
||||
throws(_ => ChromeUtils.base64URLEncode(new Uint8Array(0), {}), /TypeError/,
|
||||
"Encoding should require the padding option");
|
||||
|
||||
for (let {decoded, encoded} of binaryTests) {
|
||||
testEncode(decoded, encoded);
|
||||
}
|
||||
|
||||
let textEncoder = new TextEncoder("utf-8");
|
||||
for (let decoded of Object.keys(textTests)) {
|
||||
let input = textEncoder.encode(decoded);
|
||||
testEncode(input, textTests[decoded]);
|
||||
}
|
||||
}
|
||||
|
||||
function testDecode(input, decoded) {
|
||||
let buffer = ChromeUtils.base64URLDecode(input, { padding: "reject" });
|
||||
deepEqual(new Uint8Array(buffer), decoded, input + " with padding rejected");
|
||||
|
||||
let paddedValue = padEncodedValue(input);
|
||||
buffer = ChromeUtils.base64URLDecode(paddedValue, { padding: "ignore" });
|
||||
deepEqual(new Uint8Array(buffer), decoded, input + " with padding ignored");
|
||||
|
||||
if (paddedValue.length > input.length) {
|
||||
throws(_ => ChromeUtils.base64URLDecode(paddedValue, { padding: "reject" }),
|
||||
paddedValue + " with padding rejected should throw");
|
||||
|
||||
throws(_ => ChromeUtils.base64URLDecode(input, { padding: "require" }),
|
||||
input + " with padding required should throw");
|
||||
|
||||
buffer = ChromeUtils.base64URLDecode(paddedValue, { padding: "require" });
|
||||
deepEqual(new Uint8Array(buffer), decoded, paddedValue + " with padding required");
|
||||
}
|
||||
}
|
||||
|
||||
function test_base64URLDecode() {
|
||||
throws(_ => ChromeUtils.base64URLDecode(""), /TypeError/,
|
||||
"Should require decoding options");
|
||||
throws(_ => ChromeUtils.base64URLEncode("", {}), /TypeError/,
|
||||
"Decoding should require the padding option");
|
||||
|
||||
for (let {decoded, encoded} of binaryTests) {
|
||||
testDecode(encoded, decoded);
|
||||
}
|
||||
|
||||
let textEncoder = new TextEncoder("utf-8");
|
||||
for (let decoded of Object.keys(textTests)) {
|
||||
let expectedBuffer = textEncoder.encode(decoded);
|
||||
testDecode(textTests[decoded], expectedBuffer);
|
||||
}
|
||||
}
|
||||
@@ -32,3 +32,4 @@ skip-if = os == 'mac'
|
||||
[test_xhr_standalone.js]
|
||||
[test_xmlserializer.js]
|
||||
[test_cancelPrefetch.js]
|
||||
[test_chromeutils_base64.js]
|
||||
|
||||
@@ -952,25 +952,6 @@ DOMInterfaces = {
|
||||
'nativeType': 'mozilla::dom::workers::PushMessageData',
|
||||
},
|
||||
|
||||
'PushManager': [{
|
||||
'workers': False,
|
||||
'headerFile': 'mozilla/dom/PushManager.h',
|
||||
'nativeType': 'mozilla::dom::PushManager',
|
||||
}, {
|
||||
'workers': True,
|
||||
'headerFile': 'mozilla/dom/PushManager.h',
|
||||
'nativeType': 'mozilla::dom::WorkerPushManager',
|
||||
}],
|
||||
|
||||
'PushSubscription': [{
|
||||
'workers': False,
|
||||
'headerFile': 'mozilla/dom/PushManager.h',
|
||||
}, {
|
||||
'workers': True,
|
||||
'headerFile': 'mozilla/dom/PushManager.h',
|
||||
'nativeType': 'mozilla::dom::WorkerPushSubscription',
|
||||
}],
|
||||
|
||||
'Range': {
|
||||
'nativeType': 'nsRange',
|
||||
'binaryNames': {
|
||||
@@ -1014,6 +995,7 @@ DOMInterfaces = {
|
||||
'ServiceWorkerRegistration': [{
|
||||
'nativeType': 'mozilla::dom::ServiceWorkerRegistrationMainThread',
|
||||
'headerFile': 'mozilla/dom/ServiceWorkerRegistration.h',
|
||||
'implicitJSContext': [ 'pushManager' ],
|
||||
}, {
|
||||
'workers': True,
|
||||
'nativeType': 'mozilla::dom::ServiceWorkerRegistrationWorkerThread',
|
||||
|
||||
@@ -62,6 +62,7 @@ MSG_DEF(MSG_MISSING_REQUIRED_DICTIONARY_MEMBER, 1, JSEXN_TYPEERR, "Missing requi
|
||||
MSG_DEF(MSG_INVALID_REQUEST_METHOD, 1, JSEXN_TYPEERR, "Invalid request method {0}.")
|
||||
MSG_DEF(MSG_INVALID_REQUEST_MODE, 1, JSEXN_TYPEERR, "Invalid request mode {0}.")
|
||||
MSG_DEF(MSG_INVALID_REFERRER_URL, 1, JSEXN_TYPEERR, "Invalid referrer URL {0}.")
|
||||
MSG_DEF(MSG_CROSS_ORIGIN_REFERRER_URL, 2, JSEXN_TYPEERR, "Referrer URL {0} cannot be cross-origin to the entry settings object ({1}).")
|
||||
MSG_DEF(MSG_FETCH_BODY_CONSUMED_ERROR, 0, JSEXN_TYPEERR, "Body has already been consumed.")
|
||||
MSG_DEF(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR, 0, JSEXN_TYPEERR, "Response statusText may not contain newline or carriage return.")
|
||||
MSG_DEF(MSG_FETCH_FAILED, 0, JSEXN_TYPEERR, "NetworkError when attempting to fetch resource.")
|
||||
|
||||
Vendored
+2
-2
@@ -17,7 +17,7 @@ namespace dom {
|
||||
namespace cache {
|
||||
|
||||
class CachePushStreamChild::Callback final : public nsIInputStreamCallback
|
||||
, public nsCancelableRunnable
|
||||
, public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit Callback(CachePushStreamChild* aActor)
|
||||
@@ -89,7 +89,7 @@ private:
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(CachePushStreamChild::Callback,
|
||||
nsCancelableRunnable,
|
||||
CancelableRunnable,
|
||||
nsIInputStreamCallback);
|
||||
|
||||
CachePushStreamChild::CachePushStreamChild(Feature* aFeature,
|
||||
|
||||
Vendored
+1
@@ -119,6 +119,7 @@ IsTrusted(const PrincipalInfo& aPrincipalInfo, bool aTestingPrefEnabled)
|
||||
|
||||
nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
|
||||
if (scheme.LowerCaseEqualsLiteral("https") ||
|
||||
scheme.LowerCaseEqualsLiteral("app") ||
|
||||
scheme.LowerCaseEqualsLiteral("file")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -2158,7 +2158,7 @@ BindId(mozIStorageStatement* aState, const nsACString& aName, const nsID* aId)
|
||||
|
||||
char idBuf[NSID_LENGTH];
|
||||
aId->ToProvidedString(idBuf);
|
||||
rv = aState->BindUTF8StringByName(aName, nsAutoCString(idBuf));
|
||||
rv = aState->BindUTF8StringByName(aName, nsDependentCString(idBuf));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
||||
|
||||
return rv;
|
||||
|
||||
Vendored
+2
-2
@@ -117,7 +117,7 @@ private:
|
||||
// be done on the thread associated with the PBackground actor. Must be
|
||||
// cancelable to execute on Worker threads (which can occur when the
|
||||
// ReadStream is constructed on a child process Worker thread).
|
||||
class ReadStream::Inner::NoteClosedRunnable final : public nsCancelableRunnable
|
||||
class ReadStream::Inner::NoteClosedRunnable final : public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit NoteClosedRunnable(ReadStream::Inner* aStream)
|
||||
@@ -152,7 +152,7 @@ private:
|
||||
// it on the thread associated with the PBackground actor. Must be
|
||||
// cancelable to execute on Worker threads (which can occur when the
|
||||
// ReadStream is constructed on a child process Worker thread).
|
||||
class ReadStream::Inner::ForgetRunnable final : public nsCancelableRunnable
|
||||
class ReadStream::Inner::ForgetRunnable final : public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit ForgetRunnable(ReadStream::Inner* aStream)
|
||||
|
||||
Vendored
+2
-1
@@ -419,7 +419,8 @@ TypeUtils::ProcessURL(nsACString& aUrl, bool* aSchemeValidOut,
|
||||
if (aSchemeValidOut) {
|
||||
nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
|
||||
*aSchemeValidOut = scheme.LowerCaseEqualsLiteral("http") ||
|
||||
scheme.LowerCaseEqualsLiteral("https");
|
||||
scheme.LowerCaseEqualsLiteral("https") ||
|
||||
scheme.LowerCaseEqualsLiteral("app");
|
||||
}
|
||||
|
||||
uint32_t queryPos;
|
||||
|
||||
Vendored
+2
-1
@@ -89,7 +89,8 @@ function runTests(testFile, order) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
if (typeof order == "undefined") {
|
||||
order = "both"; // both by default
|
||||
order = "sequential"; // sequential by default, see bug 1143222.
|
||||
// TODO: Make this "both" again.
|
||||
}
|
||||
|
||||
ok(order == "parallel" || order == "sequential" || order == "both",
|
||||
|
||||
Vendored
-3
@@ -18,9 +18,6 @@ var sts = Cc['@mozilla.org/network/stream-transport-service;1']
|
||||
var hash = Cc['@mozilla.org/security/hash;1']
|
||||
.createInstance(Ci.nsICryptoHash);
|
||||
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
prefs.setBoolPref("dom.requestcache.enabled", true);
|
||||
|
||||
// Expose Cache and Fetch symbols on the global
|
||||
Cu.importGlobalProperties(['caches', 'fetch']);
|
||||
|
||||
|
||||
@@ -431,7 +431,9 @@ static bool
|
||||
IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature)
|
||||
{
|
||||
int32_t status;
|
||||
if (!NS_SUCCEEDED(gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, feature, &status)))
|
||||
nsCString discardFailureId;
|
||||
if (!NS_SUCCEEDED(gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, feature,
|
||||
discardFailureId, &status)))
|
||||
return false;
|
||||
|
||||
return status != nsIGfxInfo::FEATURE_STATUS_OK;
|
||||
@@ -442,28 +444,34 @@ HasAcceleratedLayers(const nsCOMPtr<nsIGfxInfo>& gfxInfo)
|
||||
{
|
||||
int32_t status;
|
||||
|
||||
nsCString discardFailureId;
|
||||
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
|
||||
nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS,
|
||||
discardFailureId,
|
||||
&status);
|
||||
if (status)
|
||||
return true;
|
||||
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
|
||||
nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS,
|
||||
discardFailureId,
|
||||
&status);
|
||||
if (status)
|
||||
return true;
|
||||
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
|
||||
nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS,
|
||||
discardFailureId,
|
||||
&status);
|
||||
if (status)
|
||||
return true;
|
||||
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
|
||||
nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS,
|
||||
discardFailureId,
|
||||
&status);
|
||||
if (status)
|
||||
return true;
|
||||
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
|
||||
nsIGfxInfo::FEATURE_OPENGL_LAYERS,
|
||||
discardFailureId,
|
||||
&status);
|
||||
if (status)
|
||||
return true;
|
||||
@@ -1527,7 +1535,7 @@ WebGLContext::RunContextLossTimer()
|
||||
mContextLossHandler->RunTimer();
|
||||
}
|
||||
|
||||
class UpdateContextLossStatusTask : public nsCancelableRunnable
|
||||
class UpdateContextLossStatusTask : public CancelableRunnable
|
||||
{
|
||||
RefPtr<WebGLContext> mWebGL;
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ private:
|
||||
nsCOMPtr<nsIEventTarget> mEventTarget;
|
||||
};
|
||||
|
||||
class ContextLossWorkerRunnable final : public nsCancelableRunnable
|
||||
class ContextLossWorkerRunnable final : public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit ContextLossWorkerRunnable(nsIRunnable* aRunnable)
|
||||
|
||||
@@ -57,7 +57,7 @@ if (NS_FAILED(rv)) { \
|
||||
return; \
|
||||
}
|
||||
|
||||
class WebCryptoTask : public nsCancelableRunnable,
|
||||
class WebCryptoTask : public CancelableRunnable,
|
||||
public nsNSSShutDownObject
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -30,7 +30,7 @@ AsyncEventDispatcher::AsyncEventDispatcher(EventTarget* aTarget,
|
||||
mEvent = do_QueryInterface(event);
|
||||
NS_ASSERTION(mEvent, "Should never fail to create an event");
|
||||
mEvent->DuplicatePrivateData();
|
||||
mEvent->SetTrusted(aEvent.mFlags.mIsTrusted);
|
||||
mEvent->SetTrusted(aEvent.IsTrusted());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
||||
@@ -24,8 +24,8 @@ namespace mozilla {
|
||||
* want to ensure that the event handler doesn't mutate the DOM at
|
||||
* the wrong time, in order to avoid resulting instability.
|
||||
*/
|
||||
|
||||
class AsyncEventDispatcher : public nsCancelableRunnable
|
||||
|
||||
class AsyncEventDispatcher : public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -95,7 +95,7 @@ public:
|
||||
mBlockedDoc->BlockOnload();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
~LoadBlockingAsyncEventDispatcher();
|
||||
|
||||
private:
|
||||
|
||||
+9
-20
@@ -466,22 +466,21 @@ Event::GetTimeStamp(uint64_t* aTimeStamp)
|
||||
NS_IMETHODIMP
|
||||
Event::StopPropagation()
|
||||
{
|
||||
mEvent->mFlags.mPropagationStopped = true;
|
||||
mEvent->StopPropagation();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Event::StopImmediatePropagation()
|
||||
{
|
||||
mEvent->mFlags.mPropagationStopped = true;
|
||||
mEvent->mFlags.mImmediatePropagationStopped = true;
|
||||
mEvent->StopImmediatePropagation();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Event::StopCrossProcessForwarding()
|
||||
{
|
||||
mEvent->mFlags.mNoCrossProcessBoundaryForwarding = true;
|
||||
mEvent->StopCrossProcessForwarding();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -520,17 +519,7 @@ Event::PreventDefaultInternal(bool aCalledByDefaultHandler)
|
||||
return;
|
||||
}
|
||||
|
||||
mEvent->mFlags.mDefaultPrevented = true;
|
||||
|
||||
// Note that even if preventDefault() has already been called by chrome,
|
||||
// a call of preventDefault() by content needs to overwrite
|
||||
// mDefaultPreventedByContent to true because in such case, defaultPrevented
|
||||
// must be true when web apps check it after they call preventDefault().
|
||||
if (!aCalledByDefaultHandler) {
|
||||
mEvent->mFlags.mDefaultPreventedByContent = true;
|
||||
} else {
|
||||
mEvent->mFlags.mDefaultPreventedByChrome = true;
|
||||
}
|
||||
mEvent->PreventDefault(aCalledByDefaultHandler);
|
||||
|
||||
if (!IsTrusted()) {
|
||||
return;
|
||||
@@ -763,7 +752,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
|
||||
}
|
||||
break;
|
||||
case eKeyboardEventClass:
|
||||
if (aEvent->mFlags.mIsTrusted) {
|
||||
if (aEvent->IsTrusted()) {
|
||||
uint32_t key = aEvent->AsKeyboardEvent()->keyCode;
|
||||
switch(aEvent->mMessage) {
|
||||
case eKeyPress:
|
||||
@@ -793,7 +782,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
|
||||
}
|
||||
break;
|
||||
case eTouchEventClass:
|
||||
if (aEvent->mFlags.mIsTrusted) {
|
||||
if (aEvent->IsTrusted()) {
|
||||
switch (aEvent->mMessage) {
|
||||
case eTouchStart:
|
||||
if (PopupAllowedForEvent("touchstart")) {
|
||||
@@ -811,7 +800,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
|
||||
}
|
||||
break;
|
||||
case eMouseEventClass:
|
||||
if (aEvent->mFlags.mIsTrusted &&
|
||||
if (aEvent->IsTrusted() &&
|
||||
aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
|
||||
switch(aEvent->mMessage) {
|
||||
case eMouseUp:
|
||||
@@ -1082,14 +1071,14 @@ Event::DefaultPrevented(JSContext* aCx) const
|
||||
NS_ENSURE_TRUE(mEvent, false);
|
||||
|
||||
// If preventDefault() has never been called, just return false.
|
||||
if (!mEvent->mFlags.mDefaultPrevented) {
|
||||
if (!mEvent->DefaultPrevented()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If preventDefault() has been called by content, return true. Otherwise,
|
||||
// i.e., preventDefault() has been called by chrome, return true only when
|
||||
// this is called by chrome.
|
||||
return mEvent->mFlags.mDefaultPreventedByContent || IsChrome(aCx);
|
||||
return mEvent->DefaultPreventedByContent() || IsChrome(aCx);
|
||||
}
|
||||
|
||||
double
|
||||
|
||||
+2
-2
@@ -186,7 +186,7 @@ public:
|
||||
|
||||
bool DefaultPrevented() const
|
||||
{
|
||||
return mEvent->mFlags.mDefaultPrevented;
|
||||
return mEvent->DefaultPrevented();
|
||||
}
|
||||
|
||||
bool MultipleActionsPrevented() const
|
||||
@@ -196,7 +196,7 @@ public:
|
||||
|
||||
bool IsTrusted() const
|
||||
{
|
||||
return mEvent->mFlags.mIsTrusted;
|
||||
return mEvent->IsTrusted();
|
||||
}
|
||||
|
||||
bool IsSynthesized() const
|
||||
|
||||
@@ -85,9 +85,46 @@ private:
|
||||
uint32_t mInitialCount;
|
||||
};
|
||||
|
||||
static bool IsEventTargetChrome(EventTarget* aEventTarget,
|
||||
nsIDocument** aDocument = nullptr)
|
||||
{
|
||||
if (aDocument) {
|
||||
*aDocument = nullptr;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!aEventTarget)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aEventTarget);
|
||||
if (!doc) {
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aEventTarget);
|
||||
if (node) {
|
||||
doc = node->OwnerDoc();
|
||||
} else {
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aEventTarget);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
doc = window->GetExtantDoc();
|
||||
}
|
||||
if (!doc) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool isChrome = nsContentUtils::IsChromeDoc(doc);
|
||||
if (aDocument) {
|
||||
doc.swap(*aDocument);
|
||||
}
|
||||
return isChrome;
|
||||
}
|
||||
|
||||
|
||||
#define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
|
||||
#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
|
||||
#define NS_TARGET_CHAIN_MAY_HAVE_MANAGER (1 << 2)
|
||||
#define NS_TARGET_CHAIN_CHECKED_IF_CHROME (1 << 3)
|
||||
#define NS_TARGET_CHAIN_IS_CHROME_CONTENT (1 << 4)
|
||||
|
||||
// EventTargetChainItem represents a single item in the event target chain.
|
||||
class EventTargetChainItem
|
||||
@@ -210,6 +247,11 @@ public:
|
||||
if (aVisitor.mEvent->mFlags.mPropagationStopped) {
|
||||
return;
|
||||
}
|
||||
if (aVisitor.mEvent->mFlags.mOnlySystemGroupDispatchInContent &&
|
||||
!aVisitor.mEvent->mFlags.mInSystemGroup &&
|
||||
!IsCurrentTargetChrome()) {
|
||||
return;
|
||||
}
|
||||
if (!mManager) {
|
||||
if (!MayHaveListenerManager() && !aCd.MayHaveNewListenerManager()) {
|
||||
return;
|
||||
@@ -233,6 +275,7 @@ public:
|
||||
*/
|
||||
void PostHandleEvent(EventChainPostVisitor& aVisitor);
|
||||
|
||||
private:
|
||||
nsCOMPtr<EventTarget> mTarget;
|
||||
uint16_t mFlags;
|
||||
uint16_t mItemFlags;
|
||||
@@ -241,6 +284,17 @@ public:
|
||||
nsCOMPtr<EventTarget> mNewTarget;
|
||||
// Cache mTarget's event listener manager.
|
||||
RefPtr<EventListenerManager> mManager;
|
||||
|
||||
bool IsCurrentTargetChrome()
|
||||
{
|
||||
if (!(mFlags & NS_TARGET_CHAIN_CHECKED_IF_CHROME)) {
|
||||
mFlags |= NS_TARGET_CHAIN_CHECKED_IF_CHROME;
|
||||
if (IsEventTargetChrome(mTarget)) {
|
||||
mFlags |= NS_TARGET_CHAIN_IS_CHROME_CONTENT;
|
||||
}
|
||||
}
|
||||
return !!(mFlags & NS_TARGET_CHAIN_IS_CHROME_CONTENT);
|
||||
}
|
||||
};
|
||||
|
||||
EventTargetChainItem::EventTargetChainItem(EventTarget* aTarget)
|
||||
@@ -468,18 +522,9 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
}
|
||||
|
||||
if (aEvent->mFlags.mOnlyChromeDispatch) {
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aTarget);
|
||||
if (!node) {
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aTarget);
|
||||
if (win) {
|
||||
node = win->GetExtantDoc();
|
||||
}
|
||||
}
|
||||
|
||||
NS_ENSURE_STATE(node);
|
||||
nsIDocument* doc = node->OwnerDoc();
|
||||
if (!nsContentUtils::IsChromeDoc(doc)) {
|
||||
nsPIDOMWindow* win = doc ? doc->GetInnerWindow() : nullptr;
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
if (!IsEventTargetChrome(target, getter_AddRefs(doc)) && doc) {
|
||||
nsPIDOMWindow* win = doc->GetInnerWindow();
|
||||
// If we can't dispatch the event to chrome, do nothing.
|
||||
EventTarget* piTarget = win ? win->GetParentTarget() : nullptr;
|
||||
if (!piTarget) {
|
||||
@@ -490,6 +535,8 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
|
||||
aEvent->target = target;
|
||||
// but use chrome event handler or TabChildGlobal for event target chain.
|
||||
target = piTarget;
|
||||
} else if (NS_WARN_IF(!doc)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1153,8 +1153,11 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
|
||||
nsEventStatus* aEventStatus)
|
||||
{
|
||||
//Set the value of the internal PreventDefault flag properly based on aEventStatus
|
||||
if (*aEventStatus == nsEventStatus_eConsumeNoDefault) {
|
||||
aEvent->mFlags.mDefaultPrevented = true;
|
||||
if (!aEvent->DefaultPrevented() &&
|
||||
*aEventStatus == nsEventStatus_eConsumeNoDefault) {
|
||||
// Assume that if only aEventStatus claims that the event has already been
|
||||
// consumed, the consumer is default event handler.
|
||||
aEvent->PreventDefault();
|
||||
}
|
||||
|
||||
nsAutoTObserverArray<Listener, 2>::EndLimitedIterator iter(mListeners);
|
||||
@@ -1174,8 +1177,7 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
|
||||
if (ListenerCanHandle(listener, aEvent)) {
|
||||
hasListener = true;
|
||||
if (listener->IsListening(aEvent) &&
|
||||
(aEvent->mFlags.mIsTrusted ||
|
||||
listener->mFlags.mAllowUntrustedEvents)) {
|
||||
(aEvent->IsTrusted() || listener->mFlags.mAllowUntrustedEvents)) {
|
||||
if (!*aDOMEvent) {
|
||||
// This is tiny bit slow, but happens only once per event.
|
||||
nsCOMPtr<EventTarget> et =
|
||||
@@ -1237,7 +1239,7 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
|
||||
mNoListenerForEventAtom = aEvent->userType;
|
||||
}
|
||||
|
||||
if (aEvent->mFlags.mDefaultPrevented) {
|
||||
if (aEvent->DefaultPrevented()) {
|
||||
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,7 +537,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
// Do not take account eMouseEnterIntoWidget/ExitFromWidget so that loading
|
||||
// a page when user is not active doesn't change the state to active.
|
||||
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
|
||||
if (aEvent->mFlags.mIsTrusted &&
|
||||
if (aEvent->IsTrusted() &&
|
||||
((mouseEvent && mouseEvent->IsReal() &&
|
||||
IsMessageMouseUserActivity(mouseEvent->mMessage)) ||
|
||||
aEvent->mClass == eWheelEventClass ||
|
||||
@@ -585,7 +585,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
#endif
|
||||
// Store last known screenPoint and clientPoint so pointer lock
|
||||
// can use these values as constants.
|
||||
if (aEvent->mFlags.mIsTrusted &&
|
||||
if (aEvent->IsTrusted() &&
|
||||
((mouseEvent && mouseEvent->IsReal()) ||
|
||||
aEvent->mClass == eWheelEventClass) &&
|
||||
!sIsPointerLocked) {
|
||||
@@ -651,7 +651,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
// from ESM::DispatchMouseOrPointerEvent (sending is permanent)).
|
||||
// Flag mNoCrossProcessBoundaryForwarding helps to
|
||||
// suppress sending accidental event from widget code.
|
||||
aEvent->mFlags.mNoCrossProcessBoundaryForwarding = true;
|
||||
aEvent->StopCrossProcessForwarding();
|
||||
break;
|
||||
case eMouseExitFromWidget:
|
||||
// If this is a remote frame, we receive eMouseExitFromWidget from the
|
||||
@@ -668,7 +668,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
|
||||
// Flag helps to suppress double event sending into process of content.
|
||||
// For more information see comment above, at eMouseEnterIntoWidget case.
|
||||
aEvent->mFlags.mNoCrossProcessBoundaryForwarding = true;
|
||||
aEvent->StopCrossProcessForwarding();
|
||||
|
||||
// If the event is not a top-level window exit, then it's not
|
||||
// really an exit --- we may have traversed widget boundaries but
|
||||
@@ -742,10 +742,10 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
(modifierMask == Prefs::ChromeAccessModifierMask() ||
|
||||
modifierMask == Prefs::ContentAccessModifierMask())) {
|
||||
AutoTArray<uint32_t, 10> accessCharCodes;
|
||||
nsContentUtils::GetAccessKeyCandidates(keyEvent, accessCharCodes);
|
||||
keyEvent->GetAccessKeyCandidates(accessCharCodes);
|
||||
|
||||
if (HandleAccessKey(aPresContext, accessCharCodes,
|
||||
keyEvent->mFlags.mIsTrusted, modifierMask)) {
|
||||
keyEvent->IsTrusted(), modifierMask)) {
|
||||
*aStatus = nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
}
|
||||
@@ -780,7 +780,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
case eWheelOperationStart:
|
||||
case eWheelOperationEnd:
|
||||
{
|
||||
NS_ASSERTION(aEvent->mFlags.mIsTrusted,
|
||||
NS_ASSERTION(aEvent->IsTrusted(),
|
||||
"Untrusted wheel event shouldn't be here");
|
||||
|
||||
nsIContent* content = GetFocusedContent();
|
||||
@@ -825,7 +825,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
|
||||
break;
|
||||
case eCompositionStart:
|
||||
if (aEvent->mFlags.mIsTrusted) {
|
||||
if (aEvent->IsTrusted()) {
|
||||
// If the event is trusted event, set the selected text to data of
|
||||
// composition event.
|
||||
WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
|
||||
@@ -1382,7 +1382,7 @@ EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
|
||||
nsIFrame* inDownFrame,
|
||||
WidgetGUIEvent* inMouseDownEvent)
|
||||
{
|
||||
if (!inMouseDownEvent->mFlags.mIsTrusted ||
|
||||
if (!inMouseDownEvent->IsTrusted() ||
|
||||
IsRemoteTarget(mGestureDownContent) ||
|
||||
sIsPointerLocked) {
|
||||
return;
|
||||
@@ -1740,11 +1740,10 @@ EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
|
||||
nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
|
||||
|
||||
// get the widget from the target frame
|
||||
WidgetDragEvent startEvent(aEvent->mFlags.mIsTrusted,
|
||||
eDragStart, widget);
|
||||
WidgetDragEvent startEvent(aEvent->IsTrusted(), eDragStart, widget);
|
||||
FillInEventFromGestureDown(&startEvent);
|
||||
|
||||
WidgetDragEvent gestureEvent(aEvent->mFlags.mIsTrusted,
|
||||
WidgetDragEvent gestureEvent(aEvent->IsTrusted(),
|
||||
eLegacyDragGesture, widget);
|
||||
FillInEventFromGestureDown(&gestureEvent);
|
||||
|
||||
@@ -1800,7 +1799,7 @@ EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
|
||||
targetContent, selection);
|
||||
if (dragStarted) {
|
||||
sActiveESM = nullptr;
|
||||
aEvent->mFlags.mPropagationStopped = true;
|
||||
aEvent->StopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2232,7 +2231,7 @@ EventStateManager::DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
|
||||
nsWeakFrame targetFrame(aTargetFrame);
|
||||
|
||||
MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault &&
|
||||
!aEvent->mFlags.mDefaultPrevented,
|
||||
!aEvent->DefaultPrevented(),
|
||||
"If you make legacy events dispatched for default prevented wheel "
|
||||
"event, you need to initialize stateX and stateY");
|
||||
EventState stateX, stateY;
|
||||
@@ -2272,11 +2271,14 @@ EventStateManager::DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
|
||||
}
|
||||
}
|
||||
|
||||
if (stateY.mDefaultPrevented || stateX.mDefaultPrevented) {
|
||||
if (stateY.mDefaultPrevented) {
|
||||
*aStatus = nsEventStatus_eConsumeNoDefault;
|
||||
aEvent->mFlags.mDefaultPrevented = true;
|
||||
aEvent->mFlags.mDefaultPreventedByContent |=
|
||||
stateY.mDefaultPreventedByContent || stateX.mDefaultPreventedByContent;
|
||||
aEvent->PreventDefault(!stateY.mDefaultPreventedByContent);
|
||||
}
|
||||
|
||||
if (stateX.mDefaultPrevented) {
|
||||
*aStatus = nsEventStatus_eConsumeNoDefault;
|
||||
aEvent->PreventDefault(!stateX.mDefaultPreventedByContent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2297,7 +2299,7 @@ EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
|
||||
targetContent = targetContent->GetParent();
|
||||
}
|
||||
|
||||
WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted,
|
||||
WidgetMouseScrollEvent event(aEvent->IsTrusted(),
|
||||
eLegacyMouseLineOrPageScroll, aEvent->widget);
|
||||
event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
|
||||
event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
|
||||
@@ -2315,8 +2317,8 @@ EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
|
||||
EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
|
||||
&event, nullptr, &status);
|
||||
aState.mDefaultPrevented =
|
||||
event.mFlags.mDefaultPrevented || status == nsEventStatus_eConsumeNoDefault;
|
||||
aState.mDefaultPreventedByContent = event.mFlags.mDefaultPreventedByContent;
|
||||
event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
|
||||
aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2337,7 +2339,7 @@ EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
|
||||
targetContent = targetContent->GetParent();
|
||||
}
|
||||
|
||||
WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted,
|
||||
WidgetMouseScrollEvent event(aEvent->IsTrusted(),
|
||||
eLegacyMousePixelScroll, aEvent->widget);
|
||||
event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
|
||||
event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
|
||||
@@ -2355,8 +2357,8 @@ EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
|
||||
EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
|
||||
&event, nullptr, &status);
|
||||
aState.mDefaultPrevented =
|
||||
event.mFlags.mDefaultPrevented || status == nsEventStatus_eConsumeNoDefault;
|
||||
aState.mDefaultPreventedByContent = event.mFlags.mDefaultPreventedByContent;
|
||||
event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
|
||||
aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
@@ -3133,7 +3135,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||
break;
|
||||
case eWheelOperationEnd:
|
||||
{
|
||||
MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
|
||||
MOZ_ASSERT(aEvent->IsTrusted());
|
||||
ScrollbarsForWheel::MayInactivate();
|
||||
WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
|
||||
nsIScrollableFrame* scrollTarget =
|
||||
@@ -3147,7 +3149,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||
case eWheel:
|
||||
case eWheelOperationStart:
|
||||
{
|
||||
MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
|
||||
MOZ_ASSERT(aEvent->IsTrusted());
|
||||
|
||||
if (*aStatus == nsEventStatus_eConsumeNoDefault) {
|
||||
ScrollbarsForWheel::Inactivate();
|
||||
@@ -3180,7 +3182,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||
// APZ to handle it, because it will track the velocity and predicted
|
||||
// destination from the momentum.
|
||||
if (wheelEvent->mFlags.mHandledByAPZ) {
|
||||
wheelEvent->mFlags.mDefaultPrevented = true;
|
||||
wheelEvent->PreventDefault();
|
||||
}
|
||||
action = WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
|
||||
} else if (wheelEvent->mFlags.mHandledByAPZ) {
|
||||
@@ -3426,8 +3428,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||
getter_AddRefs(targetContent));
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
|
||||
WidgetDragEvent event(aEvent->mFlags.mIsTrusted,
|
||||
eLegacyDragDrop, widget);
|
||||
WidgetDragEvent event(aEvent->IsTrusted(), eLegacyDragDrop, widget);
|
||||
|
||||
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
|
||||
event.refPoint = mouseEvent->refPoint;
|
||||
@@ -3853,7 +3854,7 @@ CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent,
|
||||
|
||||
nsAutoPtr<WidgetPointerEvent> newPointerEvent;
|
||||
newPointerEvent =
|
||||
new WidgetPointerEvent(aMouseEvent->mFlags.mIsTrusted, aMessage,
|
||||
new WidgetPointerEvent(aMouseEvent->IsTrusted(), aMessage,
|
||||
aMouseEvent->widget);
|
||||
newPointerEvent->isPrimary = sourcePointer->isPrimary;
|
||||
newPointerEvent->pointerId = sourcePointer->pointerId;
|
||||
@@ -3867,7 +3868,7 @@ CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent,
|
||||
aNewEvent = newPointerEvent.forget();
|
||||
} else {
|
||||
aNewEvent =
|
||||
new WidgetMouseEvent(aMouseEvent->mFlags.mIsTrusted, aMessage,
|
||||
new WidgetMouseEvent(aMouseEvent->IsTrusted(), aMessage,
|
||||
aMouseEvent->widget, WidgetMouseEvent::eReal);
|
||||
aNewEvent->relatedTarget = aRelatedContent;
|
||||
}
|
||||
@@ -4263,7 +4264,7 @@ EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent)
|
||||
} else if (aMouseEvent->refPoint == sSynthCenteringPoint) {
|
||||
// This is the "synthetic native" event we dispatched to re-center the
|
||||
// pointer. Cancel it so we don't expose the centering move to content.
|
||||
aMouseEvent->mFlags.mPropagationStopped = true;
|
||||
aMouseEvent->StopPropagation();
|
||||
// Clear sSynthCenteringPoint so we don't cancel other events
|
||||
// targeted at the center.
|
||||
sSynthCenteringPoint = kInvalidRefPoint;
|
||||
@@ -4509,8 +4510,7 @@ EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
|
||||
nsWeakFrame& aTargetFrame)
|
||||
{
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetDragEvent event(aDragEvent->mFlags.mIsTrusted, aMessage,
|
||||
aDragEvent->widget);
|
||||
WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->widget);
|
||||
event.refPoint = aDragEvent->refPoint;
|
||||
event.modifiers = aDragEvent->modifiers;
|
||||
event.buttons = aDragEvent->buttons;
|
||||
@@ -4654,7 +4654,7 @@ EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
|
||||
nsWeakFrame aCurrentTarget,
|
||||
bool aNoContentDispatch)
|
||||
{
|
||||
WidgetMouseEvent event(aEvent->mFlags.mIsTrusted, aMessage,
|
||||
WidgetMouseEvent event(aEvent->IsTrusted(), aMessage,
|
||||
aEvent->widget, WidgetMouseEvent::eReal);
|
||||
|
||||
event.refPoint = aEvent->refPoint;
|
||||
@@ -5918,7 +5918,7 @@ AutoHandlingUserInputStatePusher::AutoHandlingUserInputStatePusher(
|
||||
nsIPresShell::SetCapturingContent(nullptr, 0);
|
||||
nsIPresShell::AllowMouseCapture(true);
|
||||
}
|
||||
if (!aDocument || !aEvent || !aEvent->mFlags.mIsTrusted) {
|
||||
if (!aDocument || !aEvent || !aEvent->IsTrusted()) {
|
||||
return;
|
||||
}
|
||||
mResetFMMouseButtonHandlingState =
|
||||
|
||||
@@ -755,8 +755,8 @@ IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext,
|
||||
if (!mUpdatePreference.WantMouseButtonEventOnChar()) {
|
||||
return false;
|
||||
}
|
||||
if (!aMouseEvent->mFlags.mIsTrusted ||
|
||||
aMouseEvent->mFlags.mDefaultPrevented ||
|
||||
if (!aMouseEvent->IsTrusted() ||
|
||||
aMouseEvent->DefaultPrevented() ||
|
||||
!aMouseEvent->widget) {
|
||||
return false;
|
||||
}
|
||||
@@ -822,7 +822,9 @@ IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext,
|
||||
}
|
||||
|
||||
bool consumed = (rv == NS_SUCCESS_EVENT_CONSUMED);
|
||||
aMouseEvent->mFlags.mDefaultPrevented = consumed;
|
||||
if (consumed) {
|
||||
aMouseEvent->PreventDefault();
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
|
||||
@@ -1164,7 +1164,7 @@ IMEStateManager::DispatchCompositionEvent(
|
||||
GetBoolName(aCompositionEvent->mFlags.mPropagationStopped),
|
||||
GetBoolName(aIsSynthesized), tabParent.get()));
|
||||
|
||||
if (!aCompositionEvent->mFlags.mIsTrusted ||
|
||||
if (!aCompositionEvent->IsTrusted() ||
|
||||
aCompositionEvent->mFlags.mPropagationStopped) {
|
||||
return;
|
||||
}
|
||||
@@ -1261,7 +1261,7 @@ IMEStateManager::HandleSelectionEvent(nsPresContext* aPresContext,
|
||||
GetBoolName(aSelectionEvent->mFlags.mIsTrusted),
|
||||
tabParent.get()));
|
||||
|
||||
if (!aSelectionEvent->mFlags.mIsTrusted) {
|
||||
if (!aSelectionEvent->IsTrusted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1303,7 +1303,7 @@ IMEStateManager::OnCompositionEventDiscarded(
|
||||
GetBoolName(aCompositionEvent->widget->Destroyed()),
|
||||
GetBoolName(aCompositionEvent->mFlags.mIsTrusted)));
|
||||
|
||||
if (!aCompositionEvent->mFlags.mIsTrusted) {
|
||||
if (!aCompositionEvent->IsTrusted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ TextComposition::CloneAndDispatchAs(
|
||||
MOZ_ASSERT(IsValidStateForComposition(aCompositionEvent->widget),
|
||||
"Should be called only when it's safe to dispatch an event");
|
||||
|
||||
WidgetCompositionEvent compositionEvent(aCompositionEvent->mFlags.mIsTrusted,
|
||||
WidgetCompositionEvent compositionEvent(aCompositionEvent->IsTrusted(),
|
||||
aMessage, aCompositionEvent->widget);
|
||||
compositionEvent.time = aCompositionEvent->time;
|
||||
compositionEvent.timeStamp = aCompositionEvent->timeStamp;
|
||||
@@ -159,7 +159,7 @@ TextComposition::OnCompositionEventDiscarded(
|
||||
// Note that this method is never called for synthesized events for emulating
|
||||
// commit or cancel composition.
|
||||
|
||||
MOZ_ASSERT(aCompositionEvent->mFlags.mIsTrusted,
|
||||
MOZ_ASSERT(aCompositionEvent->IsTrusted(),
|
||||
"Shouldn't be called with untrusted event");
|
||||
|
||||
if (mTabParent) {
|
||||
@@ -243,7 +243,7 @@ TextComposition::DispatchCompositionEvent(
|
||||
// remote process.
|
||||
if (mTabParent) {
|
||||
Unused << mTabParent->SendCompositionEvent(*aCompositionEvent);
|
||||
aCompositionEvent->mFlags.mPropagationStopped = true;
|
||||
aCompositionEvent->StopPropagation();
|
||||
if (aCompositionEvent->CausesDOMTextEvent()) {
|
||||
mLastData = aCompositionEvent->mData;
|
||||
mLastRanges = aCompositionEvent->mRanges;
|
||||
@@ -411,7 +411,7 @@ TextComposition::HandleSelectionEvent(nsPresContext* aPresContext,
|
||||
// remote process.
|
||||
if (aTabParent) {
|
||||
Unused << aTabParent->SendSelectionEvent(*aSelectionEvent);
|
||||
aSelectionEvent->mFlags.mPropagationStopped = true;
|
||||
aSelectionEvent->StopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+6
-21
@@ -64,25 +64,6 @@ Request::RequestContextEnabled(JSContext* aCx, JSObject* aObj)
|
||||
return workerPrivate->RequestContextEnabled();
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
Request::RequestCacheEnabled(JSContext* aCx, JSObject* aObj)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
return Preferences::GetBool("dom.requestcache.enabled", false);
|
||||
}
|
||||
|
||||
using namespace workers;
|
||||
|
||||
// Otherwise, check the pref via the WorkerPrivate
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||
if (!workerPrivate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return workerPrivate->RequestCacheEnabled();
|
||||
}
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
Request::GetInternalRequest()
|
||||
{
|
||||
@@ -384,7 +365,10 @@ Request::Constructor(const GlobalObject& aGlobal,
|
||||
nsresult rv = principal->CheckMayLoad(uri, /* report */ false,
|
||||
/* allowIfInheritsPrincipal */ false);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
|
||||
nsAutoCString globalOrigin;
|
||||
principal->GetOrigin(globalOrigin);
|
||||
aRv.ThrowTypeError<MSG_CROSS_ORIGIN_REFERRER_URL>(referrer,
|
||||
NS_ConvertUTF8toUTF16(globalOrigin));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -412,7 +396,8 @@ Request::Constructor(const GlobalObject& aGlobal,
|
||||
new ReferrerSameOriginChecker(worker, referrerURL, rv);
|
||||
checker->Dispatch(aRv);
|
||||
if (aRv.Failed() || NS_FAILED(rv)) {
|
||||
aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
|
||||
aRv.ThrowTypeError<MSG_CROSS_ORIGIN_REFERRER_URL>(referrer,
|
||||
worker->GetLocationInfo().mOrigin);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,6 @@ public:
|
||||
|
||||
static bool
|
||||
RequestContextEnabled(JSContext* aCx, JSObject* aObj);
|
||||
static bool
|
||||
RequestCacheEnabled(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
|
||||
|
||||
@@ -9,23 +9,32 @@
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/PFileSystemParams.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace ipc;
|
||||
|
||||
namespace dom {
|
||||
|
||||
/* static */ already_AddRefed<CreateDirectoryTask>
|
||||
CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
ErrorResult& aRv)
|
||||
/**
|
||||
* CreateDirectoryTaskChild
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<CreateDirectoryTaskChild>
|
||||
CreateDirectoryTaskChild::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateDirectoryTask> task =
|
||||
new CreateDirectoryTask(aFileSystem, aTargetPath);
|
||||
RefPtr<CreateDirectoryTaskChild> task =
|
||||
new CreateDirectoryTaskChild(aFileSystem, aTargetPath);
|
||||
|
||||
// aTargetPath can be null. In this case SetError will be called.
|
||||
|
||||
@@ -44,63 +53,30 @@ CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<CreateDirectoryTask>
|
||||
CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateDirectoryTask> task =
|
||||
new CreateDirectoryTask(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
CreateDirectoryTaskChild::CreateDirectoryTaskChild(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath)
|
||||
: FileSystemTaskChildBase(aFileSystem)
|
||||
, mTargetPath(aTargetPath)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
CreateDirectoryTaskChild::~CreateDirectoryTaskChild()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
CreateDirectoryTask::~CreateDirectoryTask()
|
||||
{
|
||||
MOZ_ASSERT(!mPromise || NS_IsMainThread(),
|
||||
"mPromise should be released on main thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
CreateDirectoryTask::GetPromise()
|
||||
CreateDirectoryTaskChild::GetPromise()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return RefPtr<Promise>(mPromise).forget();
|
||||
}
|
||||
|
||||
FileSystemParams
|
||||
CreateDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
CreateDirectoryTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
@@ -113,11 +89,92 @@ CreateDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
return FileSystemCreateDirectoryParams(aSerializedDOMPath, path);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
CreateDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
void
|
||||
CreateDirectoryTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
const FileSystemDirectoryResponse& r =
|
||||
aValue.get_FileSystemDirectoryResponse();
|
||||
|
||||
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(r.realPath()), true,
|
||||
getter_AddRefs(mTargetPath));
|
||||
NS_WARN_IF(aRv.Failed());
|
||||
}
|
||||
|
||||
void
|
||||
CreateDirectoryTaskChild::HandlerCallback()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
|
||||
mTargetPath,
|
||||
Directory::eNotDOMRootDirectory,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(dir);
|
||||
|
||||
mPromise->MaybeResolve(dir);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CreateDirectoryTaskChild::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(CREATE_DIRECTORY_TASK_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* CreateDirectoryTaskParent
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<CreateDirectoryTaskParent>
|
||||
CreateDirectoryTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateDirectoryTaskParent> task =
|
||||
new CreateDirectoryTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(aParam.realPath()), true,
|
||||
getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
CreateDirectoryTaskParent::CreateDirectoryTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
CreateDirectoryTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
@@ -127,20 +184,8 @@ CreateDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
return FileSystemDirectoryResponse(path);
|
||||
}
|
||||
|
||||
void
|
||||
CreateDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemDirectoryResponse r = aValue;
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(r.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
|
||||
NS_WARN_IF(aRv.Failed());
|
||||
}
|
||||
|
||||
nsresult
|
||||
CreateDirectoryTask::Work()
|
||||
CreateDirectoryTaskParent::IOWork()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
@@ -169,33 +214,9 @@ CreateDirectoryTask::Work()
|
||||
}
|
||||
|
||||
void
|
||||
CreateDirectoryTask::HandlerCallback()
|
||||
CreateDirectoryTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
|
||||
mTargetPath,
|
||||
Directory::eNotDOMRootDirectory,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(dir);
|
||||
|
||||
mPromise->MaybeResolve(dir);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CreateDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral("create");
|
||||
aAccess.AssignLiteral(CREATE_DIRECTORY_TASK_PERMISSION);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -11,27 +11,24 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
#define CREATE_DIRECTORY_TASK_PERMISSION "create"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class FileSystemCreateDirectoryParams;
|
||||
class Promise;
|
||||
|
||||
class CreateDirectoryTask final : public FileSystemTaskBase
|
||||
class CreateDirectoryTaskChild final : public FileSystemTaskChildBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<CreateDirectoryTask>
|
||||
static already_AddRefed<CreateDirectoryTaskChild>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<CreateDirectoryTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~CreateDirectoryTask();
|
||||
~CreateDirectoryTaskChild();
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetPromise();
|
||||
@@ -39,36 +36,54 @@ public:
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
protected:
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
||||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
private:
|
||||
CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath);
|
||||
|
||||
CreateDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
CreateDirectoryTaskChild(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath);
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
};
|
||||
|
||||
class CreateDirectoryTaskParent final : public FileSystemTaskParentBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<CreateDirectoryTaskParent>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
protected:
|
||||
virtual nsresult
|
||||
IOWork() override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
private:
|
||||
CreateDirectoryTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
+170
-152
@@ -5,6 +5,8 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "CreateFileTask.h"
|
||||
#include "CreateDirectoryTask.h"
|
||||
#include "RemoveTask.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -12,46 +14,49 @@
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/PFileSystemParams.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
#define GET_PERMISSION_ACCESS_TYPE(aAccess) \
|
||||
if (mReplace) { \
|
||||
aAccess.AssignLiteral(REMOVE_TASK_PERMISSION); \
|
||||
return; \
|
||||
} \
|
||||
aAccess.AssignLiteral(CREATE_DIRECTORY_TASK_PERMISSION);
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
uint32_t CreateFileTask::sOutputBufferSize = 0;
|
||||
/**
|
||||
*CreateFileTaskChild
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<CreateFileTask>
|
||||
CreateFileTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Blob* aBlobData,
|
||||
InfallibleTArray<uint8_t>& aArrayData,
|
||||
bool aReplace,
|
||||
ErrorResult& aRv)
|
||||
/* static */ already_AddRefed<CreateFileTaskChild>
|
||||
CreateFileTaskChild::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Blob* aBlobData,
|
||||
InfallibleTArray<uint8_t>& aArrayData,
|
||||
bool aReplace,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateFileTask> task =
|
||||
new CreateFileTask(aFileSystem, aTargetPath, aReplace);
|
||||
RefPtr<CreateFileTaskChild> task =
|
||||
new CreateFileTaskChild(aFileSystem, aTargetPath, aReplace);
|
||||
|
||||
// aTargetPath can be null. In this case SetError will be called.
|
||||
|
||||
task->GetOutputBufferSize();
|
||||
|
||||
if (aBlobData) {
|
||||
if (XRE_IsParentProcess()) {
|
||||
aBlobData->GetInternalStream(getter_AddRefs(task->mBlobStream), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
task->mBlobData = aBlobData;
|
||||
}
|
||||
task->mBlobImpl = aBlobData->Impl();
|
||||
}
|
||||
|
||||
task->mArrayData.SwapElements(aArrayData);
|
||||
@@ -71,53 +76,10 @@ CreateFileTask::Create(FileSystemBase* aFileSystem,
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<CreateFileTask>
|
||||
CreateFileTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateFileTask> task =
|
||||
new CreateFileTask(aFileSystem, aParam, aParent);
|
||||
|
||||
task->GetOutputBufferSize();
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mReplace = aParam.replace();
|
||||
|
||||
auto& data = aParam.data();
|
||||
|
||||
if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
|
||||
task->mArrayData = data;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
|
||||
RefPtr<BlobImpl> blobImpl = bp->GetBlobImpl();
|
||||
MOZ_ASSERT(blobImpl, "blobData should not be null.");
|
||||
|
||||
ErrorResult rv;
|
||||
blobImpl->GetInternalStream(getter_AddRefs(task->mBlobStream), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
}
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
bool aReplace)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
CreateFileTaskChild::CreateFileTaskChild(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
bool aReplace)
|
||||
: FileSystemTaskChildBase(aFileSystem)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mReplace(aReplace)
|
||||
{
|
||||
@@ -125,37 +87,21 @@ CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
, mReplace(false)
|
||||
CreateFileTaskChild::~CreateFileTaskChild()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
CreateFileTask::~CreateFileTask()
|
||||
{
|
||||
MOZ_ASSERT((!mPromise && !mBlobData) || NS_IsMainThread(),
|
||||
"mPromise and mBlobData should be released on main thread!");
|
||||
|
||||
if (mBlobStream) {
|
||||
mBlobStream->Close();
|
||||
}
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
CreateFileTask::GetPromise()
|
||||
CreateFileTaskChild::GetPromise()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return RefPtr<Promise>(mPromise).forget();
|
||||
}
|
||||
|
||||
FileSystemParams
|
||||
CreateFileTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
CreateFileTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemCreateFileParams param;
|
||||
@@ -166,12 +112,21 @@ CreateFileTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
return param;
|
||||
}
|
||||
|
||||
// If we are here, PBackground must be up and running: this method is called
|
||||
// when the task has been already started by FileSystemPermissionRequest
|
||||
// class and this happens only when PBackground actor has already been
|
||||
// created.
|
||||
PBackgroundChild* actor =
|
||||
mozilla::ipc::BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(actor);
|
||||
|
||||
param.replace() = mReplace;
|
||||
if (mBlobData) {
|
||||
BlobChild* actor =
|
||||
ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlobData);
|
||||
if (actor) {
|
||||
param.data() = actor;
|
||||
if (mBlobImpl) {
|
||||
PBlobChild* blobActor =
|
||||
mozilla::ipc::BackgroundChild::GetOrCreateActorForBlobImpl(actor,
|
||||
mBlobImpl);
|
||||
if (blobActor) {
|
||||
param.data() = blobActor;
|
||||
}
|
||||
} else {
|
||||
param.data() = mArrayData;
|
||||
@@ -179,11 +134,108 @@ CreateFileTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
return param;
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
CreateFileTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
void
|
||||
CreateFileTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
const FileSystemFileResponse& r = aValue.get_FileSystemFileResponse();
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(r.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CreateFileTaskChild::HandlerCallback()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<File> file = File::CreateFromFile(mFileSystem->GetParentObject(),
|
||||
mTargetPath);
|
||||
mPromise->MaybeResolve(file);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CreateFileTaskChild::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
GET_PERMISSION_ACCESS_TYPE(aAccess)
|
||||
}
|
||||
|
||||
/**
|
||||
* CreateFileTaskParent
|
||||
*/
|
||||
|
||||
uint32_t CreateFileTaskParent::sOutputBufferSize = 0;
|
||||
|
||||
/* static */ already_AddRefed<CreateFileTaskParent>
|
||||
CreateFileTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<CreateFileTaskParent> task =
|
||||
new CreateFileTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mReplace = aParam.replace();
|
||||
|
||||
const FileSystemFileDataValue& data = aParam.data();
|
||||
|
||||
if (data.type() == FileSystemFileDataValue::TArrayOfuint8_t) {
|
||||
task->mArrayData = data;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(data.type() == FileSystemFileDataValue::TPBlobParent);
|
||||
|
||||
BlobParent* bp = static_cast<BlobParent*>(static_cast<PBlobParent*>(data));
|
||||
task->mBlobImpl = bp->GetBlobImpl();
|
||||
MOZ_ASSERT(task->mBlobImpl, "blobData should not be null.");
|
||||
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
CreateFileTaskParent::CreateFileTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
|
||||
, mReplace(false)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
CreateFileTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
@@ -193,22 +245,8 @@ CreateFileTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
return FileSystemFileResponse(path);
|
||||
}
|
||||
|
||||
void
|
||||
CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemFileResponse r = aValue;
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(r.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
CreateFileTask::Work()
|
||||
CreateFileTaskParent::IOWork()
|
||||
{
|
||||
class MOZ_RAII AutoClose final
|
||||
{
|
||||
@@ -280,6 +318,7 @@ CreateFileTask::Work()
|
||||
}
|
||||
|
||||
AutoClose acOutputStream(outputStream);
|
||||
MOZ_ASSERT(sOutputBufferSize);
|
||||
|
||||
nsCOMPtr<nsIOutputStream> bufferedOutputStream;
|
||||
rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
|
||||
@@ -291,11 +330,17 @@ CreateFileTask::Work()
|
||||
|
||||
AutoClose acBufferedOutputStream(bufferedOutputStream);
|
||||
|
||||
if (mBlobStream) {
|
||||
// Write the file content from blob data.
|
||||
// Write the file content from blob data.
|
||||
if (mBlobImpl) {
|
||||
ErrorResult error;
|
||||
nsCOMPtr<nsIInputStream> blobStream;
|
||||
mBlobImpl->GetInternalStream(getter_AddRefs(blobStream), error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
uint64_t bufSize = 0;
|
||||
rv = mBlobStream->Available(&bufSize);
|
||||
rv = blobStream->Available(&bufSize);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@@ -303,15 +348,14 @@ CreateFileTask::Work()
|
||||
while (bufSize && !mFileSystem->IsShutdown()) {
|
||||
uint32_t written = 0;
|
||||
uint32_t writeSize = bufSize < UINT32_MAX ? bufSize : UINT32_MAX;
|
||||
rv = bufferedOutputStream->WriteFrom(mBlobStream, writeSize, &written);
|
||||
rv = bufferedOutputStream->WriteFrom(blobStream, writeSize, &written);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
bufSize -= written;
|
||||
}
|
||||
|
||||
mBlobStream->Close();
|
||||
mBlobStream = nullptr;
|
||||
blobStream->Close();
|
||||
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@@ -338,49 +382,23 @@ CreateFileTask::Work()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
CreateFileTask::HandlerCallback()
|
||||
nsresult
|
||||
CreateFileTaskParent::MainThreadWork()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
mBlobData = nullptr;
|
||||
return;
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sOutputBufferSize) {
|
||||
sOutputBufferSize =
|
||||
mozilla::Preferences::GetUint("dom.filesystem.outputBufferSize", 4096 * 4);
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
mBlobData = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<File> file = File::CreateFromFile(mFileSystem->GetParentObject(),
|
||||
mTargetPath);
|
||||
mPromise->MaybeResolve(file);
|
||||
mPromise = nullptr;
|
||||
mBlobData = nullptr;
|
||||
return FileSystemTaskParentBase::MainThreadWork();
|
||||
}
|
||||
|
||||
void
|
||||
CreateFileTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
CreateFileTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
if (mReplace) {
|
||||
aAccess.AssignLiteral("write");
|
||||
return;
|
||||
}
|
||||
|
||||
aAccess.AssignLiteral("create");
|
||||
}
|
||||
|
||||
void
|
||||
CreateFileTask::GetOutputBufferSize() const
|
||||
{
|
||||
if (sOutputBufferSize || !XRE_IsParentProcess()) {
|
||||
return;
|
||||
}
|
||||
sOutputBufferSize =
|
||||
mozilla::Preferences::GetUint("dom.filesystem.outputBufferSize", 4096 * 4);
|
||||
GET_PERMISSION_ACCESS_TYPE(aAccess)
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -20,10 +20,10 @@ class Blob;
|
||||
class BlobImpl;
|
||||
class Promise;
|
||||
|
||||
class CreateFileTask final : public FileSystemTaskBase
|
||||
class CreateFileTaskChild final : public FileSystemTaskChildBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<CreateFileTask>
|
||||
static already_AddRefed<CreateFileTaskChild>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aFile,
|
||||
Blob* aBlobData,
|
||||
@@ -31,14 +31,8 @@ public:
|
||||
bool replace,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<CreateFileTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~CreateFileTask();
|
||||
~CreateFileTaskChild();
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetPromise();
|
||||
@@ -51,40 +45,70 @@ protected:
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
||||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
private:
|
||||
CreateFileTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aFile,
|
||||
bool aReplace);
|
||||
CreateFileTaskChild(FileSystemBase* aFileSystem,
|
||||
nsIFile* aFile,
|
||||
bool aReplace);
|
||||
|
||||
CreateFileTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
void
|
||||
GetOutputBufferSize() const;
|
||||
|
||||
static uint32_t sOutputBufferSize;
|
||||
RefPtr<Promise> mPromise;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
|
||||
// Not thread-safe and should be released on main thread.
|
||||
RefPtr<Blob> mBlobData;
|
||||
RefPtr<BlobImpl> mBlobImpl;
|
||||
|
||||
nsCOMPtr<nsIInputStream> mBlobStream;
|
||||
// This is going to be the content of the file, received by createFile()
|
||||
// params.
|
||||
InfallibleTArray<uint8_t> mArrayData;
|
||||
|
||||
bool mReplace;
|
||||
};
|
||||
|
||||
class CreateFileTaskParent final : public FileSystemTaskParentBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<CreateFileTaskParent>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual bool
|
||||
NeedToGoToMainThread() const override { return true; }
|
||||
|
||||
virtual nsresult
|
||||
MainThreadWork() override;
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
protected:
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual nsresult
|
||||
IOWork() override;
|
||||
|
||||
private:
|
||||
CreateFileTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemCreateFileParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
static uint32_t sOutputBufferSize;
|
||||
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
|
||||
RefPtr<BlobImpl> mBlobImpl;
|
||||
|
||||
// This is going to be the content of the file, received by createFile()
|
||||
// params.
|
||||
InfallibleTArray<uint8_t> mArrayData;
|
||||
|
||||
bool mReplace;
|
||||
};
|
||||
|
||||
|
||||
@@ -23,15 +23,21 @@ namespace dom {
|
||||
|
||||
DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType,
|
||||
const nsAString& aStorageName)
|
||||
: mWindowId(0)
|
||||
: mStorageType(aStorageType)
|
||||
, mStorageName(aStorageName)
|
||||
, mWindowId(0)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
mPermissionCheckType = ePermissionCheckByTestingPref;
|
||||
|
||||
mStorageType = aStorageType;
|
||||
mStorageName = aStorageName;
|
||||
|
||||
mRequiresPermissionChecks =
|
||||
!mozilla::Preferences::GetBool("device.storage.prompt.testing", false);
|
||||
if (NS_IsMainThread()) {
|
||||
if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
|
||||
mPermissionCheckType = ePermissionCheckNotRequired;
|
||||
} else {
|
||||
mPermissionCheckType = ePermissionCheckRequired;
|
||||
}
|
||||
} else {
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
// Get the permission name required to access the file system.
|
||||
nsresult rv =
|
||||
@@ -53,18 +59,23 @@ DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType,
|
||||
// DeviceStorageTypeChecker is a singleton object and must be initialized on
|
||||
// the main thread. We initialize it here so that we can use it on the worker
|
||||
// thread.
|
||||
DebugOnly<DeviceStorageTypeChecker*> typeChecker
|
||||
= DeviceStorageTypeChecker::CreateOrGet();
|
||||
MOZ_ASSERT(typeChecker);
|
||||
if (NS_IsMainThread()) {
|
||||
DebugOnly<DeviceStorageTypeChecker*> typeChecker =
|
||||
DeviceStorageTypeChecker::CreateOrGet();
|
||||
MOZ_ASSERT(typeChecker);
|
||||
}
|
||||
}
|
||||
|
||||
DeviceStorageFileSystem::~DeviceStorageFileSystem()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
already_AddRefed<FileSystemBase>
|
||||
DeviceStorageFileSystem::Clone()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
RefPtr<DeviceStorageFileSystem> fs =
|
||||
new DeviceStorageFileSystem(mStorageType, mStorageName);
|
||||
|
||||
@@ -77,7 +88,9 @@ void
|
||||
DeviceStorageFileSystem::Init(nsDOMDeviceStorage* aDeviceStorage)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aDeviceStorage);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = aDeviceStorage->GetOwner();
|
||||
MOZ_ASSERT(window->IsInnerWindow());
|
||||
mWindowId = window->WindowID();
|
||||
@@ -86,7 +99,7 @@ DeviceStorageFileSystem::Init(nsDOMDeviceStorage* aDeviceStorage)
|
||||
void
|
||||
DeviceStorageFileSystem::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
AssertIsOnOwningThread();
|
||||
mShutdown = true;
|
||||
}
|
||||
|
||||
@@ -94,6 +107,8 @@ nsISupports*
|
||||
DeviceStorageFileSystem::GetParentObject() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
|
||||
MOZ_ASSERT_IF(!mShutdown, window);
|
||||
return ToSupports(window);
|
||||
@@ -102,14 +117,15 @@ DeviceStorageFileSystem::GetParentObject() const
|
||||
void
|
||||
DeviceStorageFileSystem::GetRootName(nsAString& aRetval) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
aRetval = mStorageName;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Should be on parent process!");
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Should be on parent process!");
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
nsCOMPtr<nsIFile> rootPath;
|
||||
@@ -134,7 +150,7 @@ DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const
|
||||
bool
|
||||
DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aDir);
|
||||
|
||||
ErrorResult rv;
|
||||
@@ -157,6 +173,8 @@ DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const
|
||||
void
|
||||
DeviceStorageFileSystem::SerializeDOMPath(nsAString& aString) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
// Generate the string representation of the file system.
|
||||
aString.AssignLiteral("devicestorage-");
|
||||
aString.Append(mStorageType);
|
||||
@@ -164,5 +182,16 @@ DeviceStorageFileSystem::SerializeDOMPath(nsAString& aString) const
|
||||
aString.Append(mStorageName);
|
||||
}
|
||||
|
||||
nsresult
|
||||
DeviceStorageFileSystem::MainThreadWork()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
DebugOnly<DeviceStorageTypeChecker*> typeChecker =
|
||||
DeviceStorageTypeChecker::CreateOrGet();
|
||||
MOZ_ASSERT(typeChecker);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -48,6 +48,12 @@ public:
|
||||
virtual void
|
||||
SerializeDOMPath(nsAString& aSerializedString) const override;
|
||||
|
||||
virtual bool
|
||||
NeedToGoToMainThread() const override { return true; }
|
||||
|
||||
virtual nsresult
|
||||
MainThreadWork() override;
|
||||
|
||||
private:
|
||||
virtual
|
||||
~DeviceStorageFileSystem();
|
||||
|
||||
@@ -111,10 +111,21 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Directory)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
// static
|
||||
already_AddRefed<Promise>
|
||||
/* static */ bool
|
||||
Directory::DeviceStorageEnabled(JSContext* aCx, JSObject* aObj)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Preferences::GetBool("device.storage.enabled", false);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Promise>
|
||||
Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
|
||||
{
|
||||
// Only exposed for DeviceStorage.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
nsCOMPtr<nsIFile> path;
|
||||
@@ -124,8 +135,9 @@ Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<GetFileOrDirectoryTask> task =
|
||||
GetFileOrDirectoryTask::Create(aFileSystem, path, eDOMRootDirectory, true, aRv);
|
||||
RefPtr<GetFileOrDirectoryTaskChild> task =
|
||||
GetFileOrDirectoryTaskChild::Create(aFileSystem, path, eDOMRootDirectory,
|
||||
true, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -138,7 +150,6 @@ Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
|
||||
Directory::Create(nsISupports* aParent, nsIFile* aFile,
|
||||
DirectoryType aType, FileSystemBase* aFileSystem)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aParent);
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
@@ -168,7 +179,6 @@ Directory::Directory(nsISupports* aParent,
|
||||
, mFile(aFile)
|
||||
, mType(aType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
// aFileSystem can be null. In this case we create a OSFileSystem when needed.
|
||||
@@ -220,6 +230,9 @@ already_AddRefed<Promise>
|
||||
Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// Only exposed for DeviceStorage.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<Blob> blobData;
|
||||
InfallibleTArray<uint8_t> arrayData;
|
||||
bool replace = (aOptions.mIfExists == CreateIfExistsMode::Replace);
|
||||
@@ -252,8 +265,9 @@ Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CreateFileTask> task =
|
||||
CreateFileTask::Create(fs, realPath, blobData, arrayData, replace, aRv);
|
||||
RefPtr<CreateFileTaskChild> task =
|
||||
CreateFileTaskChild::Create(fs, realPath, blobData, arrayData, replace,
|
||||
aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -266,6 +280,9 @@ Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
|
||||
already_AddRefed<Promise>
|
||||
Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
|
||||
{
|
||||
// Only exposed for DeviceStorage.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIFile> realPath;
|
||||
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
|
||||
|
||||
@@ -274,8 +291,8 @@ Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CreateDirectoryTask> task =
|
||||
CreateDirectoryTask::Create(fs, realPath, aRv);
|
||||
RefPtr<CreateDirectoryTaskChild> task =
|
||||
CreateDirectoryTaskChild::Create(fs, realPath, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -288,6 +305,9 @@ Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
|
||||
already_AddRefed<Promise>
|
||||
Directory::Get(const nsAString& aPath, ErrorResult& aRv)
|
||||
{
|
||||
// Only exposed for DeviceStorage.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIFile> realPath;
|
||||
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
|
||||
|
||||
@@ -296,9 +316,9 @@ Directory::Get(const nsAString& aPath, ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<GetFileOrDirectoryTask> task =
|
||||
GetFileOrDirectoryTask::Create(fs, realPath, eNotDOMRootDirectory, false,
|
||||
aRv);
|
||||
RefPtr<GetFileOrDirectoryTaskChild> task =
|
||||
GetFileOrDirectoryTaskChild::Create(fs, realPath, eNotDOMRootDirectory,
|
||||
false, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -311,12 +331,16 @@ Directory::Get(const nsAString& aPath, ErrorResult& aRv)
|
||||
already_AddRefed<Promise>
|
||||
Directory::Remove(const StringOrFileOrDirectory& aPath, ErrorResult& aRv)
|
||||
{
|
||||
// Only exposed for DeviceStorage.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return RemoveInternal(aPath, false, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Directory::RemoveDeep(const StringOrFileOrDirectory& aPath, ErrorResult& aRv)
|
||||
{
|
||||
// Only exposed for DeviceStorage.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return RemoveInternal(aPath, true, aRv);
|
||||
}
|
||||
|
||||
@@ -324,6 +348,9 @@ already_AddRefed<Promise>
|
||||
Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// Only exposed for DeviceStorage.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsresult error = NS_OK;
|
||||
nsCOMPtr<nsIFile> realPath;
|
||||
|
||||
@@ -360,8 +387,8 @@ Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
|
||||
error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
RefPtr<RemoveTask> task =
|
||||
RemoveTask::Create(fs, mFile, realPath, aRecursive, aRv);
|
||||
RefPtr<RemoveTaskChild> task =
|
||||
RemoveTaskChild::Create(fs, mFile, realPath, aRecursive, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -409,8 +436,8 @@ Directory::GetFilesAndDirectories(ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<GetDirectoryListingTask> task =
|
||||
GetDirectoryListingTask::Create(fs, mFile, mType, mFilters, aRv);
|
||||
RefPtr<GetDirectoryListingTaskChild> task =
|
||||
GetDirectoryListingTaskChild::Create(fs, mFile, mType, mFilters, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -480,5 +507,17 @@ Directory::DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
Directory::ClonableToDifferentThreadOrProcess() const
|
||||
{
|
||||
// If we don't have a fileSystem we are going to create a OSFileSystem that is
|
||||
// clonable everywhere.
|
||||
if (!mFileSystem) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return mFileSystem->ClonableToDifferentThreadOrProcess();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -53,6 +53,9 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Directory)
|
||||
|
||||
static bool
|
||||
DeviceStorageEnabled(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
static already_AddRefed<Promise>
|
||||
GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv);
|
||||
|
||||
@@ -144,6 +147,9 @@ public:
|
||||
return mType;
|
||||
}
|
||||
|
||||
bool
|
||||
ClonableToDifferentThreadOrProcess() const;
|
||||
|
||||
private:
|
||||
Directory(nsISupports* aParent,
|
||||
nsIFile* aFile, DirectoryType aType,
|
||||
|
||||
@@ -17,6 +17,9 @@ namespace dom {
|
||||
already_AddRefed<FileSystemBase>
|
||||
FileSystemBase::DeserializeDOMPath(const nsAString& aString)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
if (StringBeginsWith(aString, NS_LITERAL_STRING("devicestorage-"))) {
|
||||
// The string representation of devicestorage file system is of the format:
|
||||
// devicestorage-StorageType-StorageName
|
||||
@@ -39,34 +42,41 @@ FileSystemBase::DeserializeDOMPath(const nsAString& aString)
|
||||
return f.forget();
|
||||
}
|
||||
|
||||
return RefPtr<OSFileSystem>(new OSFileSystem(aString)).forget();
|
||||
return RefPtr<OSFileSystemParent>(new OSFileSystemParent(aString)).forget();
|
||||
}
|
||||
|
||||
FileSystemBase::FileSystemBase()
|
||||
: mShutdown(false)
|
||||
, mRequiresPermissionChecks(true)
|
||||
, mPermissionCheckType(eNotSet)
|
||||
#ifdef DEBUG
|
||||
, mOwningThread(PR_GetCurrentThread())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
FileSystemBase::~FileSystemBase()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemBase::Shutdown()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
mShutdown = true;
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
FileSystemBase::GetParentObject() const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aFile, "aFile Should not be null.");
|
||||
MOZ_ASSERT(aPath);
|
||||
|
||||
@@ -89,12 +99,14 @@ FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
|
||||
bool
|
||||
FileSystemBase::IsSafeFile(nsIFile* aFile) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
FileSystemBase::IsSafeDirectory(Directory* aDir) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -104,6 +116,7 @@ FileSystemBase::GetDOMPath(nsIFile* aFile,
|
||||
nsAString& aRetval,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aFile);
|
||||
|
||||
if (aType == Directory::eDOMRootDirectory) {
|
||||
@@ -171,5 +184,12 @@ FileSystemBase::GetDOMPath(nsIFile* aFile,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemBase::AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -18,8 +18,8 @@ class BlobImpl;
|
||||
|
||||
class FileSystemBase
|
||||
{
|
||||
NS_INLINE_DECL_REFCOUNTING(FileSystemBase)
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(FileSystemBase)
|
||||
|
||||
// Create file system object from its string representation.
|
||||
static already_AddRefed<FileSystemBase>
|
||||
@@ -87,23 +87,63 @@ public:
|
||||
return mPermission;
|
||||
}
|
||||
|
||||
bool
|
||||
RequiresPermissionChecks() const
|
||||
// The decision about doing or not doing the permission check cannot be done
|
||||
// everywhere because, for some FileSystemBase implementation, this depends on
|
||||
// a preference.
|
||||
// This enum describes all the possible decisions. The implementation will do
|
||||
// the check on the main-thread in the child and in the parent process when
|
||||
// needed.
|
||||
// Note: the permission check should not fail in PBackground because that
|
||||
// means that the child has been compromised. If this happens the child
|
||||
// process is killed.
|
||||
enum ePermissionCheckType {
|
||||
// When on the main-thread, we must check if we have
|
||||
// device.storage.prompt.testing set to true.
|
||||
ePermissionCheckByTestingPref,
|
||||
|
||||
// No permission check must be done.
|
||||
ePermissionCheckNotRequired,
|
||||
|
||||
// Permission check is required.
|
||||
ePermissionCheckRequired,
|
||||
|
||||
// This is the default value. We crash if this is let like this.
|
||||
eNotSet
|
||||
};
|
||||
|
||||
ePermissionCheckType
|
||||
PermissionCheckType() const
|
||||
{
|
||||
return mRequiresPermissionChecks;
|
||||
MOZ_ASSERT(mPermissionCheckType != eNotSet);
|
||||
return mPermissionCheckType;
|
||||
}
|
||||
|
||||
// IPC initialization
|
||||
// See how these 2 methods are used in FileSystemTaskChildBase.
|
||||
|
||||
virtual bool
|
||||
NeedToGoToMainThread() const { return false; }
|
||||
|
||||
virtual nsresult
|
||||
MainThreadWork() { return NS_ERROR_FAILURE; }
|
||||
|
||||
virtual bool
|
||||
ClonableToDifferentThreadOrProcess() const { return false; }
|
||||
|
||||
// CC methods
|
||||
virtual void Unlink() {}
|
||||
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) {}
|
||||
|
||||
void
|
||||
AssertIsOnOwningThread() const;
|
||||
|
||||
protected:
|
||||
virtual ~FileSystemBase();
|
||||
|
||||
// The local path of the root (i.e. the OS path, with OS path separators, of
|
||||
// the OS directory that acts as the root of this OSFileSystem).
|
||||
// This path must be set by the FileSystem implementation immediately
|
||||
// because it will be used for the validation of any FileSystemTaskBase.
|
||||
// because it will be used for the validation of any FileSystemTaskChildBase.
|
||||
// The concept of this path is that, any task will never go out of it and this
|
||||
// must be considered the OS 'root' of the current FileSystem. Different
|
||||
// Directory object can have different OS 'root' path.
|
||||
@@ -119,7 +159,11 @@ protected:
|
||||
// The permission name required to access the file system.
|
||||
nsCString mPermission;
|
||||
|
||||
bool mRequiresPermissionChecks;
|
||||
ePermissionCheckType mPermissionCheckType;
|
||||
|
||||
#ifdef DEBUG
|
||||
PRThread* mOwningThread;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -8,28 +8,128 @@
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemTaskBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIIPCBackgroundChildCreateCallback.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
// This class takes care of the PBackground initialization and, once this step
|
||||
// is completed, it starts the task.
|
||||
class PBackgroundInitializer final : public nsIIPCBackgroundChildCreateCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
|
||||
|
||||
static void
|
||||
ScheduleTask(FileSystemTaskChildBase* aTask)
|
||||
{
|
||||
MOZ_ASSERT(aTask);
|
||||
RefPtr<PBackgroundInitializer> pb = new PBackgroundInitializer(aTask);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit PBackgroundInitializer(FileSystemTaskChildBase* aTask)
|
||||
: mTask(aTask)
|
||||
{
|
||||
MOZ_ASSERT(aTask);
|
||||
|
||||
PBackgroundChild* actor =
|
||||
mozilla::ipc::BackgroundChild::GetForCurrentThread();
|
||||
if (actor) {
|
||||
ActorCreated(actor);
|
||||
} else {
|
||||
if (NS_WARN_IF(
|
||||
!mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread(this))) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~PBackgroundInitializer()
|
||||
{}
|
||||
|
||||
RefPtr<FileSystemTaskChildBase> mTask;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(PBackgroundInitializer,
|
||||
nsIIPCBackgroundChildCreateCallback)
|
||||
|
||||
void
|
||||
PBackgroundInitializer::ActorFailed()
|
||||
{
|
||||
MOZ_CRASH("Failed to create a PBackgroundChild actor!");
|
||||
}
|
||||
|
||||
void
|
||||
PBackgroundInitializer::ActorCreated(mozilla::ipc::PBackgroundChild* aActor)
|
||||
{
|
||||
mTask->Start();
|
||||
}
|
||||
|
||||
// This must be a CancelableRunnable because it can be dispatched to a worker
|
||||
// thread. But we don't care about the Cancel() because in that case, Run() is
|
||||
// not called and the task is deleted by the DTOR.
|
||||
class AsyncStartRunnable final : public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit AsyncStartRunnable(FileSystemTaskChildBase* aTask)
|
||||
: mTask(aTask)
|
||||
{
|
||||
MOZ_ASSERT(aTask);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
PBackgroundInitializer::ScheduleTask(mTask);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<FileSystemTaskChildBase> mTask;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
NS_IMPL_ISUPPORTS(FileSystemPermissionRequest, nsIRunnable,
|
||||
nsIContentPermissionRequest)
|
||||
|
||||
// static
|
||||
void
|
||||
FileSystemPermissionRequest::RequestForTask(FileSystemTaskBase* aTask)
|
||||
/* static */ void
|
||||
FileSystemPermissionRequest::RequestForTask(FileSystemTaskChildBase* aTask)
|
||||
{
|
||||
MOZ_ASSERT(aTask, "aTask should not be null!");
|
||||
MOZ_ASSERT(aTask);
|
||||
|
||||
RefPtr<FileSystemBase> filesystem = aTask->GetFileSystem();
|
||||
if (!filesystem) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (filesystem->PermissionCheckType() == FileSystemBase::ePermissionCheckNotRequired) {
|
||||
// Let's make the scheduling of this task asynchronous.
|
||||
RefPtr<AsyncStartRunnable> runnable = new AsyncStartRunnable(aTask);
|
||||
NS_DispatchToCurrentThread(runnable);
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't need any permission check for the FileSystem API. If we are here
|
||||
// it's because we are dealing with a DeviceStorage API that is main-thread
|
||||
// only.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<FileSystemPermissionRequest> request =
|
||||
new FileSystemPermissionRequest(aTask);
|
||||
NS_DispatchToCurrentThread(request);
|
||||
}
|
||||
|
||||
FileSystemPermissionRequest::FileSystemPermissionRequest(FileSystemTaskBase* aTask)
|
||||
FileSystemPermissionRequest::FileSystemPermissionRequest(FileSystemTaskChildBase* aTask)
|
||||
: mTask(aTask)
|
||||
{
|
||||
MOZ_ASSERT(mTask, "aTask should not be null!");
|
||||
@@ -98,7 +198,7 @@ FileSystemPermissionRequest::Cancel()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mTask->SetError(NS_ERROR_DOM_SECURITY_ERR);
|
||||
mTask->Start();
|
||||
ScheduleTask();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -107,7 +207,7 @@ FileSystemPermissionRequest::Allow(JS::HandleValue aChoices)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aChoices.isUndefined());
|
||||
mTask->Start();
|
||||
ScheduleTask();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -122,7 +222,13 @@ FileSystemPermissionRequest::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!filesystem->RequiresPermissionChecks()) {
|
||||
if (filesystem->PermissionCheckType() == FileSystemBase::ePermissionCheckNotRequired) {
|
||||
Allow(JS::UndefinedHandleValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (filesystem->PermissionCheckType() == FileSystemBase::ePermissionCheckByTestingPref &&
|
||||
mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
|
||||
Allow(JS::UndefinedHandleValue);
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -146,5 +252,11 @@ FileSystemPermissionRequest::GetRequester(nsIContentPermissionRequester** aReque
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemPermissionRequest::ScheduleTask()
|
||||
{
|
||||
PBackgroundInitializer::ScheduleTask(mTask);
|
||||
}
|
||||
|
||||
} /* namespace dom */
|
||||
} /* namespace mozilla */
|
||||
|
||||
@@ -17,7 +17,7 @@ class nsPIDOMWindow;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class FileSystemTaskBase;
|
||||
class FileSystemTaskChildBase;
|
||||
|
||||
class FileSystemPermissionRequest final
|
||||
: public nsIContentPermissionRequest
|
||||
@@ -26,20 +26,27 @@ class FileSystemPermissionRequest final
|
||||
public:
|
||||
// Request permission for the given task.
|
||||
static void
|
||||
RequestForTask(FileSystemTaskBase* aTask);
|
||||
RequestForTask(FileSystemTaskChildBase* aTask);
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSICONTENTPERMISSIONREQUEST
|
||||
NS_DECL_NSIRUNNABLE
|
||||
private:
|
||||
explicit FileSystemPermissionRequest(FileSystemTaskBase* aTask);
|
||||
|
||||
virtual
|
||||
private:
|
||||
explicit FileSystemPermissionRequest(FileSystemTaskChildBase* aTask);
|
||||
|
||||
~FileSystemPermissionRequest();
|
||||
|
||||
// Once the permission check has been done, we must run the task using IPC and
|
||||
// PBackground. This method checks if the PBackground thread is ready to
|
||||
// receive the task and in case waits for ActorCreated() to be called using
|
||||
// the PBackgroundInitializer class (see FileSystemPermissionRequest.cpp).
|
||||
void
|
||||
ScheduleTask();
|
||||
|
||||
nsCString mPermissionType;
|
||||
nsCString mPermissionAccess;
|
||||
RefPtr<FileSystemTaskBase> mTask;
|
||||
RefPtr<FileSystemTaskChildBase> mTask;
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsCOMPtr<nsIContentPermissionRequester> mRequester;
|
||||
|
||||
@@ -18,18 +18,22 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
FileSystemRequestParent::FileSystemRequestParent()
|
||||
: mDestroyed(false)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
FileSystemRequestParent::~FileSystemRequestParent()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
#define FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(name) \
|
||||
case FileSystemParams::TFileSystem##name##Params: { \
|
||||
const FileSystem##name##Params& p = aParams; \
|
||||
mFileSystem = FileSystemBase::DeserializeDOMPath(p.filesystem()); \
|
||||
task = name##Task::Create(mFileSystem, p, this, rv); \
|
||||
MOZ_ASSERT(mFileSystem); \
|
||||
mTask = name##TaskParent::Create(mFileSystem, p, this, rv); \
|
||||
if (NS_WARN_IF(rv.Failed())) { \
|
||||
return false; \
|
||||
} \
|
||||
@@ -37,11 +41,10 @@ FileSystemRequestParent::~FileSystemRequestParent()
|
||||
}
|
||||
|
||||
bool
|
||||
FileSystemRequestParent::Dispatch(ContentParent* aParent,
|
||||
const FileSystemParams& aParams)
|
||||
FileSystemRequestParent::Initialize(const FileSystemParams& aParams)
|
||||
{
|
||||
MOZ_ASSERT(aParent, "aParent should not be null.");
|
||||
RefPtr<FileSystemTaskBase> task;
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
ErrorResult rv;
|
||||
|
||||
switch (aParams.type()) {
|
||||
@@ -58,39 +61,47 @@ FileSystemRequestParent::Dispatch(ContentParent* aParent,
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!task || !mFileSystem)) {
|
||||
if (NS_WARN_IF(!mTask || !mFileSystem)) {
|
||||
// Should never reach here.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mFileSystem->RequiresPermissionChecks()) {
|
||||
// Check the content process permission.
|
||||
if (mFileSystem->PermissionCheckType() != FileSystemBase::ePermissionCheckNotRequired) {
|
||||
nsAutoCString access;
|
||||
mTask->GetPermissionAccessType(access);
|
||||
|
||||
nsCString access;
|
||||
task->GetPermissionAccessType(access);
|
||||
|
||||
nsAutoCString permissionName;
|
||||
permissionName = mFileSystem->GetPermission();
|
||||
permissionName.Append('-');
|
||||
permissionName.Append(access);
|
||||
|
||||
if (!AssertAppProcessPermission(aParent, permissionName.get())) {
|
||||
return false;
|
||||
}
|
||||
mPermissionName = mFileSystem->GetPermission();
|
||||
mPermissionName.Append('-');
|
||||
mPermissionName.Append(access);
|
||||
}
|
||||
|
||||
task->Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemRequestParent::ActorDestroy(ActorDestroyReason why)
|
||||
FileSystemRequestParent::Start()
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
MOZ_ASSERT(mFileSystem);
|
||||
MOZ_ASSERT(mTask);
|
||||
|
||||
mTask->Start();
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemRequestParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
|
||||
if (!mFileSystem) {
|
||||
return;
|
||||
}
|
||||
|
||||
mFileSystem->Shutdown();
|
||||
mFileSystem = nullptr;
|
||||
mTask = nullptr;
|
||||
mDestroyed = true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -8,39 +8,57 @@
|
||||
#define mozilla_dom_FileSystemRequestParent_h
|
||||
|
||||
#include "mozilla/dom/PFileSystemRequestParent.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class FileSystemBase;
|
||||
class FileSystemParams;
|
||||
class FileSystemTaskParentBase;
|
||||
|
||||
class FileSystemRequestParent final
|
||||
: public PFileSystemRequestParent
|
||||
class FileSystemRequestParent final : public PFileSystemRequestParent
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileSystemRequestParent)
|
||||
|
||||
public:
|
||||
FileSystemRequestParent();
|
||||
|
||||
bool
|
||||
IsRunning()
|
||||
const nsCString&
|
||||
PermissionName() const
|
||||
{
|
||||
return state() == PFileSystemRequest::__Start;
|
||||
return mPermissionName;
|
||||
}
|
||||
|
||||
FileSystemBase::ePermissionCheckType
|
||||
PermissionCheckType() const
|
||||
{
|
||||
return mFileSystem ? mFileSystem->PermissionCheckType()
|
||||
: FileSystemBase::eNotSet;
|
||||
}
|
||||
|
||||
bool
|
||||
Dispatch(ContentParent* aParent, const FileSystemParams& aParams);
|
||||
Initialize(const FileSystemParams& aParams);
|
||||
|
||||
void
|
||||
Start();
|
||||
|
||||
bool Destroyed() const
|
||||
{
|
||||
return mDestroyed;
|
||||
}
|
||||
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason why) override;
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
virtual
|
||||
~FileSystemRequestParent();
|
||||
|
||||
RefPtr<FileSystemBase> mFileSystem;
|
||||
RefPtr<FileSystemTaskParentBase> mTask;
|
||||
|
||||
nsCString mPermissionName;
|
||||
|
||||
bool mDestroyed;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -7,14 +7,13 @@
|
||||
#include "mozilla/dom/FileSystemTaskBase.h"
|
||||
|
||||
#include "nsNetCID.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemRequestParent.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
@@ -23,85 +22,124 @@ namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
class FileSystemReleaseRunnable final : public nsRunnable
|
||||
nsresult
|
||||
FileSystemErrorFromNsError(const nsresult& aErrorValue)
|
||||
{
|
||||
public:
|
||||
explicit FileSystemReleaseRunnable(RefPtr<FileSystemBase>& aDoomed)
|
||||
: mDoomed(nullptr)
|
||||
{
|
||||
aDoomed.swap(mDoomed);
|
||||
uint16_t module = NS_ERROR_GET_MODULE(aErrorValue);
|
||||
if (module == NS_ERROR_MODULE_DOM_FILESYSTEM ||
|
||||
module == NS_ERROR_MODULE_DOM_FILE ||
|
||||
module == NS_ERROR_MODULE_DOM) {
|
||||
return aErrorValue;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
switch (aErrorValue) {
|
||||
case NS_OK:
|
||||
return NS_OK;
|
||||
|
||||
case NS_ERROR_FILE_INVALID_PATH:
|
||||
case NS_ERROR_FILE_UNRECOGNIZED_PATH:
|
||||
return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
|
||||
case NS_ERROR_FILE_DESTINATION_NOT_DIR:
|
||||
return NS_ERROR_DOM_FILESYSTEM_INVALID_MODIFICATION_ERR;
|
||||
|
||||
case NS_ERROR_FILE_ACCESS_DENIED:
|
||||
case NS_ERROR_FILE_DIR_NOT_EMPTY:
|
||||
return NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
|
||||
case NS_ERROR_FILE_TARGET_DOES_NOT_EXIST:
|
||||
case NS_ERROR_NOT_AVAILABLE:
|
||||
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
|
||||
|
||||
case NS_ERROR_FILE_ALREADY_EXISTS:
|
||||
return NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR;
|
||||
|
||||
case NS_ERROR_FILE_NOT_DIRECTORY:
|
||||
return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
|
||||
|
||||
case NS_ERROR_UNEXPECTED:
|
||||
default:
|
||||
return NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
DispatchToIOThread(nsIRunnable* aRunnable)
|
||||
{
|
||||
MOZ_ASSERT(aRunnable);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target
|
||||
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||
MOZ_ASSERT(target);
|
||||
|
||||
return target->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
// This runnable is used when an error value is set before doing any real
|
||||
// operation on the I/O thread. In this case we skip all and we directly
|
||||
// communicate the error.
|
||||
class ErrorRunnable final : public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit ErrorRunnable(FileSystemTaskChildBase* aTask)
|
||||
: mTask(aTask)
|
||||
{
|
||||
mDoomed->Release();
|
||||
MOZ_ASSERT(aTask);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mTask->HasError());
|
||||
|
||||
mTask->HandlerCallback();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
FileSystemBase* MOZ_OWNING_REF mDoomed;
|
||||
RefPtr<FileSystemTaskChildBase> mTask;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem)
|
||||
/**
|
||||
* FileSystemTaskBase class
|
||||
*/
|
||||
|
||||
FileSystemTaskChildBase::FileSystemTaskChildBase(FileSystemBase* aFileSystem)
|
||||
: mErrorValue(NS_OK)
|
||||
, mFileSystem(aFileSystem)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
|
||||
aFileSystem->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem,
|
||||
const FileSystemParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: mErrorValue(NS_OK)
|
||||
, mFileSystem(aFileSystem)
|
||||
, mRequestParent(aParent)
|
||||
FileSystemTaskChildBase::~FileSystemTaskChildBase()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
|
||||
}
|
||||
|
||||
FileSystemTaskBase::~FileSystemTaskBase()
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
RefPtr<FileSystemReleaseRunnable> runnable =
|
||||
new FileSystemReleaseRunnable(mFileSystem);
|
||||
MOZ_ASSERT(!mFileSystem);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
FileSystemBase*
|
||||
FileSystemTaskBase::GetFileSystem() const
|
||||
FileSystemTaskChildBase::GetFileSystem() const
|
||||
{
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
return mFileSystem.get();
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemTaskBase::Start()
|
||||
FileSystemTaskChildBase::Start()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
if (HasError()) {
|
||||
NS_DispatchToMainThread(this);
|
||||
// In this case we don't want to use IPC at all.
|
||||
RefPtr<ErrorRunnable> runnable = new ErrorRunnable(this);
|
||||
nsresult rv = NS_DispatchToCurrentThread(runnable);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
return;
|
||||
}
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
// Run in parent process.
|
||||
// Start worker thread.
|
||||
nsCOMPtr<nsIEventTarget> target
|
||||
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
|
||||
NS_ASSERTION(target, "Must have stream transport service.");
|
||||
target->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
return;
|
||||
}
|
||||
|
||||
// Run in child process.
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
return;
|
||||
}
|
||||
@@ -117,72 +155,24 @@ FileSystemTaskBase::Start()
|
||||
|
||||
// Retain a reference so the task object isn't deleted without IPDL's
|
||||
// knowledge. The reference will be released by
|
||||
// mozilla::dom::ContentChild::DeallocPFileSystemRequestChild.
|
||||
// mozilla::ipc::BackgroundChildImpl::DeallocPFileSystemRequestChild.
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
ContentChild::GetSingleton()->SendPFileSystemRequestConstructor(this,
|
||||
params);
|
||||
}
|
||||
// If we are here, PBackground must be up and running, because Start() is
|
||||
// called only by FileSystemPermissionRequest, and that class takes care of
|
||||
// PBackground initialization.
|
||||
PBackgroundChild* actor =
|
||||
mozilla::ipc::BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(actor);
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileSystemTaskBase::Run()
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
// Run worker thread tasks
|
||||
nsresult rv = Work();
|
||||
if (NS_FAILED(rv)) {
|
||||
SetError(rv);
|
||||
}
|
||||
// Dispatch itself to main thread
|
||||
NS_DispatchToMainThread(this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Run main thread tasks
|
||||
HandleResult();
|
||||
return NS_OK;
|
||||
actor->SendPFileSystemRequestConstructor(this, params);
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemTaskBase::HandleResult()
|
||||
FileSystemTaskChildBase::SetRequestResult(const FileSystemResponseValue& aValue)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
return;
|
||||
}
|
||||
if (mRequestParent && mRequestParent->IsRunning()) {
|
||||
Unused << mRequestParent->Send__delete__(mRequestParent,
|
||||
GetRequestResult());
|
||||
} else {
|
||||
HandlerCallback();
|
||||
}
|
||||
}
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
FileSystemResponseValue
|
||||
FileSystemTaskBase::GetRequestResult() const
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (!HasError()) {
|
||||
ErrorResult rv;
|
||||
FileSystemResponseValue value = GetSuccessRequestResult(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return FileSystemErrorResponse(rv.StealNSResult());
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return FileSystemErrorResponse(mErrorValue);
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemTaskBase::SetRequestResult(const FileSystemResponseValue& aValue)
|
||||
{
|
||||
MOZ_ASSERT(!XRE_IsParentProcess(),
|
||||
"Only call from child process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (aValue.type() == FileSystemResponseValue::TFileSystemErrorResponse) {
|
||||
FileSystemErrorResponse r = aValue;
|
||||
mErrorValue = r.error();
|
||||
@@ -194,61 +184,172 @@ FileSystemTaskBase::SetRequestResult(const FileSystemResponseValue& aValue)
|
||||
}
|
||||
|
||||
bool
|
||||
FileSystemTaskBase::Recv__delete__(const FileSystemResponseValue& aValue)
|
||||
FileSystemTaskChildBase::Recv__delete__(const FileSystemResponseValue& aValue)
|
||||
{
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
SetRequestResult(aValue);
|
||||
HandlerCallback();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemTaskBase::SetError(const nsresult& aErrorValue)
|
||||
FileSystemTaskChildBase::SetError(const nsresult& aErrorValue)
|
||||
{
|
||||
uint16_t module = NS_ERROR_GET_MODULE(aErrorValue);
|
||||
if (module == NS_ERROR_MODULE_DOM_FILESYSTEM ||
|
||||
module == NS_ERROR_MODULE_DOM_FILE ||
|
||||
module == NS_ERROR_MODULE_DOM) {
|
||||
mErrorValue = aErrorValue;
|
||||
mErrorValue = FileSystemErrorFromNsError(aErrorValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* FileSystemTaskParentBase class
|
||||
*/
|
||||
|
||||
FileSystemTaskParentBase::FileSystemTaskParentBase(FileSystemBase* aFileSystem,
|
||||
const FileSystemParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: mErrorValue(NS_OK)
|
||||
, mFileSystem(aFileSystem)
|
||||
, mRequestParent(aParent)
|
||||
, mBackgroundEventTarget(NS_GetCurrentThread())
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
|
||||
MOZ_ASSERT(aParent);
|
||||
MOZ_ASSERT(mBackgroundEventTarget);
|
||||
AssertIsOnBackgroundThread();
|
||||
}
|
||||
|
||||
FileSystemTaskParentBase::~FileSystemTaskParentBase()
|
||||
{
|
||||
// This task can be released on different threads because we dispatch it (as
|
||||
// runnable) to main-thread, I/O and then back to the PBackground thread.
|
||||
NS_ProxyRelease(mBackgroundEventTarget, mFileSystem.forget());
|
||||
NS_ProxyRelease(mBackgroundEventTarget, mRequestParent.forget());
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemTaskParentBase::Start()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
if (NeedToGoToMainThread()) {
|
||||
nsresult rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aErrorValue) {
|
||||
case NS_OK:
|
||||
mErrorValue = NS_OK;
|
||||
return;
|
||||
nsresult rv = DispatchToIOThread(this);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
case NS_ERROR_FILE_INVALID_PATH:
|
||||
case NS_ERROR_FILE_UNRECOGNIZED_PATH:
|
||||
mErrorValue = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
|
||||
return;
|
||||
void
|
||||
FileSystemTaskParentBase::HandleResult()
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
case NS_ERROR_FILE_DESTINATION_NOT_DIR:
|
||||
mErrorValue = NS_ERROR_DOM_FILESYSTEM_INVALID_MODIFICATION_ERR;
|
||||
return;
|
||||
|
||||
case NS_ERROR_FILE_ACCESS_DENIED:
|
||||
case NS_ERROR_FILE_DIR_NOT_EMPTY:
|
||||
mErrorValue = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
return;
|
||||
|
||||
case NS_ERROR_FILE_TARGET_DOES_NOT_EXIST:
|
||||
case NS_ERROR_NOT_AVAILABLE:
|
||||
mErrorValue = NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
|
||||
return;
|
||||
|
||||
case NS_ERROR_FILE_ALREADY_EXISTS:
|
||||
mErrorValue = NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR;
|
||||
return;
|
||||
|
||||
case NS_ERROR_FILE_NOT_DIRECTORY:
|
||||
mErrorValue = NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
|
||||
return;
|
||||
|
||||
case NS_ERROR_UNEXPECTED:
|
||||
default:
|
||||
mErrorValue = NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR;
|
||||
return;
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mRequestParent);
|
||||
Unused << mRequestParent->Send__delete__(mRequestParent, GetRequestResult());
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
FileSystemTaskParentBase::GetRequestResult() const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
if (HasError()) {
|
||||
return FileSystemErrorResponse(mErrorValue);
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
FileSystemResponseValue value = GetSuccessRequestResult(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return FileSystemErrorResponse(rv.StealNSResult());
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
FileSystemTaskParentBase::SetError(const nsresult& aErrorValue)
|
||||
{
|
||||
mErrorValue = FileSystemErrorFromNsError(aErrorValue);
|
||||
}
|
||||
|
||||
bool
|
||||
FileSystemTaskParentBase::NeedToGoToMainThread() const
|
||||
{
|
||||
return mFileSystem->NeedToGoToMainThread();
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileSystemTaskParentBase::MainThreadWork()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mFileSystem->MainThreadWork();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FileSystemTaskParentBase::Run()
|
||||
{
|
||||
// This method can run in 3 different threads. Here why:
|
||||
// 1. if we are on the main-thread it's because the task must do something
|
||||
// here. If no errors are returned we go the step 2.
|
||||
// 2. We can be here directly if the task doesn't have nothing to do on the
|
||||
// main-thread. We are are on the I/O thread and we call IOWork().
|
||||
// 3. Both step 1 (in case of error) and step 2 end up here where return the
|
||||
// value back to the PBackground thread.
|
||||
if (NS_IsMainThread()) {
|
||||
MOZ_ASSERT(NeedToGoToMainThread());
|
||||
|
||||
nsresult rv = MainThreadWork();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
SetError(rv);
|
||||
|
||||
// Something when wrong. Let's go to the Background thread directly
|
||||
// skipping the I/O thread step.
|
||||
rv = mBackgroundEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Next step must happen on the I/O thread.
|
||||
rv = DispatchToIOThread(this);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Run I/O thread tasks
|
||||
if (!IsOnBackgroundThread()) {
|
||||
nsresult rv = IOWork();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
SetError(rv);
|
||||
}
|
||||
|
||||
// Let's go back to PBackground thread to finish the work.
|
||||
rv = mBackgroundEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we are here, it's because the I/O work has been done and we have to
|
||||
// handle the result back via IPC.
|
||||
AssertIsOnBackgroundThread();
|
||||
HandleResult();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
+194
-134
@@ -10,111 +10,118 @@
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/FileSystemRequestParent.h"
|
||||
#include "mozilla/dom/PFileSystemRequestChild.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class BlobImpl;
|
||||
class BlobParent;
|
||||
class FileSystemBase;
|
||||
class FileSystemParams;
|
||||
class PBlobParent;
|
||||
|
||||
/*
|
||||
* The base class to implement a Task class.
|
||||
* The task is used to handle the OOP (out of process) operations.
|
||||
* The file system operations can only be performed in the parent process. When
|
||||
* performing such a parent-process-only operation, a task will delivered the
|
||||
* operation to the parent process if needed.
|
||||
* The file system operations can only be performed in the parent process. In
|
||||
* order to avoid duplicated code, we used PBackground for child-parent and
|
||||
* parent-parent communications.
|
||||
*
|
||||
* The following diagram illustrates the how a API call from the content page
|
||||
* starts a task and gets call back results.
|
||||
*
|
||||
* The left block is the call sequence inside the child process, while the
|
||||
* right block is the call sequence inside the parent process.
|
||||
* The left block is the call sequence inside any process loading content, while
|
||||
* the right block is the call sequence only inside the parent process.
|
||||
*
|
||||
* There are two types of API call. One is from the content page of the child
|
||||
* process and we mark the steps as (1) to (8). The other is from the content
|
||||
* page of the parent process and we mark the steps as (1') to (4').
|
||||
* Page
|
||||
* |
|
||||
* | (1)
|
||||
* ______|_______________________ | __________________________________
|
||||
* | | | | | |
|
||||
* | | | | | |
|
||||
* | V | IPC | PBackground thread on |
|
||||
* | [new FileSystemTaskChildBase()] | | | the parent process |
|
||||
* | | | | | |
|
||||
* | | (2) | | | |
|
||||
* | V | | | |
|
||||
* | [FileSystemPermissionRequest------------------\ |
|
||||
* | ::RequestForTask()] <------------------------/ |
|
||||
* | | | | | |
|
||||
* | | (3) | | |
|
||||
* | V | (4) | |
|
||||
* | [GetRequestParams]------------------->[new FileSystemTaskParentBase()] |
|
||||
* | | | | |
|
||||
* | | | | | (5) _____________ |
|
||||
* | | | | | | | |
|
||||
* | | | | | | I/O Thread | |
|
||||
* | | | | | | | |
|
||||
* | | | | ---------> [IOWork] | |
|
||||
* | | IPC | | | | |
|
||||
* | | | | | | (6) | |
|
||||
* | | | | -------------- | |
|
||||
* | | | | | |_____________| |
|
||||
* | | | | | |
|
||||
* | | | | V |
|
||||
* | | | | [HandleResult] |
|
||||
* | | | | | |
|
||||
* | | | | (7) |
|
||||
* | | (8) | V |
|
||||
* | [SetRequestResult]<---------------------[GetRequestResult] |
|
||||
* | | | | |
|
||||
* | | (9) | | | |
|
||||
* | V | | | |
|
||||
* |[HandlerCallback] | IPC | |
|
||||
* |_______|_________________________| | |_________________________________|
|
||||
* | |
|
||||
* V
|
||||
* Page
|
||||
*
|
||||
* Page Page
|
||||
* | |
|
||||
* | (1) | (1')
|
||||
* ______|________________ | _____________________|_____________
|
||||
* | | | | | | |
|
||||
* | | Task in | | | Task in | |
|
||||
* | | Child Process | | | Parent Process | |
|
||||
* | V | IPC | V |
|
||||
* [new FileSystemTaskBase()] | | [new FileSystemTaskBase()] |
|
||||
* | | | | | | |
|
||||
* | | (2) | | | (2') |
|
||||
* | V | (3) | | |
|
||||
* | [GetRequestParams]------------->[new FileSystemTaskBase(...)] |
|
||||
* | | | | | |
|
||||
* | | | | | (4) | |
|
||||
* | | | | | V |
|
||||
* | | | | -----------> [Work] |
|
||||
* | | IPC | | |
|
||||
* | | | | (5) | (3') |
|
||||
* | | | | V |
|
||||
* | | | | --------[HandleResult] |
|
||||
* | | | | | | |
|
||||
* | | | | (6) | |
|
||||
* | | (7) | V | |
|
||||
* | [SetRequestResult]<-------------[GetRequestResult] | |
|
||||
* | | | | | (4') |
|
||||
* | | (8) | | | | |
|
||||
* | V | | | V |
|
||||
* |[HandlerCallback] | IPC | [HandlerCallback] |
|
||||
* |_______|_______________| | |_________________________|_________|
|
||||
* | | |
|
||||
* V V
|
||||
* Page Page
|
||||
*
|
||||
* 1. From child process page
|
||||
* Child:
|
||||
* 1. From the process that is handling the request
|
||||
* Child/Parent (it can be in any process):
|
||||
* (1) Call FileSystem API from content page with JS. Create a task and run.
|
||||
* The base constructor [FileSystemTaskBase()] of the task should be called.
|
||||
* (2) Forward the task to the parent process through the IPC and call
|
||||
* The base constructor [FileSystemTaskChildBase()] of the task should be
|
||||
* called.
|
||||
* (2) The FileSystemTaskChildBase object is given to
|
||||
* [FileSystemPermissionRequest::RequestForTask()] that will perform a
|
||||
* permission check step if needed (See ePermissionCheckType enum). The real
|
||||
* operation is done on the parent process but it's hidden by
|
||||
* [nsContentPermissionUtils::AskPermission()]. If the permission check is not
|
||||
* needed or if the page has the right permission, the
|
||||
* FileSystemPermissionRequest will start the task (only once PBackground
|
||||
* actor is fully initialized).
|
||||
* (3) Forward the task to the parent process through the IPC and call
|
||||
* [GetRequestParams] to prepare the parameters of the IPC.
|
||||
* Parent:
|
||||
* (3) The parent process receives IPC and handle it in
|
||||
* FileystemRequestParent.
|
||||
* Get the IPC parameters and create a task to run the IPC task. The base
|
||||
* constructor [FileSystemTaskBase(aParam, aParent)] of the task should be
|
||||
* called to set the task as an IPC task.
|
||||
* (4) The task operation will be performed in the member function of [Work].
|
||||
* A worker thread will be created to run that function. If error occurs
|
||||
* (4) The parent process receives IPC and handle it in
|
||||
* FileystemRequestParent. Get the IPC parameters and create a task to run the
|
||||
* IPC task. The base constructor [FileSystemTaskParentBase(aParam, aParent)]
|
||||
* For security reasons, we do an additional permission check if needed. In
|
||||
* the check fails, the child process will be killed.
|
||||
* of the task should be called to set the task as an IPC task.
|
||||
* (5) The task operation will be performed in the member function of [IOWork].
|
||||
* A I/O thread will be created to run that function. If error occurs
|
||||
* during the operation, call [SetError] to record the error and then abort.
|
||||
* (5) After finishing the task operation, call [HandleResult] to send the
|
||||
* (6) After finishing the task operation, call [HandleResult] to send the
|
||||
* result back to the child process though the IPC.
|
||||
* (6) Call [GetRequestResult] request result to prepare the parameters of the
|
||||
* (7) Call [GetRequestResult] request result to prepare the parameters of the
|
||||
* IPC. Because the formats of the error result for different task are the
|
||||
* same, FileSystemTaskBase can handle the error message without interfering.
|
||||
* same, FileSystemTaskChildBase can handle the error message without
|
||||
* interfering.
|
||||
* Each task only needs to implement its specific success result preparation
|
||||
* function -[GetSuccessRequestResult].
|
||||
* Child:
|
||||
* (7) The child process receives IPC and calls [SetRequestResult] to get the
|
||||
* Child/Parent:
|
||||
* (8) The process receives IPC and calls [SetRequestResult] to get the
|
||||
* task result. Each task needs to implement its specific success result
|
||||
* parsing function [SetSuccessRequestResult] to get the success result.
|
||||
* (8) Call [HandlerCallback] to send the task result to the content page.
|
||||
* 2. From parent process page
|
||||
* We don't need to send the task parameters and result to other process. So
|
||||
* there are less steps, but their functions are the same. The correspondence
|
||||
* between the two types of steps is:
|
||||
* (1') = (1),
|
||||
* (2') = (4),
|
||||
* (3') = (5),
|
||||
* (4') = (8).
|
||||
* (9) Call [HandlerCallback] to send the task result to the content page.
|
||||
*/
|
||||
class FileSystemTaskBase
|
||||
: public nsRunnable
|
||||
, public PFileSystemRequestChild
|
||||
class FileSystemTaskChildBase : public PFileSystemRequestChild
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(FileSystemTaskChildBase)
|
||||
|
||||
/*
|
||||
* Start the task. If the task is running the child process, it will be
|
||||
* forwarded to parent process by IPC, or else, creates a worker thread to
|
||||
* do the task work.
|
||||
* Start the task. It will dispatch all the information to the parent process,
|
||||
* PBackground thread. This method must be called from the owning thread.
|
||||
*/
|
||||
void
|
||||
Start();
|
||||
@@ -135,104 +142,157 @@ public:
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const = 0;
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
protected:
|
||||
/*
|
||||
* To create a task to handle the page content request.
|
||||
*/
|
||||
explicit FileSystemTaskBase(FileSystemBase* aFileSystem);
|
||||
|
||||
/*
|
||||
* To create a parent process task delivered from the child process through
|
||||
* IPC.
|
||||
*/
|
||||
FileSystemTaskBase(FileSystemBase* aFileSystem,
|
||||
const FileSystemParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
virtual
|
||||
~FileSystemTaskBase();
|
||||
|
||||
/*
|
||||
* The function to perform task operation. It will be run on the worker
|
||||
* thread of the parent process.
|
||||
* Overrides this function to define the task operation for individual task.
|
||||
*/
|
||||
virtual nsresult
|
||||
Work() = 0;
|
||||
|
||||
/*
|
||||
* After the task is completed, this function will be called to pass the task
|
||||
* result to the content page.
|
||||
* result to the content page. This method is called in the owning thread.
|
||||
* Override this function to handle the call back to the content page.
|
||||
*/
|
||||
virtual void
|
||||
HandlerCallback() = 0;
|
||||
|
||||
bool
|
||||
HasError() const { return NS_FAILED(mErrorValue); }
|
||||
|
||||
protected:
|
||||
/*
|
||||
* To create a task to handle the page content request.
|
||||
*/
|
||||
explicit FileSystemTaskChildBase(FileSystemBase* aFileSystem);
|
||||
|
||||
virtual
|
||||
~FileSystemTaskChildBase();
|
||||
|
||||
/*
|
||||
* Wrap the task parameter to FileSystemParams for sending it through IPC.
|
||||
* It will be called when we need to forward a task from the child process to
|
||||
* the prarent process.
|
||||
* the parent process. This method runs in the owning thread.
|
||||
* @param filesystem The string representation of the file system.
|
||||
*/
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const = 0;
|
||||
|
||||
/*
|
||||
* Unwrap the IPC message to get the task success result.
|
||||
* It will be called when the task is completed successfully and an IPC
|
||||
* message is received in the child process and we want to get the task
|
||||
* success result. This method runs in the owning thread.
|
||||
*/
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) = 0;
|
||||
|
||||
// Overrides PFileSystemRequestChild
|
||||
virtual bool
|
||||
Recv__delete__(const FileSystemResponseValue& value) override;
|
||||
|
||||
nsresult mErrorValue;
|
||||
RefPtr<FileSystemBase> mFileSystem;
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Unwrap the IPC message to get the task result.
|
||||
* It will be called when the task is completed and an IPC message is received
|
||||
* in the content process and we want to get the task result. This runs on the
|
||||
* owning thread.
|
||||
*/
|
||||
void
|
||||
SetRequestResult(const FileSystemResponseValue& aValue);
|
||||
};
|
||||
|
||||
// This class is the 'alter ego' of FileSystemTaskChildBase in the PBackground
|
||||
// world.
|
||||
class FileSystemTaskParentBase : public nsRunnable
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Start the task. This must be called from the PBackground thread only.
|
||||
*/
|
||||
void
|
||||
Start();
|
||||
|
||||
/*
|
||||
* The error codes are defined in xpcom/base/ErrorList.h and their
|
||||
* corresponding error name and message are defined in dom/base/domerr.msg.
|
||||
*/
|
||||
void
|
||||
SetError(const nsresult& aErrorCode);
|
||||
|
||||
/*
|
||||
* The function to perform task operation. It will be run on the I/O
|
||||
* thread of the parent process.
|
||||
* Overrides this function to define the task operation for individual task.
|
||||
*/
|
||||
virtual nsresult
|
||||
IOWork() = 0;
|
||||
|
||||
/*
|
||||
* Wrap the task success result to FileSystemResponseValue for sending it
|
||||
* through IPC.
|
||||
* through IPC. This method runs in the PBackground thread.
|
||||
* It will be called when the task is completed successfully and we need to
|
||||
* send the task success result back to the child process.
|
||||
*/
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const = 0;
|
||||
|
||||
/*
|
||||
* Unwrap the IPC message to get the task success result.
|
||||
* It will be called when the task is completed successfully and an IPC
|
||||
* message is received in the child process and we want to get the task
|
||||
* success result.
|
||||
*/
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) = 0;
|
||||
|
||||
bool
|
||||
HasError() const { return mErrorValue != NS_OK; }
|
||||
|
||||
// Overrides PFileSystemRequestChild
|
||||
virtual bool
|
||||
Recv__delete__(const FileSystemResponseValue& value) override;
|
||||
|
||||
nsresult mErrorValue;
|
||||
|
||||
RefPtr<FileSystemBase> mFileSystem;
|
||||
RefPtr<FileSystemRequestParent> mRequestParent;
|
||||
private:
|
||||
/*
|
||||
* After finishing the task operation, handle the task result.
|
||||
* If it is an IPC task, send back the IPC result. Or else, send the result
|
||||
* to the content page.
|
||||
* If it is an IPC task, send back the IPC result. It runs on the PBackground
|
||||
* thread.
|
||||
*/
|
||||
void
|
||||
HandleResult();
|
||||
|
||||
// If this task must do something on the main-thread before IOWork(), it must
|
||||
// overwrite this method. Otherwise it returns true if the FileSystem must be
|
||||
// initialized on the main-thread. It's called from the Background thread.
|
||||
virtual bool
|
||||
NeedToGoToMainThread() const;
|
||||
|
||||
// This method is called only if NeedToGoToMainThread() returns true.
|
||||
// Of course, it runs on the main-thread.
|
||||
virtual nsresult
|
||||
MainThreadWork();
|
||||
|
||||
/*
|
||||
* Get the type of permission access required to perform this task.
|
||||
*/
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const = 0;
|
||||
|
||||
bool
|
||||
HasError() const { return NS_FAILED(mErrorValue); }
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override;
|
||||
|
||||
private:
|
||||
/*
|
||||
* Wrap the task result to FileSystemResponseValue for sending it through IPC.
|
||||
* It will be called when the task is completed and we need to
|
||||
* send the task result back to the child process.
|
||||
* send the task result back to the content. This runs on the PBackground
|
||||
* thread.
|
||||
*/
|
||||
FileSystemResponseValue
|
||||
GetRequestResult() const;
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Unwrap the IPC message to get the task result.
|
||||
* It will be called when the task is completed and an IPC message is received
|
||||
* in the child process and we want to get the task result.
|
||||
* To create a parent process task delivered from the child process through
|
||||
* IPC.
|
||||
*/
|
||||
void
|
||||
SetRequestResult(const FileSystemResponseValue& aValue);
|
||||
FileSystemTaskParentBase(FileSystemBase* aFileSystem,
|
||||
const FileSystemParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
virtual
|
||||
~FileSystemTaskParentBase();
|
||||
|
||||
nsresult mErrorValue;
|
||||
RefPtr<FileSystemBase> mFileSystem;
|
||||
RefPtr<FileSystemRequestParent> mRequestParent;
|
||||
nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -11,27 +11,34 @@
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/PFileSystemParams.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
#define GET_DIRECTORY_LISTING_PERMISSION "read"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* static */ already_AddRefed<GetDirectoryListingTask>
|
||||
GetDirectoryListingTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
const nsAString& aFilters,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
/**
|
||||
* GetDirectoryListingTaskChild
|
||||
*/
|
||||
|
||||
RefPtr<GetDirectoryListingTask> task =
|
||||
new GetDirectoryListingTask(aFileSystem, aTargetPath, aType, aFilters);
|
||||
/* static */ already_AddRefed<GetDirectoryListingTaskChild>
|
||||
GetDirectoryListingTaskChild::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
const nsAString& aFilters,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
aFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
RefPtr<GetDirectoryListingTaskChild> task =
|
||||
new GetDirectoryListingTaskChild(aFileSystem, aTargetPath, aType, aFilters);
|
||||
|
||||
// aTargetPath can be null. In this case SetError will be called.
|
||||
|
||||
@@ -50,72 +57,36 @@ GetDirectoryListingTask::Create(FileSystemBase* aFileSystem,
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<GetDirectoryListingTask>
|
||||
GetDirectoryListingTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetDirectoryListingTask> task =
|
||||
new GetDirectoryListingTask(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mType = aParam.isRoot()
|
||||
? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
const nsAString& aFilters)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
GetDirectoryListingTaskChild::GetDirectoryListingTaskChild(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
const nsAString& aFilters)
|
||||
: FileSystemTaskChildBase(aFileSystem)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mFilters(aFilters)
|
||||
, mType(aType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
aFileSystem->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
, mFilters(aParam.filters())
|
||||
GetDirectoryListingTaskChild::~GetDirectoryListingTaskChild()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
GetDirectoryListingTask::~GetDirectoryListingTask()
|
||||
{
|
||||
MOZ_ASSERT(!mPromise || NS_IsMainThread(),
|
||||
"mPromise should be released on main thread!");
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetDirectoryListingTask::GetPromise()
|
||||
GetDirectoryListingTaskChild::GetPromise()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
return RefPtr<Promise>(mPromise).forget();
|
||||
}
|
||||
|
||||
FileSystemParams
|
||||
GetDirectoryListingTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
GetDirectoryListingTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
@@ -128,38 +99,11 @@ GetDirectoryListingTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
mFilters);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
GetDirectoryListingTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
InfallibleTArray<PBlobParent*> blobs;
|
||||
|
||||
nsTArray<FileSystemDirectoryListingResponseData> inputs;
|
||||
|
||||
for (unsigned i = 0; i < mTargetData.Length(); i++) {
|
||||
if (mTargetData[i].mType == Directory::FileOrDirectoryPath::eFilePath) {
|
||||
FileSystemDirectoryListingResponseFile fileData;
|
||||
fileData.fileRealPath() = mTargetData[i].mPath;
|
||||
inputs.AppendElement(fileData);
|
||||
} else {
|
||||
MOZ_ASSERT(mTargetData[i].mType == Directory::FileOrDirectoryPath::eDirectoryPath);
|
||||
FileSystemDirectoryListingResponseDirectory directoryData;
|
||||
directoryData.directoryRealPath() = mTargetData[i].mPath;
|
||||
inputs.AppendElement(directoryData);
|
||||
}
|
||||
}
|
||||
|
||||
FileSystemDirectoryListingResponse response;
|
||||
response.data().SwapElements(inputs);
|
||||
return response;
|
||||
}
|
||||
|
||||
void
|
||||
GetDirectoryListingTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
GetDirectoryListingTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aValue.type() ==
|
||||
FileSystemResponseValue::TFileSystemDirectoryListingResponse);
|
||||
|
||||
@@ -186,8 +130,153 @@ GetDirectoryListingTask::SetSuccessRequestResult(const FileSystemResponseValue&
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetDirectoryListingTaskChild::HandlerCallback()
|
||||
{
|
||||
mFileSystem->AssertIsOnOwningThread();
|
||||
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t count = mTargetData.Length();
|
||||
|
||||
Sequence<OwningFileOrDirectory> listing;
|
||||
|
||||
if (!listing.SetLength(count, mozilla::fallible_t())) {
|
||||
mPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsIFile> path;
|
||||
NS_ConvertUTF16toUTF8 fullPath(mTargetData[i].mPath);
|
||||
nsresult rv = NS_NewNativeLocalFile(fullPath, true, getter_AddRefs(path));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIFile> rootPath;
|
||||
rv = NS_NewLocalFile(mFileSystem->LocalOrDeviceStorageRootPath(), false,
|
||||
getter_AddRefs(rootPath));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(FileSystemUtils::IsDescendantPath(rootPath, path));
|
||||
#endif
|
||||
|
||||
if (mTargetData[i].mType == Directory::FileOrDirectoryPath::eDirectoryPath) {
|
||||
RefPtr<Directory> directory =
|
||||
Directory::Create(mFileSystem->GetParentObject(), path,
|
||||
Directory::eNotDOMRootDirectory, mFileSystem);
|
||||
MOZ_ASSERT(directory);
|
||||
|
||||
// Propogate mFilter onto sub-Directory object:
|
||||
directory->SetContentFilters(mFilters);
|
||||
listing[i].SetAsDirectory() = directory;
|
||||
} else {
|
||||
MOZ_ASSERT(mTargetData[i].mType == Directory::FileOrDirectoryPath::eFilePath);
|
||||
|
||||
RefPtr<File> file =
|
||||
File::CreateFromFile(mFileSystem->GetParentObject(), path);
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
listing[i].SetAsFile() = file;
|
||||
}
|
||||
}
|
||||
|
||||
mPromise->MaybeResolve(listing);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GetDirectoryListingTaskChild::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(GET_DIRECTORY_LISTING_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetDirectoryListingTaskParent
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<GetDirectoryListingTaskParent>
|
||||
GetDirectoryListingTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetDirectoryListingTaskParent> task =
|
||||
new GetDirectoryListingTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mType = aParam.isRoot()
|
||||
? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetDirectoryListingTaskParent::GetDirectoryListingTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
|
||||
, mFilters(aParam.filters())
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
GetDirectoryListingTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
InfallibleTArray<PBlobParent*> blobs;
|
||||
|
||||
nsTArray<FileSystemDirectoryListingResponseData> inputs;
|
||||
|
||||
for (unsigned i = 0; i < mTargetData.Length(); i++) {
|
||||
if (mTargetData[i].mType == Directory::FileOrDirectoryPath::eFilePath) {
|
||||
FileSystemDirectoryListingResponseFile fileData;
|
||||
fileData.fileRealPath() = mTargetData[i].mPath;
|
||||
inputs.AppendElement(fileData);
|
||||
} else {
|
||||
MOZ_ASSERT(mTargetData[i].mType == Directory::FileOrDirectoryPath::eDirectoryPath);
|
||||
FileSystemDirectoryListingResponseDirectory directoryData;
|
||||
directoryData.directoryRealPath() = mTargetData[i].mPath;
|
||||
inputs.AppendElement(directoryData);
|
||||
}
|
||||
}
|
||||
|
||||
FileSystemDirectoryListingResponse response;
|
||||
response.data().SwapElements(inputs);
|
||||
return response;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetDirectoryListingTask::Work()
|
||||
GetDirectoryListingTaskParent::IOWork()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
@@ -303,81 +392,9 @@ GetDirectoryListingTask::Work()
|
||||
}
|
||||
|
||||
void
|
||||
GetDirectoryListingTask::HandlerCallback()
|
||||
GetDirectoryListingTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t count = mTargetData.Length();
|
||||
|
||||
Sequence<OwningFileOrDirectory> listing;
|
||||
|
||||
if (!listing.SetLength(count, mozilla::fallible_t())) {
|
||||
mPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsIFile> path;
|
||||
NS_ConvertUTF16toUTF8 fullPath(mTargetData[i].mPath);
|
||||
nsresult rv = NS_NewNativeLocalFile(fullPath, true, getter_AddRefs(path));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCOMPtr<nsIFile> rootPath;
|
||||
rv = NS_NewLocalFile(mFileSystem->LocalOrDeviceStorageRootPath(), false,
|
||||
getter_AddRefs(rootPath));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(FileSystemUtils::IsDescendantPath(rootPath, path));
|
||||
#endif
|
||||
|
||||
if (mTargetData[i].mType == Directory::FileOrDirectoryPath::eDirectoryPath) {
|
||||
RefPtr<Directory> directory =
|
||||
Directory::Create(mFileSystem->GetParentObject(), path,
|
||||
Directory::eNotDOMRootDirectory, mFileSystem);
|
||||
MOZ_ASSERT(directory);
|
||||
|
||||
// Propogate mFilter onto sub-Directory object:
|
||||
directory->SetContentFilters(mFilters);
|
||||
listing[i].SetAsDirectory() = directory;
|
||||
} else {
|
||||
MOZ_ASSERT(mTargetData[i].mType == Directory::FileOrDirectoryPath::eFilePath);
|
||||
|
||||
RefPtr<File> file =
|
||||
File::CreateFromFile(mFileSystem->GetParentObject(), path);
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
listing[i].SetAsFile() = file;
|
||||
}
|
||||
}
|
||||
|
||||
mPromise->MaybeResolve(listing);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GetDirectoryListingTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral("read");
|
||||
aAccess.AssignLiteral(GET_DIRECTORY_LISTING_PERMISSION);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -17,24 +17,18 @@ namespace dom {
|
||||
|
||||
class BlobImpl;
|
||||
|
||||
class GetDirectoryListingTask final : public FileSystemTaskBase
|
||||
class GetDirectoryListingTaskChild final : public FileSystemTaskChildBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<GetDirectoryListingTask>
|
||||
static already_AddRefed<GetDirectoryListingTaskChild>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
const nsAString& aFilters,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<GetDirectoryListingTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~GetDirectoryListingTask();
|
||||
~GetDirectoryListingTaskChild();
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetPromise();
|
||||
@@ -44,29 +38,19 @@ public:
|
||||
|
||||
private:
|
||||
// If aDirectoryOnly is set, we should ensure that the target is a directory.
|
||||
GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
const nsAString& aFilters);
|
||||
|
||||
GetDirectoryListingTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
GetDirectoryListingTaskChild(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
const nsAString& aFilters);
|
||||
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
||||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
@@ -80,6 +64,38 @@ private:
|
||||
FallibleTArray<Directory::FileOrDirectoryPath> mTargetData;
|
||||
};
|
||||
|
||||
class GetDirectoryListingTaskParent final : public FileSystemTaskParentBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<GetDirectoryListingTaskParent>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
private:
|
||||
GetDirectoryListingTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetDirectoryListingParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual nsresult
|
||||
IOWork() override;
|
||||
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
nsString mFilters;
|
||||
Directory::DirectoryType mType;
|
||||
|
||||
// We cannot store File or Directory objects bacause this object is created
|
||||
// on a different thread and File and Directory are not thread-safe.
|
||||
FallibleTArray<Directory::FileOrDirectoryPath> mTargetData;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
@@ -10,27 +10,35 @@
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/PFileSystemParams.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
#define GET_FILE_OR_DIRECTORY_PERMISSION "read"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* static */ already_AddRefed<GetFileOrDirectoryTask>
|
||||
GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
bool aDirectoryOnly,
|
||||
ErrorResult& aRv)
|
||||
/**
|
||||
* GetFileOrDirectoryTaskChild
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<GetFileOrDirectoryTaskChild>
|
||||
GetFileOrDirectoryTaskChild::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
bool aDirectoryOnly,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetFileOrDirectoryTask> task =
|
||||
new GetFileOrDirectoryTask(aFileSystem, aTargetPath, aType, aDirectoryOnly);
|
||||
RefPtr<GetFileOrDirectoryTaskChild> task =
|
||||
new GetFileOrDirectoryTaskChild(aFileSystem, aTargetPath, aType,
|
||||
aDirectoryOnly);
|
||||
|
||||
// aTargetPath can be null. In this case SetError will be called.
|
||||
|
||||
@@ -49,35 +57,11 @@ GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<GetFileOrDirectoryTask>
|
||||
GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetFileOrDirectoryTask> task =
|
||||
new GetFileOrDirectoryTask(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mType = aParam.isRoot()
|
||||
? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
bool aDirectoryOnly)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
GetFileOrDirectoryTaskChild::GetFileOrDirectoryTaskChild(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
bool aDirectoryOnly)
|
||||
: FileSystemTaskChildBase(aFileSystem)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mIsDirectory(aDirectoryOnly)
|
||||
, mType(aType)
|
||||
@@ -86,33 +70,21 @@ GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
, mIsDirectory(false)
|
||||
GetFileOrDirectoryTaskChild::~GetFileOrDirectoryTaskChild()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTask::~GetFileOrDirectoryTask()
|
||||
{
|
||||
MOZ_ASSERT(!mPromise || NS_IsMainThread(),
|
||||
"mPromise should be released on main thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetFileOrDirectoryTask::GetPromise()
|
||||
GetFileOrDirectoryTaskChild::GetPromise()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return RefPtr<Promise>(mPromise).forget();
|
||||
}
|
||||
|
||||
FileSystemParams
|
||||
GetFileOrDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
GetFileOrDirectoryTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
@@ -126,26 +98,9 @@ GetFileOrDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
mType == Directory::eDOMRootDirectory);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
GetFileOrDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemDirectoryResponse();
|
||||
}
|
||||
|
||||
if (mIsDirectory) {
|
||||
return FileSystemDirectoryResponse(path);
|
||||
}
|
||||
|
||||
return FileSystemFileResponse(path);
|
||||
}
|
||||
|
||||
void
|
||||
GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
GetFileOrDirectoryTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
switch (aValue.type()) {
|
||||
@@ -180,8 +135,104 @@ GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& a
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetFileOrDirectoryTaskChild::HandlerCallback()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsDirectory) {
|
||||
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
|
||||
mTargetPath,
|
||||
mType,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(dir);
|
||||
|
||||
mPromise->MaybeResolve(dir);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<File> file = File::CreateFromFile(mFileSystem->GetParentObject(),
|
||||
mTargetPath);
|
||||
mPromise->MaybeResolve(file);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GetFileOrDirectoryTaskChild::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(GET_FILE_OR_DIRECTORY_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* GetFileOrDirectoryTaskParent
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<GetFileOrDirectoryTaskParent>
|
||||
GetFileOrDirectoryTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<GetFileOrDirectoryTaskParent> task =
|
||||
new GetFileOrDirectoryTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mType = aParam.isRoot()
|
||||
? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
GetFileOrDirectoryTaskParent::GetFileOrDirectoryTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
|
||||
, mIsDirectory(false)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
GetFileOrDirectoryTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return FileSystemDirectoryResponse();
|
||||
}
|
||||
|
||||
if (mIsDirectory) {
|
||||
return FileSystemDirectoryResponse(path);
|
||||
}
|
||||
|
||||
return FileSystemFileResponse(path);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GetFileOrDirectoryTask::Work()
|
||||
GetFileOrDirectoryTaskParent::IOWork()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
@@ -245,42 +296,9 @@ GetFileOrDirectoryTask::Work()
|
||||
}
|
||||
|
||||
void
|
||||
GetFileOrDirectoryTask::HandlerCallback()
|
||||
GetFileOrDirectoryTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsDirectory) {
|
||||
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
|
||||
mTargetPath,
|
||||
mType,
|
||||
mFileSystem);
|
||||
MOZ_ASSERT(dir);
|
||||
|
||||
mPromise->MaybeResolve(dir);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<File> file = File::CreateFromFile(mFileSystem->GetParentObject(),
|
||||
mTargetPath);
|
||||
mPromise->MaybeResolve(file);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GetFileOrDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral("read");
|
||||
aAccess.AssignLiteral(GET_FILE_OR_DIRECTORY_PERMISSION);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -17,58 +17,42 @@ namespace dom {
|
||||
|
||||
class BlobImpl;
|
||||
|
||||
class GetFileOrDirectoryTask final : public FileSystemTaskBase
|
||||
class GetFileOrDirectoryTaskChild final : public FileSystemTaskChildBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<GetFileOrDirectoryTask>
|
||||
static already_AddRefed<GetFileOrDirectoryTaskChild>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
bool aDirectoryOnly,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<GetFileOrDirectoryTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~GetFileOrDirectoryTask();
|
||||
~GetFileOrDirectoryTaskChild();
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetPromise();
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
protected:
|
||||
virtual FileSystemParams
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
||||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
private:
|
||||
// If aDirectoryOnly is set, we should ensure that the target is a directory.
|
||||
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
bool aDirectoryOnly);
|
||||
|
||||
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
GetFileOrDirectoryTaskChild(FileSystemBase* aFileSystem,
|
||||
nsIFile* aTargetPath,
|
||||
Directory::DirectoryType aType,
|
||||
bool aDirectoryOnly);
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
@@ -78,6 +62,37 @@ private:
|
||||
Directory::DirectoryType mType;
|
||||
};
|
||||
|
||||
class GetFileOrDirectoryTaskParent final : public FileSystemTaskParentBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<GetFileOrDirectoryTaskParent>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
protected:
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual nsresult
|
||||
IOWork() override;
|
||||
|
||||
private:
|
||||
GetFileOrDirectoryTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemGetFileOrDirectoryParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
|
||||
// Whether we get a directory.
|
||||
bool mIsDirectory;
|
||||
Directory::DirectoryType mType;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
@@ -20,10 +20,7 @@ namespace dom {
|
||||
OSFileSystem::OSFileSystem(const nsAString& aRootDir)
|
||||
{
|
||||
mLocalOrDeviceStorageRootPath = aRootDir;
|
||||
|
||||
// Non-mobile devices don't have the concept of separate permissions to
|
||||
// access different parts of devices storage like Pictures, or Videos, etc.
|
||||
mRequiresPermissionChecks = false;
|
||||
mPermissionCheckType = ePermissionCheckNotRequired;
|
||||
|
||||
#ifdef DEBUG
|
||||
mPermission.AssignLiteral("never-used");
|
||||
@@ -33,6 +30,8 @@ OSFileSystem::OSFileSystem(const nsAString& aRootDir)
|
||||
already_AddRefed<FileSystemBase>
|
||||
OSFileSystem::Clone()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
RefPtr<OSFileSystem> fs = new OSFileSystem(mLocalOrDeviceStorageRootPath);
|
||||
if (mParent) {
|
||||
fs->Init(mParent);
|
||||
@@ -44,9 +43,10 @@ OSFileSystem::Clone()
|
||||
void
|
||||
OSFileSystem::Init(nsISupports* aParent)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!mParent, "No duple Init() calls");
|
||||
MOZ_ASSERT(aParent);
|
||||
|
||||
mParent = aParent;
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -58,13 +58,14 @@ OSFileSystem::Init(nsISupports* aParent)
|
||||
nsISupports*
|
||||
OSFileSystem::GetParentObject() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
AssertIsOnOwningThread();
|
||||
return mParent;
|
||||
}
|
||||
|
||||
void
|
||||
OSFileSystem::GetRootName(nsAString& aRetval) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
|
||||
}
|
||||
|
||||
@@ -91,12 +92,15 @@ OSFileSystem::IsSafeDirectory(Directory* aDir) const
|
||||
void
|
||||
OSFileSystem::Unlink()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
mParent = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
OSFileSystem::Traverse(nsCycleCollectionTraversalCallback &cb)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
OSFileSystem* tmp = this;
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent);
|
||||
}
|
||||
@@ -104,8 +108,23 @@ OSFileSystem::Traverse(nsCycleCollectionTraversalCallback &cb)
|
||||
void
|
||||
OSFileSystem::SerializeDOMPath(nsAString& aOutput) const
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
aOutput = mLocalOrDeviceStorageRootPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* OSFileSystemParent
|
||||
*/
|
||||
|
||||
OSFileSystemParent::OSFileSystemParent(const nsAString& aRootDir)
|
||||
{
|
||||
mLocalOrDeviceStorageRootPath = aRootDir;
|
||||
mPermissionCheckType = ePermissionCheckNotRequired;
|
||||
|
||||
#ifdef DEBUG
|
||||
mPermission.AssignLiteral("never-used");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -40,6 +40,9 @@ public:
|
||||
virtual void
|
||||
SerializeDOMPath(nsAString& aOutput) const override;
|
||||
|
||||
virtual bool
|
||||
ClonableToDifferentThreadOrProcess() const override { return true; }
|
||||
|
||||
// CC methods
|
||||
virtual void Unlink() override;
|
||||
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) override;
|
||||
@@ -47,7 +50,71 @@ public:
|
||||
private:
|
||||
virtual ~OSFileSystem() {}
|
||||
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
};
|
||||
|
||||
class OSFileSystemParent final : public FileSystemBase
|
||||
{
|
||||
public:
|
||||
explicit OSFileSystemParent(const nsAString& aRootDir);
|
||||
|
||||
// Overrides FileSystemBase
|
||||
|
||||
virtual already_AddRefed<FileSystemBase>
|
||||
Clone() override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual nsISupports*
|
||||
GetParentObject() const override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void
|
||||
GetRootName(nsAString& aRetval) const override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
}
|
||||
|
||||
virtual bool
|
||||
IsSafeFile(nsIFile* aFile) const override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
IsSafeDirectory(Directory* aDir) const override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void
|
||||
SerializeDOMPath(nsAString& aOutput) const override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
}
|
||||
|
||||
// CC methods
|
||||
virtual void
|
||||
Unlink() override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
}
|
||||
|
||||
virtual void
|
||||
Traverse(nsCycleCollectionTraversalCallback &cb) override
|
||||
{
|
||||
MOZ_CRASH("This should not be called on the PBackground thread.");
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~OSFileSystemParent() {}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/* 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 protocol PBlob;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct FileSystemCreateDirectoryParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
};
|
||||
|
||||
union FileSystemFileDataValue
|
||||
{
|
||||
uint8_t[];
|
||||
PBlob;
|
||||
};
|
||||
|
||||
struct FileSystemCreateFileParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
FileSystemFileDataValue data;
|
||||
bool replace;
|
||||
};
|
||||
|
||||
struct FileSystemGetDirectoryListingParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
bool isRoot;
|
||||
// 'filters' could be an array rather than a semicolon separated string
|
||||
// (we'd then use InfallibleTArray<nsString> internally), but that is
|
||||
// wasteful. E10s requires us to pass the filters over as a string anyway,
|
||||
// so avoiding using an array avoids serialization on the side passing the
|
||||
// filters. Since an nsString can share its buffer when copied,
|
||||
// using that instead of InfallibleTArray<nsString> makes copying the filters
|
||||
// around in any given process a bit more efficient too, since copying a
|
||||
// single nsString is cheaper than copying InfallibleTArray member data and
|
||||
// each nsString that it contains.
|
||||
nsString filters;
|
||||
};
|
||||
|
||||
struct FileSystemGetFileOrDirectoryParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
bool isRoot;
|
||||
};
|
||||
|
||||
struct FileSystemRemoveParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString directory;
|
||||
nsString targetDirectory;
|
||||
bool recursive;
|
||||
};
|
||||
|
||||
union FileSystemParams
|
||||
{
|
||||
FileSystemCreateDirectoryParams;
|
||||
FileSystemCreateFileParams;
|
||||
FileSystemGetDirectoryListingParams;
|
||||
FileSystemGetFileOrDirectoryParams;
|
||||
FileSystemRemoveParams;
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
@@ -4,8 +4,8 @@
|
||||
* 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 protocol PBackground;
|
||||
include protocol PBlob;
|
||||
include protocol PContent;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@@ -62,9 +62,9 @@ union FileSystemResponseValue
|
||||
FileSystemErrorResponse;
|
||||
};
|
||||
|
||||
sync protocol PFileSystemRequest
|
||||
protocol PFileSystemRequest
|
||||
{
|
||||
manager PContent;
|
||||
manager PBackground;
|
||||
|
||||
child:
|
||||
async __delete__(FileSystemResponseValue response);
|
||||
|
||||
+126
-109
@@ -9,6 +9,7 @@
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/PFileSystemParams.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
@@ -18,20 +19,24 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* static */ already_AddRefed<RemoveTask>
|
||||
RemoveTask::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aDirPath,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursive,
|
||||
ErrorResult& aRv)
|
||||
/**
|
||||
* RemoveTaskChild
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<RemoveTaskChild>
|
||||
RemoveTaskChild::Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aDirPath,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursive,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
MOZ_ASSERT(aDirPath);
|
||||
MOZ_ASSERT(aTargetPath);
|
||||
|
||||
RefPtr<RemoveTask> task =
|
||||
new RemoveTask(aFileSystem, aDirPath, aTargetPath, aRecursive);
|
||||
RefPtr<RemoveTaskChild> task =
|
||||
new RemoveTaskChild(aFileSystem, aDirPath, aTargetPath, aRecursive);
|
||||
|
||||
// aTargetPath can be null. In this case SetError will be called.
|
||||
|
||||
@@ -50,18 +55,112 @@ RemoveTask::Create(FileSystemBase* aFileSystem,
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<RemoveTask>
|
||||
RemoveTask::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
RemoveTaskChild::RemoveTaskChild(FileSystemBase* aFileSystem,
|
||||
nsIFile* aDirPath,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursive)
|
||||
: FileSystemTaskChildBase(aFileSystem)
|
||||
, mDirPath(aDirPath)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mRecursive(aRecursive)
|
||||
, mReturnValue(false)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
MOZ_ASSERT(aDirPath);
|
||||
MOZ_ASSERT(aTargetPath);
|
||||
}
|
||||
|
||||
RefPtr<RemoveTask> task =
|
||||
new RemoveTask(aFileSystem, aParam, aParent);
|
||||
RemoveTaskChild::~RemoveTaskChild()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
RemoveTaskChild::GetPromise()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return RefPtr<Promise>(mPromise).forget();
|
||||
}
|
||||
|
||||
FileSystemParams
|
||||
RemoveTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemRemoveParams param;
|
||||
param.filesystem() = aSerializedDOMPath;
|
||||
|
||||
aRv = mDirPath->GetPath(param.directory());
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return param;
|
||||
}
|
||||
|
||||
param.recursive() = mRecursive;
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return param;
|
||||
}
|
||||
|
||||
param.targetDirectory() = path;
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
void
|
||||
RemoveTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
FileSystemBooleanResponse r = aValue;
|
||||
mReturnValue = r.success();
|
||||
}
|
||||
|
||||
void
|
||||
RemoveTaskChild::HandlerCallback()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mPromise->MaybeResolve(mReturnValue);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
RemoveTaskChild::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral(REMOVE_TASK_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* RemoveTaskParent
|
||||
*/
|
||||
|
||||
/* static */ already_AddRefed<RemoveTaskParent>
|
||||
RemoveTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
RefPtr<RemoveTaskParent> task =
|
||||
new RemoveTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 directoryPath(aParam.directory());
|
||||
aRv = NS_NewNativeLocalFile(directoryPath, true,
|
||||
@@ -86,91 +185,28 @@ RemoveTask::Create(FileSystemBase* aFileSystem,
|
||||
return task.forget();
|
||||
}
|
||||
|
||||
RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aDirPath,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursive)
|
||||
: FileSystemTaskBase(aFileSystem)
|
||||
, mDirPath(aDirPath)
|
||||
, mTargetPath(aTargetPath)
|
||||
, mRecursive(aRecursive)
|
||||
, mReturnValue(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
MOZ_ASSERT(aDirPath);
|
||||
MOZ_ASSERT(aTargetPath);
|
||||
}
|
||||
|
||||
RemoveTask::RemoveTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskBase(aFileSystem, aParam, aParent)
|
||||
RemoveTaskParent::RemoveTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent)
|
||||
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
|
||||
, mRecursive(false)
|
||||
, mReturnValue(false)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
}
|
||||
|
||||
RemoveTask::~RemoveTask()
|
||||
{
|
||||
MOZ_ASSERT(!mPromise || NS_IsMainThread(),
|
||||
"mPromise should be released on main thread!");
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
RemoveTask::GetPromise()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
return RefPtr<Promise>(mPromise).forget();
|
||||
}
|
||||
|
||||
FileSystemParams
|
||||
RemoveTask::GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemRemoveParams param;
|
||||
param.filesystem() = aSerializedDOMPath;
|
||||
|
||||
aRv = mDirPath->GetPath(param.directory());
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return param;
|
||||
}
|
||||
|
||||
param.recursive() = mRecursive;
|
||||
|
||||
nsAutoString path;
|
||||
aRv = mTargetPath->GetPath(path);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return param;
|
||||
}
|
||||
|
||||
param.targetDirectory() = path;
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
FileSystemResponseValue
|
||||
RemoveTask::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
RemoveTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
return FileSystemBooleanResponse(mReturnValue);
|
||||
}
|
||||
|
||||
void
|
||||
RemoveTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
FileSystemBooleanResponse r = aValue;
|
||||
mReturnValue = r.success();
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemoveTask::Work()
|
||||
RemoveTaskParent::IOWork()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"Only call from parent process!");
|
||||
@@ -214,28 +250,9 @@ RemoveTask::Work()
|
||||
}
|
||||
|
||||
void
|
||||
RemoveTask::HandlerCallback()
|
||||
RemoveTaskParent::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
|
||||
if (mFileSystem->IsShutdown()) {
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasError()) {
|
||||
mPromise->MaybeReject(mErrorValue);
|
||||
mPromise = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mPromise->MaybeResolve(mReturnValue);
|
||||
mPromise = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
RemoveTask::GetPermissionAccessType(nsCString& aAccess) const
|
||||
{
|
||||
aAccess.AssignLiteral("write");
|
||||
aAccess.AssignLiteral(REMOVE_TASK_PERMISSION);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
+43
-23
@@ -11,30 +11,26 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
#define REMOVE_TASK_PERMISSION "write"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class BlobImpl;
|
||||
class Promise;
|
||||
|
||||
class RemoveTask final : public FileSystemTaskBase
|
||||
class RemoveTaskChild final : public FileSystemTaskChildBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<RemoveTask>
|
||||
static already_AddRefed<RemoveTaskChild>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
nsIFile* aDirPath,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursive,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<RemoveTask>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual
|
||||
~RemoveTask();
|
||||
~RemoveTaskChild();
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetPromise();
|
||||
@@ -47,28 +43,18 @@ protected:
|
||||
GetRequestParams(const nsString& aSerializedDOMPath,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual void
|
||||
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual nsresult
|
||||
Work() override;
|
||||
|
||||
virtual void
|
||||
HandlerCallback() override;
|
||||
|
||||
private:
|
||||
RemoveTask(FileSystemBase* aFileSystem,
|
||||
nsIFile* aDirPath,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursive);
|
||||
|
||||
RemoveTask(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
RemoveTaskChild(FileSystemBase* aFileSystem,
|
||||
nsIFile* aDirPath,
|
||||
nsIFile* aTargetPath,
|
||||
bool aRecursive);
|
||||
|
||||
RefPtr<Promise> mPromise;
|
||||
|
||||
@@ -82,6 +68,40 @@ private:
|
||||
bool mReturnValue;
|
||||
};
|
||||
|
||||
class RemoveTaskParent final : public FileSystemTaskParentBase
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<RemoveTaskParent>
|
||||
Create(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual void
|
||||
GetPermissionAccessType(nsCString& aAccess) const override;
|
||||
|
||||
protected:
|
||||
virtual FileSystemResponseValue
|
||||
GetSuccessRequestResult(ErrorResult& aRv) const override;
|
||||
|
||||
virtual nsresult
|
||||
IOWork() override;
|
||||
|
||||
private:
|
||||
RemoveTaskParent(FileSystemBase* aFileSystem,
|
||||
const FileSystemRemoveParams& aParam,
|
||||
FileSystemRequestParent* aParent);
|
||||
|
||||
// This path is the Directory::mFile.
|
||||
nsCOMPtr<nsIFile> mDirPath;
|
||||
|
||||
// This is what we want to remove. mTargetPath is discendant path of mDirPath.
|
||||
nsCOMPtr<nsIFile> mTargetPath;
|
||||
|
||||
bool mRecursive;
|
||||
bool mReturnValue;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ UNIFIED_SOURCES += [
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'PFileSystemParams.ipdlh',
|
||||
'PFileSystemRequest.ipdl',
|
||||
]
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
script_fileList.js
|
||||
worker_basic.js
|
||||
|
||||
[test_basic.html]
|
||||
[test_worker_basic.html]
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Directory API in workers</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<input id="fileList" type="file"></input>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
function create_fileList() {
|
||||
var url = SimpleTest.getTestFileURL("script_fileList.js");
|
||||
var script = SpecialPowers.loadChromeScript(url);
|
||||
|
||||
function onOpened(message) {
|
||||
var fileList = document.getElementById('fileList');
|
||||
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
|
||||
|
||||
// Just a simple test
|
||||
is(fileList.files.length, 1, "Filelist has 1 element");
|
||||
ok(fileList.files[0] instanceof Directory, "We have a directory.");
|
||||
|
||||
script.destroy();
|
||||
next();
|
||||
}
|
||||
|
||||
script.addMessageListener("dir.opened", onOpened);
|
||||
script.sendAsyncMessage("dir.open", { path: 'ProfD' });
|
||||
}
|
||||
|
||||
function test_worker() {
|
||||
var fileList = document.getElementById('fileList');
|
||||
|
||||
var worker = new Worker('worker_basic.js');
|
||||
worker.onmessage = function(e) {
|
||||
if (e.data.type == 'finish') {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.data.type == 'test') {
|
||||
ok(e.data.test, e.data.message);
|
||||
}
|
||||
}
|
||||
|
||||
worker.postMessage(fileList.files);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
create_fileList,
|
||||
test_worker,
|
||||
];
|
||||
|
||||
function next() {
|
||||
if (!tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
next();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,58 @@
|
||||
function finish() {
|
||||
postMessage({ type: 'finish' });
|
||||
}
|
||||
|
||||
function ok(a, msg) {
|
||||
postMessage({ type: 'test', test: !!a, message: msg });
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
ok(a === b, msg);
|
||||
}
|
||||
|
||||
function isnot(a, b, msg) {
|
||||
ok(a != b, msg);
|
||||
}
|
||||
|
||||
function checkSubDir(dir) {
|
||||
return dir.getFilesAndDirectories().then(
|
||||
function(data) {
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
|
||||
if (data[i] instanceof Directory) {
|
||||
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
|
||||
isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
|
||||
isnot(data[i].path, dir.path, "Subdirectory path should contain the parent path.");
|
||||
is(data[i].path,dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
onmessage = function(e) {
|
||||
var fileList = e.data;
|
||||
ok(fileList instanceof FileList, "This is a fileList.");
|
||||
is(fileList.length, 1, "We want just 1 element.");
|
||||
ok(fileList[0] instanceof Directory, "This is a directory.");
|
||||
|
||||
fileList[0].getFilesAndDirectories().then(
|
||||
function(data) {
|
||||
ok(data.length, "We should have some data.");
|
||||
var promises = [];
|
||||
for (var i = 0; i < data.length; ++i) {
|
||||
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
|
||||
if (data[i] instanceof Directory) {
|
||||
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
|
||||
is(data[i].path, '/' + data[i].name, "Subdirectory path should be called '/' + leafname");
|
||||
promises.push(checkSubDir(data[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
},
|
||||
function() {
|
||||
ok(false, "Something when wrong");
|
||||
}
|
||||
).then(finish);
|
||||
}
|
||||
@@ -297,7 +297,7 @@ HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
eKeyPress == aVisitor.mEvent->mMessage) ||
|
||||
(keyEvent->keyCode == NS_VK_SPACE &&
|
||||
eKeyUp == aVisitor.mEvent->mMessage)) {
|
||||
DispatchSimulatedClick(this, aVisitor.mEvent->mFlags.mIsTrusted,
|
||||
DispatchSimulatedClick(this, aVisitor.mEvent->IsTrusted(),
|
||||
aVisitor.mPresContext);
|
||||
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
@@ -308,7 +308,7 @@ HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
||||
if (mouseEvent->button == WidgetMouseEvent::eLeftButton) {
|
||||
if (mouseEvent->mFlags.mIsTrusted) {
|
||||
if (mouseEvent->IsTrusted()) {
|
||||
EventStateManager* esm =
|
||||
aVisitor.mPresContext->EventStateManager();
|
||||
EventStateManager::SetActiveManager(
|
||||
|
||||
@@ -1262,7 +1262,7 @@ HTMLCanvasElement::OnVisibilityChange()
|
||||
}
|
||||
|
||||
if (mOffscreenCanvas) {
|
||||
class Runnable final : public nsCancelableRunnable
|
||||
class Runnable final : public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit Runnable(AsyncCanvasRenderer* aRenderer)
|
||||
@@ -1304,7 +1304,7 @@ void
|
||||
HTMLCanvasElement::OnMemoryPressure()
|
||||
{
|
||||
if (mOffscreenCanvas) {
|
||||
class Runnable final : public nsCancelableRunnable
|
||||
class Runnable final : public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit Runnable(AsyncCanvasRenderer* aRenderer)
|
||||
|
||||
@@ -527,7 +527,7 @@ HTMLFormElement::WillHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
aVisitor.mEvent->mMessage == eFormReset) &&
|
||||
aVisitor.mEvent->mFlags.mInBubblingPhase &&
|
||||
aVisitor.mEvent->originalTarget != static_cast<nsIContent*>(this)) {
|
||||
aVisitor.mEvent->mFlags.mPropagationStopped = true;
|
||||
aVisitor.mEvent->StopPropagation();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -3361,8 +3361,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
if (mType == NS_FORM_INPUT_NUMBER &&
|
||||
aVisitor.mEvent->mFlags.mIsTrusted) {
|
||||
if (mType == NS_FORM_INPUT_NUMBER && aVisitor.mEvent->IsTrusted()) {
|
||||
if (mNumberControlSpinnerIsSpinning) {
|
||||
// If the timer is running the user has depressed the mouse on one of the
|
||||
// spin buttons. If the mouse exits the button we either want to reverse
|
||||
@@ -3447,7 +3446,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
// We do this after calling the base class' PreHandleEvent so that
|
||||
// nsIContent::PreHandleEvent doesn't reset any change we make to mCanHandle.
|
||||
if (mType == NS_FORM_INPUT_NUMBER &&
|
||||
aVisitor.mEvent->mFlags.mIsTrusted &&
|
||||
aVisitor.mEvent->IsTrusted() &&
|
||||
aVisitor.mEvent->originalTarget != this) {
|
||||
// <input type=number> has an anonymous <input type=text> descendant. If
|
||||
// 'input' or 'change' events are fired at that text control then we need
|
||||
@@ -3724,7 +3723,7 @@ HTMLInputElement::MaybeInitPickers(EventChainPostVisitor& aVisitor)
|
||||
// - it's the left mouse button.
|
||||
// We do not prevent non-trusted click because authors can already use
|
||||
// .click(). However, the pickers will follow the rules of popup-blocking.
|
||||
if (aVisitor.mEvent->mFlags.mDefaultPrevented) {
|
||||
if (aVisitor.mEvent->DefaultPrevented()) {
|
||||
return NS_OK;
|
||||
}
|
||||
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
||||
@@ -3898,7 +3897,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
|
||||
if (mType == NS_FORM_INPUT_NUMBER &&
|
||||
keyEvent && keyEvent->mMessage == eKeyPress &&
|
||||
aVisitor.mEvent->mFlags.mIsTrusted &&
|
||||
aVisitor.mEvent->IsTrusted() &&
|
||||
(keyEvent->keyCode == NS_VK_UP || keyEvent->keyCode == NS_VK_DOWN) &&
|
||||
!(keyEvent->IsShift() || keyEvent->IsControl() ||
|
||||
keyEvent->IsAlt() || keyEvent->IsMeta() ||
|
||||
@@ -3915,7 +3914,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
// the editor's handling of up/down keypress events. For that reason we
|
||||
// just ignore aVisitor.mEventStatus here and go ahead and handle the
|
||||
// event to increase/decrease the value of the number control.
|
||||
if (!aVisitor.mEvent->mFlags.mDefaultPreventedByContent && IsMutable()) {
|
||||
if (!aVisitor.mEvent->DefaultPreventedByContent() && IsMutable()) {
|
||||
StepNumberControlForUserEvent(keyEvent->keyCode == NS_VK_UP ? 1 : -1);
|
||||
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
@@ -3976,7 +3975,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
case NS_FORM_INPUT_IMAGE: // Bug 34418
|
||||
case NS_FORM_INPUT_COLOR:
|
||||
{
|
||||
DispatchSimulatedClick(this, aVisitor.mEvent->mFlags.mIsTrusted,
|
||||
DispatchSimulatedClick(this, aVisitor.mEvent->IsTrusted(),
|
||||
aVisitor.mPresContext);
|
||||
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
} // case
|
||||
@@ -4005,7 +4004,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
rv = selectedRadioButton->Focus();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = DispatchSimulatedClick(selectedRadioButton,
|
||||
aVisitor.mEvent->mFlags.mIsTrusted,
|
||||
aVisitor.mEvent->IsTrusted(),
|
||||
aVisitor.mPresContext);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
@@ -4117,8 +4116,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mType == NS_FORM_INPUT_NUMBER &&
|
||||
aVisitor.mEvent->mFlags.mIsTrusted) {
|
||||
if (mType == NS_FORM_INPUT_NUMBER && aVisitor.mEvent->IsTrusted()) {
|
||||
if (mouseEvent->button == WidgetMouseEvent::eLeftButton &&
|
||||
!(mouseEvent->IsShift() || mouseEvent->IsControl() ||
|
||||
mouseEvent->IsAlt() || mouseEvent->IsMeta() ||
|
||||
@@ -5059,13 +5057,6 @@ HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv)
|
||||
|
||||
for (uint32_t i = 0; i < filesAndDirs.Length(); ++i) {
|
||||
if (filesAndDirs[i].IsDirectory()) {
|
||||
#if defined(ANDROID) || defined(MOZ_B2G)
|
||||
MOZ_ASSERT(false,
|
||||
"Directory picking should have been redirected to normal "
|
||||
"file picking for platforms that don't have a directory "
|
||||
"picker");
|
||||
#endif
|
||||
|
||||
RefPtr<Directory> directory = filesAndDirs[i].GetAsDirectory();
|
||||
|
||||
// In future we could refactor SetFilePickerFiltersFromAccept to return a
|
||||
|
||||
@@ -212,7 +212,7 @@ void
|
||||
HTMLObjectElement::HandleFocusBlurPlugin(Element* aElement,
|
||||
WidgetEvent* aEvent)
|
||||
{
|
||||
if (!aEvent->mFlags.mIsTrusted) {
|
||||
if (!aEvent->IsTrusted()) {
|
||||
return;
|
||||
}
|
||||
switch (aEvent->mMessage) {
|
||||
|
||||
@@ -2280,7 +2280,7 @@ nsGenericHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsresult
|
||||
nsGenericHTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
if (aVisitor.mEvent->mFlags.mIsTrusted) {
|
||||
if (aVisitor.mEvent->IsTrusted()) {
|
||||
switch (aVisitor.mEvent->mMessage) {
|
||||
case eFocus: {
|
||||
// Check to see if focus has bubbled up from a form control's
|
||||
|
||||
@@ -2531,9 +2531,9 @@ BackgroundRequestChild::Recv__delete__(const RequestResponse& aResponse)
|
||||
******************************************************************************/
|
||||
|
||||
// Does not need to be threadsafe since this only runs on one thread, but
|
||||
// inheriting from nsCancelableRunnable is easy.
|
||||
// inheriting from CancelableRunnable is easy.
|
||||
class BackgroundCursorChild::DelayedActionRunnable final
|
||||
: public nsCancelableRunnable
|
||||
: public CancelableRunnable
|
||||
{
|
||||
using ActionFunc = void (BackgroundCursorChild::*)();
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ const char kMemoryPressureObserverTopic[] = "memory-pressure";
|
||||
const char kWindowObserverTopic[] = "inner-window-destroyed";
|
||||
|
||||
class CancelableRunnableWrapper final
|
||||
: public nsCancelableRunnable
|
||||
: public CancelableRunnable
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ interface nsIPushNotifier : nsISupports
|
||||
[array, size_is(dataLen)] in uint8_t data);
|
||||
|
||||
void notifySubscriptionChange(in ACString scope, in nsIPrincipal principal);
|
||||
|
||||
void notifyError(in ACString scope, in nsIPrincipal principal,
|
||||
in DOMString message, in uint32_t flags);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -212,7 +212,7 @@ EventTargetIsOnCurrentThread(nsIEventTarget* aEventTarget)
|
||||
}
|
||||
|
||||
class CancelableRunnableWrapper final
|
||||
: public nsCancelableRunnable
|
||||
: public CancelableRunnable
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
#ifdef DEBUG
|
||||
@@ -241,7 +241,7 @@ private:
|
||||
nsresult Cancel() override;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(CancelableRunnableWrapper, nsCancelableRunnable)
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(CancelableRunnableWrapper, CancelableRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
CancelableRunnableWrapper::Run()
|
||||
|
||||
@@ -60,11 +60,11 @@ ContentBridgeChild::DeferredDestroy()
|
||||
|
||||
bool
|
||||
ContentBridgeChild::RecvAsyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData,
|
||||
InfallibleTArray<jsipc::CpowEntry>&& aCpows,
|
||||
const IPC::Principal& aPrincipal)
|
||||
const IPC::Principal& aPrincipal,
|
||||
const ClonedMessageData& aData)
|
||||
{
|
||||
return nsIContentChild::RecvAsyncMessage(aMsg, aData, Move(aCpows), aPrincipal);
|
||||
return nsIContentChild::RecvAsyncMessage(aMsg, Move(aCpows), aPrincipal, aData);
|
||||
}
|
||||
|
||||
PBlobChild*
|
||||
|
||||
@@ -28,9 +28,9 @@ public:
|
||||
void DeferredDestroy();
|
||||
|
||||
virtual bool RecvAsyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData,
|
||||
InfallibleTArray<jsipc::CpowEntry>&& aCpows,
|
||||
const IPC::Principal& aPrincipal) override;
|
||||
const IPC::Principal& aPrincipal,
|
||||
const ClonedMessageData& aData) override;
|
||||
|
||||
virtual PBlobChild*
|
||||
SendPBlobConstructor(PBlobChild* actor,
|
||||
|
||||
@@ -84,12 +84,12 @@ ContentBridgeParent::RecvSyncMessage(const nsString& aMsg,
|
||||
|
||||
bool
|
||||
ContentBridgeParent::RecvAsyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData,
|
||||
InfallibleTArray<jsipc::CpowEntry>&& aCpows,
|
||||
const IPC::Principal& aPrincipal)
|
||||
const IPC::Principal& aPrincipal,
|
||||
const ClonedMessageData& aData)
|
||||
{
|
||||
return nsIContentParent::RecvAsyncMessage(aMsg, aData, Move(aCpows),
|
||||
aPrincipal);
|
||||
return nsIContentParent::RecvAsyncMessage(aMsg, Move(aCpows),
|
||||
aPrincipal, aData);
|
||||
}
|
||||
|
||||
PBlobParent*
|
||||
|
||||
@@ -88,9 +88,9 @@ protected:
|
||||
nsTArray<StructuredCloneData>* aRetvals) override;
|
||||
|
||||
virtual bool RecvAsyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData,
|
||||
InfallibleTArray<jsipc::CpowEntry>&& aCpows,
|
||||
const IPC::Principal& aPrincipal) override;
|
||||
const IPC::Principal& aPrincipal,
|
||||
const ClonedMessageData& aData) override;
|
||||
|
||||
virtual jsipc::PJavaScriptParent* AllocPJavaScriptParent() override;
|
||||
|
||||
|
||||
+31
-30
@@ -174,8 +174,6 @@
|
||||
#include "mozilla/dom/mobileconnection/MobileConnectionChild.h"
|
||||
#include "mozilla/dom/mobilemessage/SmsChild.h"
|
||||
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
|
||||
#include "mozilla/dom/PFileSystemRequestChild.h"
|
||||
#include "mozilla/dom/FileSystemTaskBase.h"
|
||||
#include "mozilla/dom/bluetooth/PBluetoothChild.h"
|
||||
#include "mozilla/dom/PFMRadioChild.h"
|
||||
#include "mozilla/dom/PPresentationChild.h"
|
||||
@@ -850,6 +848,10 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
||||
nsTArray<FrameScriptInfo> frameScripts;
|
||||
nsCString urlToLoad;
|
||||
|
||||
PRenderFrameChild* renderFrame = newChild->SendPRenderFrameConstructor();
|
||||
TextureFactoryIdentifier textureFactoryIdentifier;
|
||||
uint64_t layersId = 0;
|
||||
|
||||
if (aIframeMoz) {
|
||||
MOZ_ASSERT(aTabOpener);
|
||||
newChild->SendBrowserFrameOpenWindow(aTabOpener, NS_ConvertUTF8toUTF16(url),
|
||||
@@ -883,7 +885,7 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
if (!SendCreateWindow(aTabOpener, newChild,
|
||||
if (!SendCreateWindow(aTabOpener, newChild, renderFrame,
|
||||
aChromeFlags, aCalledFromJS, aPositionSpecified,
|
||||
aSizeSpecified, url,
|
||||
name, features,
|
||||
@@ -895,25 +897,25 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
||||
&rv,
|
||||
aWindowIsNew,
|
||||
&frameScripts,
|
||||
&urlToLoad)) {
|
||||
&urlToLoad,
|
||||
&textureFactoryIdentifier,
|
||||
&layersId)) {
|
||||
PRenderFrameChild::Send__delete__(renderFrame);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
PRenderFrameChild::Send__delete__(renderFrame);
|
||||
PBrowserChild::Send__delete__(newChild);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
if (!*aWindowIsNew) {
|
||||
PRenderFrameChild::Send__delete__(renderFrame);
|
||||
PBrowserChild::Send__delete__(newChild);
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
TextureFactoryIdentifier textureFactoryIdentifier;
|
||||
uint64_t layersId = 0;
|
||||
PRenderFrameChild* renderFrame = newChild->SendPRenderFrameConstructor();
|
||||
newChild->SendGetRenderFrameInfo(renderFrame,
|
||||
&textureFactoryIdentifier,
|
||||
&layersId);
|
||||
if (layersId == 0) { // if renderFrame is invalid.
|
||||
PRenderFrameChild::Send__delete__(renderFrame);
|
||||
renderFrame = nullptr;
|
||||
@@ -1821,24 +1823,6 @@ ContentChild::DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild* aDev
|
||||
return true;
|
||||
}
|
||||
|
||||
PFileSystemRequestChild*
|
||||
ContentChild::AllocPFileSystemRequestChild(const FileSystemParams& aParams)
|
||||
{
|
||||
MOZ_CRASH("Should never get here!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPFileSystemRequestChild(PFileSystemRequestChild* aFileSystem)
|
||||
{
|
||||
mozilla::dom::FileSystemTaskBase* child =
|
||||
static_cast<mozilla::dom::FileSystemTaskBase*>(aFileSystem);
|
||||
// The reference is increased in FileSystemTaskBase::Start of
|
||||
// FileSystemTaskBase.cpp. We should decrease it after IPC.
|
||||
NS_RELEASE(child);
|
||||
return true;
|
||||
}
|
||||
|
||||
PMobileConnectionChild*
|
||||
ContentChild::SendPMobileConnectionConstructor(PMobileConnectionChild* aActor,
|
||||
const uint32_t& aClientId)
|
||||
@@ -2426,9 +2410,9 @@ ContentChild::RecvLoadProcessScript(const nsString& aURL)
|
||||
|
||||
bool
|
||||
ContentChild::RecvAsyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData,
|
||||
InfallibleTArray<CpowEntry>&& aCpows,
|
||||
const IPC::Principal& aPrincipal)
|
||||
const IPC::Principal& aPrincipal,
|
||||
const ClonedMessageData& aData)
|
||||
{
|
||||
RefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::GetChildProcessManager();
|
||||
if (cpm) {
|
||||
@@ -3287,5 +3271,22 @@ ContentChild::RecvPushSubscriptionChange(const nsCString& aScope,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvPushError(const nsCString& aScope, const nsString& aMessage,
|
||||
const uint32_t& aFlags)
|
||||
{
|
||||
#ifndef MOZ_SIMPLEPUSH
|
||||
nsCOMPtr<nsIPushNotifier> pushNotifierIface =
|
||||
do_GetService("@mozilla.org/push/Notifier;1");
|
||||
if (NS_WARN_IF(!pushNotifierIface)) {
|
||||
return true;
|
||||
}
|
||||
PushNotifier* pushNotifier =
|
||||
static_cast<PushNotifier*>(pushNotifierIface.get());
|
||||
pushNotifier->NotifyErrorWorkers(aScope, aMessage, aFlags);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -192,12 +192,6 @@ public:
|
||||
virtual bool
|
||||
DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild*) override;
|
||||
|
||||
virtual PFileSystemRequestChild*
|
||||
AllocPFileSystemRequestChild(const FileSystemParams&) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPFileSystemRequestChild(PFileSystemRequestChild*) override;
|
||||
|
||||
virtual PBlobChild*
|
||||
AllocPBlobChild(const BlobConstructorParams& aParams) override;
|
||||
|
||||
@@ -419,9 +413,9 @@ public:
|
||||
virtual bool RecvLoadProcessScript(const nsString& aURL) override;
|
||||
|
||||
virtual bool RecvAsyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData,
|
||||
InfallibleTArray<CpowEntry>&& aCpows,
|
||||
const IPC::Principal& aPrincipal) override;
|
||||
const IPC::Principal& aPrincipal,
|
||||
const ClonedMessageData& aData) override;
|
||||
|
||||
virtual bool RecvGeolocationUpdate(const GeoPosition& somewhere) override;
|
||||
|
||||
@@ -534,6 +528,10 @@ public:
|
||||
RecvPushSubscriptionChange(const nsCString& aScope,
|
||||
const IPC::Principal& aPrincipal) override;
|
||||
|
||||
virtual bool
|
||||
RecvPushError(const nsCString& aScope, const nsString& aMessage,
|
||||
const uint32_t& aFlags) override;
|
||||
|
||||
// Get the directory for IndexedDB files. We query the parent for this and
|
||||
// cache the value
|
||||
nsString &GetIndexedDBPath();
|
||||
|
||||
+37
-49
@@ -47,7 +47,6 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/ExternalHelperAppParent.h"
|
||||
#include "mozilla/dom/FileSystemRequestParent.h"
|
||||
#include "mozilla/dom/GeolocationBinding.h"
|
||||
#include "mozilla/dom/Notification.h"
|
||||
#include "mozilla/dom/NuwaParent.h"
|
||||
@@ -85,6 +84,7 @@
|
||||
#include "mozilla/layers/CompositorBridgeParent.h"
|
||||
#include "mozilla/layers/ImageBridgeParent.h"
|
||||
#include "mozilla/layers/SharedBufferManagerParent.h"
|
||||
#include "mozilla/layout/RenderFrameParent.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/media/MediaParent.h"
|
||||
#include "mozilla/Move.h"
|
||||
@@ -297,6 +297,7 @@ using namespace mozilla::gmp;
|
||||
using namespace mozilla::hal;
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::layout;
|
||||
using namespace mozilla::net;
|
||||
using namespace mozilla::jsipc;
|
||||
using namespace mozilla::psm;
|
||||
@@ -1176,7 +1177,6 @@ ContentParent::CreateBrowserOrApp(const TabContext& aContext,
|
||||
RefPtr<TabParent> tp(new TabParent(constructorSender, tabId,
|
||||
aContext, chromeFlags));
|
||||
tp->SetInitedByParent();
|
||||
tp->SetOwnerElement(aFrameElement);
|
||||
|
||||
PBrowserParent* browser =
|
||||
constructorSender->SendPBrowserConstructor(
|
||||
@@ -1187,7 +1187,10 @@ ContentParent::CreateBrowserOrApp(const TabContext& aContext,
|
||||
constructorSender->ChildID(),
|
||||
constructorSender->IsForApp(),
|
||||
constructorSender->IsForBrowser());
|
||||
return TabParent::GetFrom(browser);
|
||||
|
||||
RefPtr<TabParent> constructedTabParent = TabParent::GetFrom(browser);
|
||||
constructedTabParent->SetOwnerElement(aFrameElement);
|
||||
return constructedTabParent;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1285,7 +1288,6 @@ ContentParent::CreateBrowserOrApp(const TabContext& aContext,
|
||||
|
||||
RefPtr<TabParent> tp = new TabParent(parent, tabId, aContext, chromeFlags);
|
||||
tp->SetInitedByParent();
|
||||
tp->SetOwnerElement(aFrameElement);
|
||||
PBrowserParent* browser = parent->SendPBrowserConstructor(
|
||||
// DeallocPBrowserParent() releases this ref.
|
||||
RefPtr<TabParent>(tp).forget().take(),
|
||||
@@ -1296,6 +1298,11 @@ ContentParent::CreateBrowserOrApp(const TabContext& aContext,
|
||||
parent->IsForApp(),
|
||||
parent->IsForBrowser());
|
||||
|
||||
if (browser) {
|
||||
RefPtr<TabParent> constructedTabParent = TabParent::GetFrom(browser);
|
||||
constructedTabParent->SetOwnerElement(aFrameElement);
|
||||
}
|
||||
|
||||
if (isInContentProcess) {
|
||||
// Just return directly without the following check in content process.
|
||||
return TabParent::GetFrom(browser);
|
||||
@@ -3496,24 +3503,6 @@ ContentParent::DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent* d
|
||||
return true;
|
||||
}
|
||||
|
||||
PFileSystemRequestParent*
|
||||
ContentParent::AllocPFileSystemRequestParent(const FileSystemParams& aParams)
|
||||
{
|
||||
RefPtr<FileSystemRequestParent> result = new FileSystemRequestParent();
|
||||
if (!result->Dispatch(this, aParams)) {
|
||||
return nullptr;
|
||||
}
|
||||
return result.forget().take();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPFileSystemRequestParent(PFileSystemRequestParent* doomed)
|
||||
{
|
||||
FileSystemRequestParent* parent = static_cast<FileSystemRequestParent*>(doomed);
|
||||
NS_RELEASE(parent);
|
||||
return true;
|
||||
}
|
||||
|
||||
PBlobParent*
|
||||
ContentParent::AllocPBlobParent(const BlobConstructorParams& aParams)
|
||||
{
|
||||
@@ -4240,25 +4229,6 @@ ContentParent::RecvSetURITitle(const URIParams& uri,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvGetRandomValues(const uint32_t& length,
|
||||
InfallibleTArray<uint8_t>* randomValues)
|
||||
{
|
||||
uint8_t* buf = Crypto::GetRandomValues(length);
|
||||
if (!buf) {
|
||||
return true;
|
||||
}
|
||||
|
||||
randomValues->SetCapacity(length);
|
||||
randomValues->SetLength(length);
|
||||
|
||||
memcpy(randomValues->Elements(), buf, length);
|
||||
|
||||
NS_Free(buf);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvGetSystemMemory(const uint64_t& aGetterId)
|
||||
{
|
||||
@@ -4423,12 +4393,12 @@ ContentParent::RecvRpcMessage(const nsString& aMsg,
|
||||
|
||||
bool
|
||||
ContentParent::RecvAsyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData,
|
||||
InfallibleTArray<CpowEntry>&& aCpows,
|
||||
const IPC::Principal& aPrincipal)
|
||||
const IPC::Principal& aPrincipal,
|
||||
const ClonedMessageData& aData)
|
||||
{
|
||||
return nsIContentParent::RecvAsyncMessage(aMsg, aData, Move(aCpows),
|
||||
aPrincipal);
|
||||
return nsIContentParent::RecvAsyncMessage(aMsg, Move(aCpows), aPrincipal,
|
||||
aData);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -4672,7 +4642,7 @@ ContentParent::DoSendAsyncMessage(JSContext* aCx,
|
||||
// Nuwa won't receive frame messages after it is frozen.
|
||||
return NS_OK;
|
||||
}
|
||||
if (!SendAsyncMessage(nsString(aMessage), data, cpows, Principal(aPrincipal))) {
|
||||
if (!SendAsyncMessage(nsString(aMessage), cpows, Principal(aPrincipal), data)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
return NS_OK;
|
||||
@@ -4897,6 +4867,7 @@ ContentParent::RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
|
||||
bool
|
||||
ContentParent::RecvGetGraphicsFeatureStatus(const int32_t& aFeature,
|
||||
int32_t* aStatus,
|
||||
nsCString* aFailureId,
|
||||
bool* aSuccess)
|
||||
{
|
||||
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
|
||||
@@ -4905,7 +4876,7 @@ ContentParent::RecvGetGraphicsFeatureStatus(const int32_t& aFeature,
|
||||
return true;
|
||||
}
|
||||
|
||||
*aSuccess = NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aStatus));
|
||||
*aSuccess = NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, *aFailureId, aStatus));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5378,6 +5349,7 @@ ContentParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestP
|
||||
bool
|
||||
ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
|
||||
PBrowserParent* aNewTab,
|
||||
PRenderFrameParent* aRenderFrame,
|
||||
const uint32_t& aChromeFlags,
|
||||
const bool& aCalledFromJS,
|
||||
const bool& aPositionSpecified,
|
||||
@@ -5391,7 +5363,9 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
|
||||
nsresult* aResult,
|
||||
bool* aWindowIsNew,
|
||||
InfallibleTArray<FrameScriptInfo>* aFrameScripts,
|
||||
nsCString* aURLToLoad)
|
||||
nsCString* aURLToLoad,
|
||||
TextureFactoryIdentifier* aTextureFactoryIdentifier,
|
||||
uint64_t* aLayersId)
|
||||
{
|
||||
// We always expect to open a new window here. If we don't, it's an error.
|
||||
*aWindowIsNew = true;
|
||||
@@ -5480,7 +5454,7 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
|
||||
// Opening new tabs is the easy case...
|
||||
if (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB) {
|
||||
if (NS_WARN_IF(!browserDOMWin)) {
|
||||
*aResult = NS_ERROR_FAILURE;
|
||||
*aResult = NS_ERROR_ABORT;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5506,6 +5480,13 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
|
||||
}
|
||||
|
||||
newTab->SwapFrameScriptsFrom(*aFrameScripts);
|
||||
|
||||
RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame);
|
||||
if (!newTab->SetRenderFrame(rfp) ||
|
||||
!newTab->GetRenderFrameInfo(aTextureFactoryIdentifier, aLayersId)) {
|
||||
*aResult = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5590,6 +5571,13 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
|
||||
MOZ_ASSERT(TabParent::GetFrom(newRemoteTab) == newTab);
|
||||
|
||||
newTab->SwapFrameScriptsFrom(*aFrameScripts);
|
||||
|
||||
RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame);
|
||||
if (!newTab->SetRenderFrame(rfp) ||
|
||||
!newTab->GetRenderFrameInfo(aTextureFactoryIdentifier, aLayersId)) {
|
||||
*aResult = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -63,8 +63,13 @@ class PJavaScriptParent;
|
||||
namespace layers {
|
||||
class PCompositorBridgeParent;
|
||||
class PSharedBufferManagerParent;
|
||||
struct TextureFactoryIdentifier;
|
||||
} // namespace layers
|
||||
|
||||
namespace layout {
|
||||
class PRenderFrameParent;
|
||||
} // namespace layout
|
||||
|
||||
namespace dom {
|
||||
|
||||
class Element;
|
||||
@@ -489,6 +494,7 @@ public:
|
||||
|
||||
virtual bool RecvCreateWindow(PBrowserParent* aThisTabParent,
|
||||
PBrowserParent* aOpener,
|
||||
layout::PRenderFrameParent* aRenderFrame,
|
||||
const uint32_t& aChromeFlags,
|
||||
const bool& aCalledFromJS,
|
||||
const bool& aPositionSpecified,
|
||||
@@ -502,7 +508,9 @@ public:
|
||||
nsresult* aResult,
|
||||
bool* aWindowIsNew,
|
||||
InfallibleTArray<FrameScriptInfo>* aFrameScripts,
|
||||
nsCString* aURLToLoad) override;
|
||||
nsCString* aURLToLoad,
|
||||
layers::TextureFactoryIdentifier* aTextureFactoryIdentifier,
|
||||
uint64_t* aLayersId) override;
|
||||
|
||||
static bool AllocateLayerTreeId(TabParent* aTabParent, uint64_t* aId);
|
||||
|
||||
@@ -720,12 +728,6 @@ private:
|
||||
virtual bool
|
||||
DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent*) override;
|
||||
|
||||
virtual PFileSystemRequestParent*
|
||||
AllocPFileSystemRequestParent(const FileSystemParams&) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPFileSystemRequestParent(PFileSystemRequestParent*) override;
|
||||
|
||||
virtual PBlobParent*
|
||||
AllocPBlobParent(const BlobConstructorParams& aParams) override;
|
||||
|
||||
@@ -738,9 +740,6 @@ private:
|
||||
virtual bool
|
||||
DeallocPCrashReporterParent(PCrashReporterParent* crashreporter) override;
|
||||
|
||||
virtual bool RecvGetRandomValues(const uint32_t& length,
|
||||
InfallibleTArray<uint8_t>* randomValues) override;
|
||||
|
||||
virtual bool RecvIsSecureURI(const uint32_t& aType, const URIParams& aURI,
|
||||
const uint32_t& aFlags, bool* aIsSecureURI) override;
|
||||
|
||||
@@ -925,9 +924,9 @@ private:
|
||||
nsTArray<StructuredCloneData>* aRetvals) override;
|
||||
|
||||
virtual bool RecvAsyncMessage(const nsString& aMsg,
|
||||
const ClonedMessageData& aData,
|
||||
InfallibleTArray<CpowEntry>&& aCpows,
|
||||
const IPC::Principal& aPrincipal) override;
|
||||
const IPC::Principal& aPrincipal,
|
||||
const ClonedMessageData& aData) override;
|
||||
|
||||
virtual bool RecvFilePathUpdateNotify(const nsString& aType,
|
||||
const nsString& aStorageName,
|
||||
@@ -1014,6 +1013,7 @@ private:
|
||||
|
||||
virtual bool RecvGetGraphicsFeatureStatus(const int32_t& aFeature,
|
||||
int32_t* aStatus,
|
||||
nsCString* aFailureId,
|
||||
bool* aSuccess) override;
|
||||
|
||||
virtual bool RecvGraphicsError(const nsCString& aError) override;
|
||||
|
||||
@@ -107,8 +107,8 @@ prio(normal upto urgent) sync protocol PBrowser
|
||||
manages PPluginWidget;
|
||||
|
||||
both:
|
||||
async AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows,
|
||||
Principal aPrincipal);
|
||||
async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
|
||||
Principal aPrincipal, ClonedMessageData aData);
|
||||
|
||||
/**
|
||||
* Create a layout frame (encapsulating a remote layer tree) for
|
||||
@@ -482,10 +482,6 @@ parent:
|
||||
*/
|
||||
async RemotePaintIsReady();
|
||||
|
||||
sync GetRenderFrameInfo(PRenderFrame aRenderFrame)
|
||||
returns (TextureFactoryIdentifier textureFactoryIdentifier,
|
||||
uint64_t layersId);
|
||||
|
||||
/**
|
||||
* Sent by the child to the parent to inform it that an update to the
|
||||
* dimensions has been requested, likely through win.moveTo or resizeTo
|
||||
@@ -715,6 +711,13 @@ child:
|
||||
float aVolume,
|
||||
bool aMuted);
|
||||
|
||||
/**
|
||||
* Tells the root child docShell whether or not to use
|
||||
* global history. This is sent right after the PBrowser
|
||||
* is bound to a frameloader element.
|
||||
*/
|
||||
async SetUseGlobalHistory(bool aUse);
|
||||
|
||||
/*
|
||||
* FIXME: write protocol!
|
||||
|
||||
|
||||
+15
-72
@@ -21,7 +21,6 @@ include protocol PHandlerService;
|
||||
include protocol PDeviceStorageRequest;
|
||||
include protocol PFileDescriptorSet;
|
||||
include protocol PFMRadio;
|
||||
include protocol PFileSystemRequest;
|
||||
include protocol PHal;
|
||||
include protocol PHeapSnapshotTempFileHelper;
|
||||
include protocol PIcc;
|
||||
@@ -42,6 +41,7 @@ include protocol PPluginModule;
|
||||
include protocol PGMP;
|
||||
include protocol PPrinting;
|
||||
include protocol POfflineCacheUpdate;
|
||||
include protocol PRenderFrame;
|
||||
include protocol PScreenManager;
|
||||
include protocol PSharedBufferManager;
|
||||
include protocol PSms;
|
||||
@@ -96,6 +96,7 @@ using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
|
||||
using struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
|
||||
using class mozilla::dom::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h";
|
||||
using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h";
|
||||
using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
|
||||
|
||||
union ChromeRegistryItem
|
||||
{
|
||||
@@ -266,67 +267,6 @@ union FMRadioRequestParams
|
||||
FMRadioRequestCancelSeekParams;
|
||||
};
|
||||
|
||||
struct FileSystemCreateDirectoryParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
};
|
||||
|
||||
union FileSystemFileDataValue
|
||||
{
|
||||
uint8_t[];
|
||||
PBlob;
|
||||
};
|
||||
|
||||
struct FileSystemCreateFileParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
FileSystemFileDataValue data;
|
||||
bool replace;
|
||||
};
|
||||
|
||||
struct FileSystemGetDirectoryListingParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
bool isRoot;
|
||||
// 'filters' could be an array rather than a semicolon separated string
|
||||
// (we'd then use InfallibleTArray<nsString> internally), but that is
|
||||
// wasteful. E10s requires us to pass the filters over as a string anyway,
|
||||
// so avoiding using an array avoids serialization on the side passing the
|
||||
// filters. Since an nsString can share its buffer when copied,
|
||||
// using that instead of InfallibleTArray<nsString> makes copying the filters
|
||||
// around in any given process a bit more efficient too, since copying a
|
||||
// single nsString is cheaper than copying InfallibleTArray member data and
|
||||
// each nsString that it contains.
|
||||
nsString filters;
|
||||
};
|
||||
|
||||
struct FileSystemGetFileOrDirectoryParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString realPath;
|
||||
bool isRoot;
|
||||
};
|
||||
|
||||
struct FileSystemRemoveParams
|
||||
{
|
||||
nsString filesystem;
|
||||
nsString directory;
|
||||
nsString targetDirectory;
|
||||
bool recursive;
|
||||
};
|
||||
|
||||
union FileSystemParams
|
||||
{
|
||||
FileSystemCreateDirectoryParams;
|
||||
FileSystemCreateFileParams;
|
||||
FileSystemGetDirectoryListingParams;
|
||||
FileSystemGetFileOrDirectoryParams;
|
||||
FileSystemRemoveParams;
|
||||
};
|
||||
|
||||
union PrefValue {
|
||||
nsCString;
|
||||
int32_t;
|
||||
@@ -473,7 +413,6 @@ prio(normal upto urgent) sync protocol PContent
|
||||
manages PCrashReporter;
|
||||
manages PCycleCollectWithLogs;
|
||||
manages PDeviceStorageRequest;
|
||||
manages PFileSystemRequest;
|
||||
manages PPSMContentDownloader;
|
||||
manages PExternalHelperApp;
|
||||
manages PFileDescriptorSet;
|
||||
@@ -730,6 +669,11 @@ child:
|
||||
*/
|
||||
async PushSubscriptionChange(nsCString scope, Principal principal);
|
||||
|
||||
/**
|
||||
* Send a Push error message to all service worker clients in the child.
|
||||
*/
|
||||
async PushError(nsCString scope, nsString message, uint32_t flags);
|
||||
|
||||
/**
|
||||
* Windows specific: associate this content process with the browsers
|
||||
* audio session.
|
||||
@@ -811,13 +755,8 @@ parent:
|
||||
async PRemoteSpellcheckEngine();
|
||||
async PDeviceStorageRequest(DeviceStorageParams params);
|
||||
|
||||
async PFileSystemRequest(FileSystemParams params);
|
||||
|
||||
sync PCrashReporter(NativeThreadId tid, uint32_t processType);
|
||||
|
||||
prio(urgent) sync GetRandomValues(uint32_t length)
|
||||
returns (uint8_t[] randomValues);
|
||||
|
||||
async GetSystemMemory(uint64_t getterId);
|
||||
|
||||
sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags)
|
||||
@@ -1008,7 +947,8 @@ parent:
|
||||
bool isAudio,
|
||||
bool isVideo);
|
||||
|
||||
sync GetGraphicsFeatureStatus(int32_t aFeature) returns (int32_t aStatus, bool aSuccess);
|
||||
sync GetGraphicsFeatureStatus(int32_t aFeature) returns (int32_t aStatus, nsCString aFailureCode,
|
||||
bool aSuccess);
|
||||
|
||||
// Graphics errors
|
||||
async GraphicsError(nsCString aError);
|
||||
@@ -1166,6 +1106,7 @@ parent:
|
||||
|
||||
sync CreateWindow(nullable PBrowser aThisTab,
|
||||
PBrowser aNewTab,
|
||||
PRenderFrame aRenderFrame,
|
||||
uint32_t aChromeFlags,
|
||||
bool aCalledFromJS,
|
||||
bool aPositionSpecified,
|
||||
@@ -1179,7 +1120,9 @@ parent:
|
||||
returns (nsresult rv,
|
||||
bool windowOpened,
|
||||
FrameScriptInfo[] frameScripts,
|
||||
nsCString urlToLoad);
|
||||
nsCString urlToLoad,
|
||||
TextureFactoryIdentifier textureFactoryIdentifier,
|
||||
uint64_t layersId);
|
||||
|
||||
sync GetDeviceStorageLocation(nsString type)
|
||||
returns (nsString path);
|
||||
@@ -1198,8 +1141,8 @@ parent:
|
||||
*/
|
||||
sync UngrabPointer(uint32_t time);
|
||||
both:
|
||||
async AsyncMessage(nsString aMessage, ClonedMessageData aData,
|
||||
CpowEntry[] aCpows, Principal aPrincipal);
|
||||
async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
|
||||
Principal aPrincipal, ClonedMessageData aData);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user