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:
2024-04-18 11:14:32 +08:00
parent 52a27516d8
commit d457251529
392 changed files with 11612 additions and 6523 deletions
+2 -2
View File
@@ -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);
+6 -4
View File
@@ -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";
}
+56
View File
@@ -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,
+14
View File
@@ -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
View File
@@ -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
-3
View File
@@ -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;
+2 -2
View File
@@ -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)) ||
+2 -1
View File
@@ -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;
}
}
+1 -1
View File
@@ -72,7 +72,7 @@ GetBRGADataSourceSurfaceSync(already_AddRefed<layers::Image> aImage)
return helper->GetDataSurfaceSafe();
}
class EncodingCompleteEvent : public nsCancelableRunnable
class EncodingCompleteEvent : public CancelableRunnable
{
virtual ~EncodingCompleteEvent() {}
+88 -1
View File
@@ -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;
+2 -1
View File
@@ -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
};
+2 -1
View File
@@ -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
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+2 -2
View File
@@ -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;
+2 -2
View File
@@ -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;
}
+2
View File
@@ -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")
+7 -7
View File
@@ -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,
+20 -13
View File
@@ -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);
};
+80 -87
View File
@@ -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();
}
+16 -9
View File
@@ -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__
+1 -1
View File
@@ -1141,7 +1141,7 @@ PerformanceBase::CancelNotificationObservers()
mPendingNotificationObserversTask = false;
}
class NotifyObserversTask final : public nsCancelableRunnable
class NotifyObserversTask final : public CancelableRunnable
{
public:
explicit NotifyObserversTask(PerformanceBase* aPerformance)
+42 -27
View File
@@ -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);
}
}
+1
View File
@@ -32,3 +32,4 @@ skip-if = os == 'mac'
[test_xhr_standalone.js]
[test_xmlserializer.js]
[test_cancelPrefetch.js]
[test_chromeutils_base64.js]
+1 -19
View File
@@ -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',
+1
View File
@@ -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.")
+2 -2
View File
@@ -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,
+1
View File
@@ -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;
}
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -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)
+2 -1
View File
@@ -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;
+2 -1
View File
@@ -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",
-3
View File
@@ -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']);
+10 -2
View File
@@ -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;
+1 -1
View File
@@ -38,7 +38,7 @@ private:
nsCOMPtr<nsIEventTarget> mEventTarget;
};
class ContextLossWorkerRunnable final : public nsCancelableRunnable
class ContextLossWorkerRunnable final : public CancelableRunnable
{
public:
explicit ContextLossWorkerRunnable(nsIRunnable* aRunnable)
+1 -1
View File
@@ -57,7 +57,7 @@ if (NS_FAILED(rv)) { \
return; \
}
class WebCryptoTask : public nsCancelableRunnable,
class WebCryptoTask : public CancelableRunnable,
public nsNSSShutDownObject
{
public:
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
+59 -12
View File
@@ -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;
}
}
+7 -5
View File
@@ -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;
}
}
+36 -36
View File
@@ -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 =
+5 -3
View File
@@ -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;
}
+3 -3
View File
@@ -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;
}
+4 -4
View File
@@ -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
View File
@@ -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;
}
}
-2
View File
@@ -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
+109 -88
View File
@@ -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
+38 -23
View File
@@ -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
View File
@@ -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
+53 -29
View File
@@ -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;
};
+43 -14
View File
@@ -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
+6
View File
@@ -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();
+56 -17
View File
@@ -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
+6
View File
@@ -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,
+22 -2
View File
@@ -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
+50 -6
View File
@@ -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
+120 -8
View File
@@ -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 */
+13 -6
View File
@@ -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;
+32 -21
View File
@@ -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
+29 -11
View File
@@ -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
+248 -147
View File
@@ -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
View File
@@ -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
+182 -165
View File
@@ -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
+39 -23
View File
@@ -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
+127 -109
View File
@@ -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
+39 -24
View File
@@ -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
+25 -6
View File
@@ -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
+68 -1
View File
@@ -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
+72
View File
@@ -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
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1
View File
@@ -35,6 +35,7 @@ UNIFIED_SOURCES += [
FINAL_LIBRARY = 'xul'
IPDL_SOURCES += [
'PFileSystemParams.ipdlh',
'PFileSystemRequest.ipdl',
]
+2
View File
@@ -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>
+58
View File
@@ -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);
}
+2 -2
View File
@@ -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(
+2 -2
View File
@@ -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)
+1 -1
View File
@@ -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;
}
+8 -17
View File
@@ -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
+1 -1
View File
@@ -212,7 +212,7 @@ void
HTMLObjectElement::HandleFocusBlurPlugin(Element* aElement,
WidgetEvent* aEvent)
{
if (!aEvent->mFlags.mIsTrusted) {
if (!aEvent->IsTrusted()) {
return;
}
switch (aEvent->mMessage) {
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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::*)();
+1 -1
View File
@@ -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;
+3
View File
@@ -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
View File
@@ -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()
+3 -3
View File
@@ -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*
+2 -2
View File
@@ -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,
+4 -4
View File
@@ -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*
+2 -2
View File
@@ -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
View File
@@ -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
+6 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+9 -6
View File
@@ -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
View File
@@ -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