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. // Don't dump memory reports on OOM, by default.
pref("memory.dump_reports_on_oom", false); pref("memory.dump_reports_on_oom", false);
pref("layout.imagevisibility.numscrollportwidths", 1); pref("layout.framevisibility.numscrollportwidths", 1);
pref("layout.imagevisibility.numscrollportheights", 1); pref("layout.framevisibility.numscrollportheights", 1);
// Enable native identity (persona/browserid) // Enable native identity (persona/browserid)
pref("dom.identity.enabled", true); pref("dom.identity.enabled", true);
+6 -4
View File
@@ -4370,10 +4370,12 @@ this.DOMApplicationRegistry = {
return "INVALID_SEGMENTS_NUMBER"; return "INVALID_SEGMENTS_NUMBER";
} }
// We need to translate the base64 alphabet used in JWT to our base64 alphabet let jwtBuffer = ChromeUtils.base64URLDecode(segments[1], {
// before calling atob. // JWT/JWS prohibits padding per RFC 7515, section 2.
let decodedReceipt = JSON.parse(atob(segments[1].replace(/-/g, '+') padding: "reject",
.replace(/_/g, '/'))); });
let textDecoder = new TextDecoder("utf-8");
let decodedReceipt = JSON.parse(textDecoder.decode(jwtBuffer));
if (!decodedReceipt) { if (!decodedReceipt) {
return "INVALID_RECEIPT_ENCODING"; return "INVALID_RECEIPT_ENCODING";
} }
+56
View File
@@ -5,6 +5,7 @@
#include "ChromeUtils.h" #include "ChromeUtils.h"
#include "mozilla/Base64.h"
#include "mozilla/BasePrincipal.h" #include "mozilla/BasePrincipal.h"
namespace mozilla { 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 /* static */ void
ChromeUtils::OriginAttributesToSuffix(dom::GlobalObject& aGlobal, ChromeUtils::OriginAttributesToSuffix(dom::GlobalObject& aGlobal,
const dom::OriginAttributesDictionary& aAttrs, const dom::OriginAttributesDictionary& aAttrs,
+14
View File
@@ -20,6 +20,8 @@ class HeapSnapshot;
namespace dom { namespace dom {
class ArrayBufferViewOrArrayBuffer;
class ThreadSafeChromeUtils class ThreadSafeChromeUtils
{ {
public: public:
@@ -43,6 +45,18 @@ public:
JS::Handle<JS::Value> aSet, JS::Handle<JS::Value> aSet,
JS::MutableHandle<JS::Value> aRetval, JS::MutableHandle<JS::Value> aRetval,
ErrorResult& aRv); 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 class ChromeUtils : public ThreadSafeChromeUtils
+16 -42
View File
@@ -58,8 +58,6 @@ Crypto::GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
JS::MutableHandle<JSObject*> aRetval, JS::MutableHandle<JSObject*> aRetval,
ErrorResult& aRv) ErrorResult& aRv)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Called on the wrong thread");
JS::Rooted<JSObject*> view(aCx, aArray.Obj()); JS::Rooted<JSObject*> view(aCx, aArray.Obj());
if (JS_IsTypedArrayObject(view) && JS_GetTypedArraySharedness(view)) { if (JS_IsTypedArrayObject(view) && JS_GetTypedArraySharedness(view)) {
@@ -95,32 +93,24 @@ Crypto::GetRandomValues(JSContext* aCx, const ArrayBufferView& aArray,
return; return;
} }
uint8_t* data = aArray.Data(); nsCOMPtr<nsIRandomGenerator> randomGenerator =
do_GetService("@mozilla.org/security/random-generator;1");
if (!XRE_IsParentProcess()) { if (!randomGenerator) {
InfallibleTArray<uint8_t> randomValues; aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
// Tell the parent process to generate random values via PContent return;
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);
} }
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); aRetval.set(view);
} }
@@ -133,21 +123,5 @@ Crypto::Subtle()
return mSubtle; 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 dom
} // namespace mozilla } // namespace mozilla
-3
View File
@@ -54,9 +54,6 @@ public:
virtual JSObject* virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
static uint8_t*
GetRandomValues(uint32_t aLength);
private: private:
nsCOMPtr<nsIGlobalObject> mParent; nsCOMPtr<nsIGlobalObject> mParent;
RefPtr<SubtleCrypto> mSubtle; RefPtr<SubtleCrypto> mSubtle;
+2 -2
View File
@@ -2116,7 +2116,7 @@ Element::DispatchClickEvent(nsPresContext* aPresContext,
NS_PRECONDITION(aSourceEvent, "Must have source event"); NS_PRECONDITION(aSourceEvent, "Must have source event");
NS_PRECONDITION(aStatus, "Null out param?"); NS_PRECONDITION(aStatus, "Null out param?");
WidgetMouseEvent event(aSourceEvent->mFlags.mIsTrusted, eMouseClick, WidgetMouseEvent event(aSourceEvent->IsTrusted(), eMouseClick,
aSourceEvent->widget, WidgetMouseEvent::eReal); aSourceEvent->widget, WidgetMouseEvent::eReal);
event.refPoint = aSourceEvent->refPoint; event.refPoint = aSourceEvent->refPoint;
uint32_t clickCount = 1; uint32_t clickCount = 1;
@@ -2929,7 +2929,7 @@ Element::CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
nsIURI** aURI) const nsIURI** aURI) const
{ {
if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault || if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault ||
(!aVisitor.mEvent->mFlags.mIsTrusted && (!aVisitor.mEvent->IsTrusted() &&
(aVisitor.mEvent->mMessage != eMouseClick) && (aVisitor.mEvent->mMessage != eMouseClick) &&
(aVisitor.mEvent->mMessage != eKeyPress) && (aVisitor.mEvent->mMessage != eKeyPress) &&
(aVisitor.mEvent->mMessage != eLegacyDOMActivate)) || (aVisitor.mEvent->mMessage != eLegacyDOMActivate)) ||
+2 -1
View File
@@ -115,7 +115,8 @@ bool
FileList::ClonableToDifferentThreadOrProcess() const FileList::ClonableToDifferentThreadOrProcess() const
{ {
for (uint32_t i = 0; i < mFilesOrDirectories.Length(); ++i) { for (uint32_t i = 0; i < mFilesOrDirectories.Length(); ++i) {
if (mFilesOrDirectories[i].IsDirectory()) { if (mFilesOrDirectories[i].IsDirectory() &&
!mFilesOrDirectories[i].GetAsDirectory()->ClonableToDifferentThreadOrProcess()) {
return false; return false;
} }
} }
+1 -1
View File
@@ -72,7 +72,7 @@ GetBRGADataSourceSurfaceSync(already_AddRefed<layers::Image> aImage)
return helper->GetDataSurfaceSafe(); return helper->GetDataSurfaceSafe();
} }
class EncodingCompleteEvent : public nsCancelableRunnable class EncodingCompleteEvent : public CancelableRunnable
{ {
virtual ~EncodingCompleteEvent() {} virtual ~EncodingCompleteEvent() {}
+88 -1
View File
@@ -11,6 +11,7 @@
#include "mozilla/dom/BlobBinding.h" #include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/CryptoKey.h" #include "mozilla/dom/CryptoKey.h"
#include "mozilla/dom/Directory.h" #include "mozilla/dom/Directory.h"
#include "mozilla/dom/DirectoryBinding.h"
#include "mozilla/dom/File.h" #include "mozilla/dom/File.h"
#include "mozilla/dom/FileList.h" #include "mozilla/dom/FileList.h"
#include "mozilla/dom/FileListBinding.h" #include "mozilla/dom/FileListBinding.h"
@@ -663,7 +664,7 @@ ReadBlob(JSContext* aCx,
MOZ_ASSERT(blobImpl); 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 // called because the static analysis thinks dereferencing XPCOM objects
// can GC (because in some cases it can!), and a return statement with a // 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 // JSObject* type means that JSObject* is on the stack as a raw pointer
@@ -710,6 +711,80 @@ WriteBlob(JSStructuredCloneWriter* aWriter,
return false; 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. // Read the WriteFileList for the format.
JSObject* JSObject*
ReadFileList(JSContext* aCx, ReadFileList(JSContext* aCx,
@@ -1007,6 +1082,10 @@ StructuredCloneHolder::CustomReadHandler(JSContext* aCx,
return ReadBlob(aCx, aIndex, this); return ReadBlob(aCx, aIndex, this);
} }
if (aTag == SCTAG_DOM_DIRECTORY) {
return ReadDirectory(aCx, aReader, aIndex, this);
}
if (aTag == SCTAG_DOM_FILELIST) { if (aTag == SCTAG_DOM_FILELIST) {
return ReadFileList(aCx, aReader, aIndex, this); 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. // See if this is a FileList object.
{ {
FileList* fileList = nullptr; FileList* fileList = nullptr;
+2 -1
View File
@@ -17,7 +17,6 @@ namespace dom {
enum StructuredCloneTags { enum StructuredCloneTags {
SCTAG_BASE = JS_SCTAG_USER_MIN, SCTAG_BASE = JS_SCTAG_USER_MIN,
// These tags are used only for main thread structured clone.
SCTAG_DOM_BLOB, SCTAG_DOM_BLOB,
// This tag is obsolete and exists only for backwards compatibility with // This tag is obsolete and exists only for backwards compatibility with
@@ -53,6 +52,8 @@ enum StructuredCloneTags {
SCTAG_DOM_EXPANDED_PRINCIPAL, SCTAG_DOM_EXPANDED_PRINCIPAL,
SCTAG_DOM_DIRECTORY,
SCTAG_DOM_MAX SCTAG_DOM_MAX
}; };
+2 -1
View File
@@ -712,7 +712,8 @@ TextInputProcessor::WillDispatchKeyboardEvent(
uint32_t aIndexOfKeypress, uint32_t aIndexOfKeypress,
void* aData) 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 nsresult
+2 -2
View File
@@ -254,7 +254,7 @@ NS_IMPL_ISUPPORTS(WebSocketImpl,
nsIRequest, nsIRequest,
nsIEventTarget) nsIEventTarget)
class CallDispatchConnectionCloseEvents final : public nsCancelableRunnable class CallDispatchConnectionCloseEvents final : public CancelableRunnable
{ {
public: public:
explicit CallDispatchConnectionCloseEvents(WebSocketImpl* aWebSocketImpl) explicit CallDispatchConnectionCloseEvents(WebSocketImpl* aWebSocketImpl)
@@ -1251,7 +1251,7 @@ WebSocket::Constructor(const GlobalObject& aGlobal,
RefPtr<InitRunnable> runnable = RefPtr<InitRunnable> runnable =
new InitRunnable(webSocket->mImpl, aUrl, protocolArray, new InitRunnable(webSocket->mImpl, aUrl, protocolArray,
nsAutoCString(file.get()), lineno, column, aRv, nsDependentCString(file.get()), lineno, column, aRv,
&connectionFailed); &connectionFailed);
runnable->Dispatch(aRv); runnable->Dispatch(aRv);
} }
+8 -187
View File
@@ -3496,7 +3496,8 @@ nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
nsIURI* aURI, nsIURI* aURI,
const nsAFlatString& aSourceLine, const nsAFlatString& aSourceLine,
uint32_t aLineNumber, uint32_t aLineNumber,
uint32_t aColumnNumber) uint32_t aColumnNumber,
MissingErrorLocationMode aLocationMode)
{ {
uint64_t innerWindowID = 0; uint64_t innerWindowID = 0;
if (aDocument) { if (aDocument) {
@@ -3513,14 +3514,15 @@ nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
} }
nsAutoCString spec; nsAutoCString spec;
if (!aLineNumber) { if (!aLineNumber && aLocationMode == eUSE_CALLING_LOCATION) {
JSContext *cx = GetCurrentJSContext(); JSContext *cx = GetCurrentJSContext();
if (cx) { if (cx) {
nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber, &aColumnNumber); nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber, &aColumnNumber);
} }
} }
if (spec.IsEmpty() && aURI) if (spec.IsEmpty() && aURI) {
aURI->GetSpec(spec); aURI->GetSpec(spec);
}
nsCOMPtr<nsIScriptError> errorObject = nsCOMPtr<nsIScriptError> errorObject =
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv); do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
@@ -4922,188 +4924,6 @@ nsContentUtils::GetLocalizedEllipsis()
return nsDependentString(sBuf); 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 */ /* static */
void void
nsContentUtils::AddScriptBlocker() nsContentUtils::AddScriptBlocker()
@@ -5426,8 +5246,9 @@ nsContentUtils::GetDragSession()
nsresult nsresult
nsContentUtils::SetDataTransferInEvent(WidgetDragEvent* aDragEvent) nsContentUtils::SetDataTransferInEvent(WidgetDragEvent* aDragEvent)
{ {
if (aDragEvent->dataTransfer || !aDragEvent->mFlags.mIsTrusted) if (aDragEvent->dataTransfer || !aDragEvent->IsTrusted()) {
return NS_OK; return NS_OK;
}
// For draggesture and dragstart events, the data transfer object is // For draggesture and dragstart events, the data transfer object is
// created before the event fires, so it should already be set. For other // 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) { if (aAdditionalFlags & nsIDOMWindowUtils::KEY_FLAG_PREVENT_DEFAULT) {
event.mFlags.mDefaultPrevented = true; event.PreventDefaultBeforeDispatch();
} }
nsEventStatus status; nsEventStatus status;
+11 -31
View File
@@ -171,15 +171,6 @@ struct EventNameMapping
mozilla::EventClassID mEventClassID; 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, typedef void (*CallOnRemoteChildFunction) (mozilla::dom::TabParent* aTabParent,
void* aArg); void* aArg);
@@ -817,7 +808,15 @@ public:
* @param [aColumnNumber=0] (Optional) Column number within resource * @param [aColumnNumber=0] (Optional) Column number within resource
containing error. containing error.
If aURI is null, then aDocument->GetDocumentURI() is used. 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, static nsresult ReportToConsoleNonLocalized(const nsAString& aErrorText,
uint32_t aErrorFlags, uint32_t aErrorFlags,
const nsACString& aCategory, const nsACString& aCategory,
@@ -826,7 +825,9 @@ public:
const nsAFlatString& aSourceLine const nsAFlatString& aSourceLine
= EmptyString(), = EmptyString(),
uint32_t aLineNumber = 0, 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. * Report a localized error message to the error console.
@@ -1501,27 +1502,6 @@ public:
*/ */
static const nsDependentString GetLocalizedEllipsis(); 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 * Hide any XUL popups associated with aDocument, including any documents
* displayed in child frames. Does nothing if aDocument is null. * 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))) { if (aCpows && (!mgr || !mgr->Wrap(aCx, aCpows, &cpows))) {
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
} }
if (tabParent->SendAsyncMessage(nsString(aMessage), data, cpows, if (tabParent->SendAsyncMessage(nsString(aMessage), cpows,
IPC::Principal(aPrincipal))) { IPC::Principal(aPrincipal), data)) {
return NS_OK; return NS_OK;
} else { } else {
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
+2 -2
View File
@@ -2033,8 +2033,8 @@ public:
if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) { if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
} }
if (!cc->SendAsyncMessage(PromiseFlatString(aMessage), data, cpows, if (!cc->SendAsyncMessage(PromiseFlatString(aMessage), cpows,
IPC::Principal(aPrincipal))) { IPC::Principal(aPrincipal), data)) {
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
} }
+2
View File
@@ -306,6 +306,7 @@ GK_ATOM(directionality, "directionality")
GK_ATOM(directory, "directory") GK_ATOM(directory, "directory")
GK_ATOM(disableOutputEscaping, "disable-output-escaping") GK_ATOM(disableOutputEscaping, "disable-output-escaping")
GK_ATOM(disabled, "disabled") GK_ATOM(disabled, "disabled")
GK_ATOM(disableglobalhistory, "disableglobalhistory")
GK_ATOM(disablehistory, "disablehistory") GK_ATOM(disablehistory, "disablehistory")
GK_ATOM(display, "display") GK_ATOM(display, "display")
GK_ATOM(displayMode, "display-mode") GK_ATOM(displayMode, "display-mode")
@@ -1039,6 +1040,7 @@ GK_ATOM(renderingobserverlist, "renderingobserverlist")
GK_ATOM(repeat, "repeat") GK_ATOM(repeat, "repeat")
GK_ATOM(replace, "replace") GK_ATOM(replace, "replace")
GK_ATOM(required, "required") GK_ATOM(required, "required")
GK_ATOM(reserved, "reserved")
GK_ATOM(reset, "reset") GK_ATOM(reset, "reset")
GK_ATOM(resizeafter, "resizeafter") GK_ATOM(resizeafter, "resizeafter")
GK_ATOM(resizebefore, "resizebefore") GK_ATOM(resizebefore, "resizebefore")
+7 -7
View File
@@ -3112,7 +3112,7 @@ nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time), gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
sizeof(uint32_t)); 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 // QIing to window so that we can keep the old behavior also in case
// a child window is handling resize. // a child window is handling resize.
nsCOMPtr<nsPIDOMWindow> window = nsCOMPtr<nsPIDOMWindow> window =
@@ -3120,10 +3120,10 @@ nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
if (window) { if (window) {
mIsHandlingResizeEvent = true; mIsHandlingResizeEvent = true;
} }
} else if (msg == eMouseDown && aVisitor.mEvent->mFlags.mIsTrusted) { } else if (msg == eMouseDown && aVisitor.mEvent->IsTrusted()) {
gMouseDown = true; gMouseDown = true;
} else if ((msg == eMouseUp || msg == eDragEnd) && } else if ((msg == eMouseUp || msg == eDragEnd) &&
aVisitor.mEvent->mFlags.mIsTrusted) { aVisitor.mEvent->IsTrusted()) {
gMouseDown = false; gMouseDown = false;
if (gDragServiceDisabled) { if (gDragServiceDisabled) {
nsCOMPtr<nsIDragService> ds = nsCOMPtr<nsIDragService> ds =
@@ -3139,7 +3139,7 @@ nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
// Handle 'active' event. // Handle 'active' event.
if (!mIdleObservers.IsEmpty() && if (!mIdleObservers.IsEmpty() &&
aVisitor.mEvent->mFlags.mIsTrusted && aVisitor.mEvent->IsTrusted() &&
(aVisitor.mEvent->HasMouseEventMessage() || (aVisitor.mEvent->HasMouseEventMessage() ||
aVisitor.mEvent->HasDragEventMessage())) { aVisitor.mEvent->HasDragEventMessage())) {
mAddActiveEventFuzzTime = false; mAddActiveEventFuzzTime = false;
@@ -3317,7 +3317,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
if (aVisitor.mEvent->mMessage == eResize) { if (aVisitor.mEvent->mMessage == eResize) {
mIsHandlingResizeEvent = false; mIsHandlingResizeEvent = false;
} else if (aVisitor.mEvent->mMessage == eUnload && } else if (aVisitor.mEvent->mMessage == eUnload &&
aVisitor.mEvent->mFlags.mIsTrusted) { aVisitor.mEvent->IsTrusted()) {
// Execute bindingdetached handlers before we tear ourselves // Execute bindingdetached handlers before we tear ourselves
// down. // down.
if (mDoc) { if (mDoc) {
@@ -3325,7 +3325,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
} }
mIsDocumentLoaded = false; mIsDocumentLoaded = false;
} else if (aVisitor.mEvent->mMessage == eLoad && } 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|. // This is page load event since load events don't propagate to |window|.
// @see nsDocument::PreHandleEvent. // @see nsDocument::PreHandleEvent.
mIsDocumentLoaded = true; mIsDocumentLoaded = true;
@@ -3338,7 +3338,7 @@ nsGlobalWindow::PostHandleEvent(EventChainPostVisitor& aVisitor)
// onload event for the frame element. // onload event for the frame element.
nsEventStatus status = nsEventStatus_eIgnore; nsEventStatus status = nsEventStatus_eIgnore;
WidgetEvent event(aVisitor.mEvent->mFlags.mIsTrusted, eLoad); WidgetEvent event(aVisitor.mEvent->IsTrusted(), eLoad);
event.mFlags.mBubbles = false; event.mFlags.mBubbles = false;
// Most of the time we could get a pres context to pass in here, // 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" #include "imgINotificationObserver.idl"
%{C++
#include "mozilla/Maybe.h"
#include "Visibility.h"
%}
interface imgIRequest; interface imgIRequest;
interface nsIChannel; interface nsIChannel;
interface nsIStreamListener; interface nsIStreamListener;
@@ -12,6 +17,9 @@ interface nsIURI;
interface nsIDocument; interface nsIDocument;
interface nsIFrame; 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 * This interface represents a content node that loads images. The interface
* exists to allow getting information on the images that the content node * 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. * 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 interface nsIImageLoadingContent : imgINotificationObserver
{ {
/** /**
@@ -169,18 +177,17 @@ interface nsIImageLoadingContent : imgINotificationObserver
readonly attribute unsigned long naturalHeight; readonly attribute unsigned long naturalHeight;
/** /**
* A visible count is stored, if it is non-zero then this image is considered * Called by layout to announce when the frame associated with this content
* visible. These methods increment, decrement, or return the visible count. * has changed its visibility state.
* *
* @param aNonvisibleAction What to do if the image's visibility count is now * @param aNewVisibility The new visibility state.
* zero. If ON_NONVISIBLE_NO_ACTION, nothing will be * @param aNonvisibleAction A requested action if the frame has become
* done. If ON_NONVISIBLE_REQUEST_DISCARD, the image * nonvisible. If Nothing(), no action is
* will be asked to discard its surfaces if possible. * 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 onVisibilityChange(in Visibility aNewVisibility,
[noscript, notxpcom] void DecrementVisibleCount(in uint32_t aNonvisibleAction); in MaybeOnNonvisible aNonvisibleAction);
[noscript, notxpcom] uint32_t GetVisibleCount();
const long ON_NONVISIBLE_NO_ACTION = 0;
const long ON_NONVISIBLE_REQUEST_DISCARD = 1;
}; };
+80 -87
View File
@@ -94,8 +94,7 @@ nsImageLoadingContent::nsImageLoadingContent()
mStateChangerDepth(0), mStateChangerDepth(0),
mCurrentRequestRegistered(false), mCurrentRequestRegistered(false),
mPendingRequestRegistered(false), mPendingRequestRegistered(false),
mFrameCreateCalled(false), mFrameCreateCalled(false)
mVisibleCount(0)
{ {
if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) { if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
mLoadingEnabled = false; mLoadingEnabled = false;
@@ -110,8 +109,8 @@ nsImageLoadingContent::DestroyImageLoadingContent()
{ {
// Cancel our requests so they won't hold stale refs to us // Cancel our requests so they won't hold stale refs to us
// NB: Don't ask to discard the images here. // NB: Don't ask to discard the images here.
ClearCurrentRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_NO_ACTION); ClearCurrentRequest(NS_BINDING_ABORTED);
ClearPendingRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_NO_ACTION); ClearPendingRequest(NS_BINDING_ABORTED);
} }
nsImageLoadingContent::~nsImageLoadingContent() nsImageLoadingContent::~nsImageLoadingContent()
@@ -272,12 +271,7 @@ ImageIsAnimated(imgIRequest* aRequest)
void void
nsImageLoadingContent::OnUnlockedDraw() nsImageLoadingContent::OnUnlockedDraw()
{ {
if (mVisibleCount > 0) { // It's OK for non-animated images to wait until the next frame visibility
// 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
// update to become locked. (And that's preferable, since in the case of // update to become locked. (And that's preferable, since in the case of
// scrolling it keeps memory usage minimal.) For animated images, though, we // scrolling it keeps memory usage minimal.) For animated images, though, we
// want to mark them visible right away so we can call // want to mark them visible right away so we can call
@@ -286,15 +280,27 @@ nsImageLoadingContent::OnUnlockedDraw()
return; return;
} }
nsPresContext* presContext = GetFramePresContext(); nsIFrame* frame = GetOurPrimaryFrame();
if (!presContext) if (!frame) {
return; 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(); nsIPresShell* presShell = presContext->PresShell();
if (!presShell) if (!presShell) {
return; return;
}
presShell->EnsureImageInVisibleList(this); presShell->EnsureFrameInApproximatelyVisibleList(frame);
} }
nsresult nsresult
@@ -478,11 +484,6 @@ nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
mFrameCreateCalled = true; mFrameCreateCalled = true;
if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
// Assume all images in popups are visible.
IncrementVisibleCount();
}
TrackImage(mCurrentRequest); TrackImage(mCurrentRequest);
TrackImage(mPendingRequest); TrackImage(mPendingRequest);
@@ -526,13 +527,7 @@ nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
nsIPresShell* presShell = presContext ? presContext->GetPresShell() : nullptr; nsIPresShell* presShell = presContext ? presContext->GetPresShell() : nullptr;
if (presShell) { if (presShell) {
presShell->RemoveImageFromVisibleList(this); presShell->RemoveFrameFromApproximatelyVisibleList(aFrame);
}
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);
} }
} }
@@ -746,34 +741,6 @@ nsImageLoadingContent::UnblockOnload(imgIRequest* aRequest)
return NS_OK; 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 * Non-interface methods
*/ */
@@ -1080,8 +1047,8 @@ void
nsImageLoadingContent::CancelImageRequests(bool aNotify) nsImageLoadingContent::CancelImageRequests(bool aNotify)
{ {
AutoStateChanger changer(this, aNotify); AutoStateChanger changer(this, aNotify);
ClearPendingRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD); ClearPendingRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES));
ClearCurrentRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD); ClearCurrentRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES));
} }
nsresult nsresult
@@ -1093,8 +1060,8 @@ nsImageLoadingContent::UseAsPrimaryRequest(imgRequestProxy* aRequest,
AutoStateChanger changer(this, aNotify); AutoStateChanger changer(this, aNotify);
// Get rid if our existing images // Get rid if our existing images
ClearPendingRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD); ClearPendingRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES));
ClearCurrentRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD); ClearCurrentRequest(NS_BINDING_ABORTED, Some(OnNonvisible::DISCARD_IMAGES));
// Clone the request we were given. // Clone the request we were given.
RefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType); 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 // reason "image source changed". However, apparently there's some abuse
// over in nsImageFrame where the displaying of the "broken" icon for the // over in nsImageFrame where the displaying of the "broken" icon for the
// next image depends on the cancel reason of the previous image. ugh. // 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 // 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. // 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; mImageBlockingStatus = aContentDecision;
uint32_t keepFlags = mCurrentRequestFlags & REQUEST_IS_IMAGESET; 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, // 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 // 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. // Get rid of anything that was there previously.
ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED, ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED,
ON_NONVISIBLE_REQUEST_DISCARD); Some(OnNonvisible::DISCARD_IMAGES));
if (mNewRequestsWillNeedAnimationReset) { if (mNewRequestsWillNeedAnimationReset) {
mCurrentRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET; mCurrentRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET;
@@ -1267,7 +1237,7 @@ nsImageLoadingContent::PreparePendingRequest(ImageLoadType aImageLoadType)
{ {
// Get rid of anything that was there previously. // Get rid of anything that was there previously.
ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED, ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED,
ON_NONVISIBLE_REQUEST_DISCARD); Some(OnNonvisible::DISCARD_IMAGES));
if (mNewRequestsWillNeedAnimationReset) { if (mNewRequestsWillNeedAnimationReset) {
mPendingRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET; mPendingRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET;
@@ -1332,7 +1302,7 @@ nsImageLoadingContent::MakePendingRequestCurrent()
void void
nsImageLoadingContent::ClearCurrentRequest(nsresult aReason, nsImageLoadingContent::ClearCurrentRequest(nsresult aReason,
uint32_t aNonvisibleAction) const Maybe<OnNonvisible>& aNonvisibleAction)
{ {
if (!mCurrentRequest) { if (!mCurrentRequest) {
// Even if we didn't have a current request, we might have been keeping // Even if we didn't have a current request, we might have been keeping
@@ -1358,7 +1328,7 @@ nsImageLoadingContent::ClearCurrentRequest(nsresult aReason,
void void
nsImageLoadingContent::ClearPendingRequest(nsresult aReason, nsImageLoadingContent::ClearPendingRequest(nsresult aReason,
uint32_t aNonvisibleAction) const Maybe<OnNonvisible>& aNonvisibleAction)
{ {
if (!mPendingRequest) if (!mPendingRequest)
return; return;
@@ -1444,6 +1414,27 @@ nsImageLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
doc->UnblockOnload(false); 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 void
nsImageLoadingContent::TrackImage(imgIRequest* aImage) nsImageLoadingContent::TrackImage(imgIRequest* aImage)
{ {
@@ -1454,32 +1445,34 @@ nsImageLoadingContent::TrackImage(imgIRequest* aImage)
"Why haven't we heard of this request?"); "Why haven't we heard of this request?");
nsIDocument* doc = GetOurCurrentDoc(); nsIDocument* doc = GetOurCurrentDoc();
if (doc && (mFrameCreateCalled || GetOurPrimaryFrame()) && if (!doc) {
(mVisibleCount > 0)) { return;
}
if (mVisibleCount == 1) { // We only want to track this request if we're visible. Ordinarily we check
// Since we're becoming visible, request a decode. // the visible count, but that requires a frame; in cases where
nsImageFrame* f = do_QueryFrame(GetOurPrimaryFrame()); // GetOurPrimaryFrame() cannot obtain a frame (e.g. <feImage>), we assume
if (f) { // we're visible if FrameCreated() was called.
f->MaybeDecodeForPredictedSize(); nsIFrame* frame = GetOurPrimaryFrame();
} if ((frame && frame->GetVisibility() == Visibility::APPROXIMATELY_NONVISIBLE) ||
} (!frame && !mFrameCreateCalled)) {
return;
}
if (aImage == mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) { if (aImage == mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
mCurrentRequestFlags |= REQUEST_IS_TRACKED; mCurrentRequestFlags |= REQUEST_IS_TRACKED;
doc->AddImage(mCurrentRequest); doc->AddImage(mCurrentRequest);
} }
if (aImage == mPendingRequest && !(mPendingRequestFlags & REQUEST_IS_TRACKED)) { if (aImage == mPendingRequest && !(mPendingRequestFlags & REQUEST_IS_TRACKED)) {
mPendingRequestFlags |= REQUEST_IS_TRACKED; mPendingRequestFlags |= REQUEST_IS_TRACKED;
doc->AddImage(mPendingRequest); doc->AddImage(mPendingRequest);
}
} }
} }
void void
nsImageLoadingContent::UntrackImage(imgIRequest* aImage, nsImageLoadingContent::UntrackImage(imgIRequest* aImage,
uint32_t aNonvisibleAction const Maybe<OnNonvisible>& aNonvisibleAction
/* = ON_NONVISIBLE_NO_ACTION */) /* = Nothing() */)
{ {
if (!aImage) if (!aImage)
return; return;
@@ -1496,10 +1489,10 @@ nsImageLoadingContent::UntrackImage(imgIRequest* aImage,
if (doc && (mCurrentRequestFlags & REQUEST_IS_TRACKED)) { if (doc && (mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
mCurrentRequestFlags &= ~REQUEST_IS_TRACKED; mCurrentRequestFlags &= ~REQUEST_IS_TRACKED;
doc->RemoveImage(mCurrentRequest, doc->RemoveImage(mCurrentRequest,
(aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD) aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)
? nsIDocument::REQUEST_DISCARD ? nsIDocument::REQUEST_DISCARD
: 0); : 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. // If we're not in the document we may still need to be discarded.
aImage->RequestDiscard(); aImage->RequestDiscard();
} }
@@ -1508,10 +1501,10 @@ nsImageLoadingContent::UntrackImage(imgIRequest* aImage,
if (doc && (mPendingRequestFlags & REQUEST_IS_TRACKED)) { if (doc && (mPendingRequestFlags & REQUEST_IS_TRACKED)) {
mPendingRequestFlags &= ~REQUEST_IS_TRACKED; mPendingRequestFlags &= ~REQUEST_IS_TRACKED;
doc->RemoveImage(mPendingRequest, doc->RemoveImage(mPendingRequest,
(aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD) aNonvisibleAction == Some(OnNonvisible::DISCARD_IMAGES)
? nsIDocument::REQUEST_DISCARD ? nsIDocument::REQUEST_DISCARD
: 0); : 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. // If we're not in the document we may still need to be discarded.
aImage->RequestDiscard(); aImage->RequestDiscard();
} }
+16 -9
View File
@@ -41,6 +41,11 @@ class imgRequestProxy;
class nsImageLoadingContent : public nsIImageLoadingContent, class nsImageLoadingContent : public nsIImageLoadingContent,
public imgIOnloadBlocker public imgIOnloadBlocker
{ {
template <typename T> using Maybe = mozilla::Maybe<T>;
using Nothing = mozilla::Nothing;
using OnNonvisible = mozilla::OnNonvisible;
using Visibility = mozilla::Visibility;
/* METHODS */ /* METHODS */
public: public:
nsImageLoadingContent(); nsImageLoadingContent();
@@ -326,8 +331,10 @@ protected:
* @param aNonvisibleAction An action to take if the image is no longer * @param aNonvisibleAction An action to take if the image is no longer
* visible as a result; see |UntrackImage|. * visible as a result; see |UntrackImage|.
*/ */
void ClearCurrentRequest(nsresult aReason, uint32_t aNonvisibleAction); void ClearCurrentRequest(nsresult aReason,
void ClearPendingRequest(nsresult aReason, uint32_t aNonvisibleAction); 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 * Retrieve a pointer to the 'registered with the refresh driver' flag for
@@ -356,14 +363,16 @@ protected:
* *
* No-op if aImage is null. * No-op if aImage is null.
* *
* @param aNonvisibleAction What to do if the image's visibility count is now * @param aNonvisibleAction A requested action if the frame has become
* zero. If ON_NONVISIBLE_NO_ACTION, nothing will be * nonvisible. If Nothing(), no action is
* done. If ON_NONVISIBLE_REQUEST_DISCARD, the image * requested. If DISCARD_IMAGES is specified, the
* will be asked to discard its surfaces if possible. * frame is requested to ask any images it's
* associated with to discard their surfaces if
* possible.
*/ */
void TrackImage(imgIRequest* aImage); void TrackImage(imgIRequest* aImage);
void UntrackImage(imgIRequest* aImage, void UntrackImage(imgIRequest* aImage,
uint32_t aNonvisibleAction = ON_NONVISIBLE_NO_ACTION); const Maybe<OnNonvisible>& aNonvisibleAction = Nothing());
/* MEMBERS */ /* MEMBERS */
RefPtr<imgRequestProxy> mCurrentRequest; RefPtr<imgRequestProxy> mCurrentRequest;
@@ -447,8 +456,6 @@ private:
// True when FrameCreate has been called but FrameDestroy has not. // True when FrameCreate has been called but FrameDestroy has not.
bool mFrameCreateCalled; bool mFrameCreateCalled;
uint32_t mVisibleCount;
}; };
#endif // nsImageLoadingContent_h__ #endif // nsImageLoadingContent_h__
+1 -1
View File
@@ -1141,7 +1141,7 @@ PerformanceBase::CancelNotificationObservers()
mPendingNotificationObserversTask = false; mPendingNotificationObserversTask = false;
} }
class NotifyObserversTask final : public nsCancelableRunnable class NotifyObserversTask final : public CancelableRunnable
{ {
public: public:
explicit NotifyObserversTask(PerformanceBase* aPerformance) explicit NotifyObserversTask(PerformanceBase* aPerformance)
+42 -27
View File
@@ -61,15 +61,15 @@ function compare(a, b) {
} }
var clonableObjects = [ var clonableObjects = [
{ crossThreads: true, data: 'hello world' }, 'hello world',
{ crossThreads: true, data: 123 }, 123,
{ crossThreads: true, data: null }, null,
{ crossThreads: true, data: true }, true,
{ crossThreads: true, data: new Date() }, new Date(),
{ crossThreads: true, data: [ 1, 'test', true, new Date() ] }, [ 1, 'test', true, new Date() ],
{ crossThreads: true, data: { a: true, b: null, c: new Date(), d: [ true, false, {} ] } }, { a: true, b: null, c: new Date(), d: [ true, false, {} ] },
{ crossThreads: true, data: new Blob([123], { type: 'plain/text' }) }, new Blob([123], { type: 'plain/text' }),
{ crossThreads: true, data: new ImageData(2, 2) }, new ImageData(2, 2),
]; ];
function create_fileList_forFile() { function create_fileList_forFile() {
@@ -84,7 +84,7 @@ function create_fileList_forFile() {
var domFile = fileList.files[0]; var domFile = fileList.files[0];
is(domFile.name, "prefs.js", "fileName should be prefs.js"); is(domFile.name, "prefs.js", "fileName should be prefs.js");
clonableObjects.push({ crossThreads: true, data: fileList.files }); clonableObjects.push(fileList.files);
script.destroy(); script.destroy();
next(); next();
} }
@@ -105,7 +105,7 @@ function create_fileList_forDir() {
is(fileList.files.length, 1, "Filelist has 1 element"); is(fileList.files.length, 1, "Filelist has 1 element");
ok(fileList.files[0] instanceof Directory, "We have a directory."); ok(fileList.files[0] instanceof Directory, "We have a directory.");
clonableObjects.push({ crossThreads: false, data: fileList.files }); clonableObjects.push(fileList.files);
script.destroy(); script.destroy();
next(); next();
} }
@@ -114,6 +114,34 @@ function create_fileList_forDir() {
script.sendAsyncMessage("dir.open"); 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) { function runTests(obj) {
ok(('clonableObjects' in obj) && ok(('clonableObjects' in obj) &&
('transferableObjects' in obj) && ('transferableObjects' in obj) &&
@@ -135,15 +163,8 @@ function runTests(obj) {
var object = clonableObjects[clonableObjectsId++]; var object = clonableObjects[clonableObjectsId++];
// If this test requires a cross-thread structured clone algorithm, maybe obj.send(object, []).then(function(received) {
// we have to skip it. compare(received.data, object);
if (!object.crossThread && obj.crossThread) {
runClonableTest();
return;
}
obj.send(object.data, []).then(function(received) {
compare(received.data, object.data);
runClonableTest(); runClonableTest();
}); });
} }
@@ -232,7 +253,6 @@ function test_windowToWindow() {
runTests({ runTests({
clonableObjects: true, clonableObjects: true,
transferableObjects: true, transferableObjects: true,
crossThread: false,
send: function(what, ports) { send: function(what, ports) {
return new Promise(function(r, rr) { return new Promise(function(r, rr) {
resolve = r; resolve = r;
@@ -286,7 +306,6 @@ function test_windowToIframeURL(url) {
runTests({ runTests({
clonableObjects: true, clonableObjects: true,
transferableObjects: true, transferableObjects: true,
crossThread: false,
send: function(what, ports) { send: function(what, ports) {
return new Promise(function(r, rr) { return new Promise(function(r, rr) {
resolve = r; resolve = r;
@@ -334,7 +353,6 @@ function test_workers() {
runTests({ runTests({
clonableObjects: true, clonableObjects: true,
transferableObjects: true, transferableObjects: true,
crossThread: true,
send: function(what, ports) { send: function(what, ports) {
return new Promise(function(r, rr) { return new Promise(function(r, rr) {
resolve = r; resolve = r;
@@ -378,7 +396,6 @@ function test_broadcastChannel() {
runTests({ runTests({
clonableObjects: true, clonableObjects: true,
transferableObjects: false, transferableObjects: false,
crossThread: true,
send: function(what, ports) { send: function(what, ports) {
return new Promise(function(r, rr) { return new Promise(function(r, rr) {
if (ports.length) { if (ports.length) {
@@ -424,7 +441,6 @@ function test_broadcastChannel_inWorkers() {
runTests({ runTests({
clonableObjects: true, clonableObjects: true,
transferableObjects: false, transferableObjects: false,
crossThread: true,
send: function(what, ports) { send: function(what, ports) {
return new Promise(function(r, rr) { return new Promise(function(r, rr) {
if (ports.length) { if (ports.length) {
@@ -466,7 +482,6 @@ function test_messagePort() {
runTests({ runTests({
clonableObjects: true, clonableObjects: true,
transferableObjects: true, transferableObjects: true,
crossThread: true,
send: function(what, ports) { send: function(what, ports) {
return new Promise(function(r, rr) { return new Promise(function(r, rr) {
resolve = r; resolve = r;
@@ -512,7 +527,6 @@ function test_messagePort_inWorkers() {
runTests({ runTests({
clonableObjects: true, clonableObjects: true,
transferableObjects: true, transferableObjects: true,
crossThread: true,
send: function(what, ports) { send: function(what, ports) {
return new Promise(function(r, rr) { return new Promise(function(r, rr) {
resolve = r; resolve = r;
@@ -536,6 +550,7 @@ function test_messagePort_inWorkers() {
var tests = [ var tests = [
create_fileList_forFile, create_fileList_forFile,
create_fileList_forDir, create_fileList_forDir,
create_directory,
test_windowToWindow, test_windowToWindow,
test_windowToIframe, 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_xhr_standalone.js]
[test_xmlserializer.js] [test_xmlserializer.js]
[test_cancelPrefetch.js] [test_cancelPrefetch.js]
[test_chromeutils_base64.js]
+1 -19
View File
@@ -952,25 +952,6 @@ DOMInterfaces = {
'nativeType': 'mozilla::dom::workers::PushMessageData', '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': { 'Range': {
'nativeType': 'nsRange', 'nativeType': 'nsRange',
'binaryNames': { 'binaryNames': {
@@ -1014,6 +995,7 @@ DOMInterfaces = {
'ServiceWorkerRegistration': [{ 'ServiceWorkerRegistration': [{
'nativeType': 'mozilla::dom::ServiceWorkerRegistrationMainThread', 'nativeType': 'mozilla::dom::ServiceWorkerRegistrationMainThread',
'headerFile': 'mozilla/dom/ServiceWorkerRegistration.h', 'headerFile': 'mozilla/dom/ServiceWorkerRegistration.h',
'implicitJSContext': [ 'pushManager' ],
}, { }, {
'workers': True, 'workers': True,
'nativeType': 'mozilla::dom::ServiceWorkerRegistrationWorkerThread', '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_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_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_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_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_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.") 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 { namespace cache {
class CachePushStreamChild::Callback final : public nsIInputStreamCallback class CachePushStreamChild::Callback final : public nsIInputStreamCallback
, public nsCancelableRunnable , public CancelableRunnable
{ {
public: public:
explicit Callback(CachePushStreamChild* aActor) explicit Callback(CachePushStreamChild* aActor)
@@ -89,7 +89,7 @@ private:
}; };
NS_IMPL_ISUPPORTS_INHERITED(CachePushStreamChild::Callback, NS_IMPL_ISUPPORTS_INHERITED(CachePushStreamChild::Callback,
nsCancelableRunnable, CancelableRunnable,
nsIInputStreamCallback); nsIInputStreamCallback);
CachePushStreamChild::CachePushStreamChild(Feature* aFeature, CachePushStreamChild::CachePushStreamChild(Feature* aFeature,
+1
View File
@@ -119,6 +119,7 @@ IsTrusted(const PrincipalInfo& aPrincipalInfo, bool aTestingPrefEnabled)
nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen)); nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
if (scheme.LowerCaseEqualsLiteral("https") || if (scheme.LowerCaseEqualsLiteral("https") ||
scheme.LowerCaseEqualsLiteral("app") ||
scheme.LowerCaseEqualsLiteral("file")) { scheme.LowerCaseEqualsLiteral("file")) {
return true; return true;
} }
+1 -1
View File
@@ -2158,7 +2158,7 @@ BindId(mozIStorageStatement* aState, const nsACString& aName, const nsID* aId)
char idBuf[NSID_LENGTH]; char idBuf[NSID_LENGTH];
aId->ToProvidedString(idBuf); aId->ToProvidedString(idBuf);
rv = aState->BindUTF8StringByName(aName, nsAutoCString(idBuf)); rv = aState->BindUTF8StringByName(aName, nsDependentCString(idBuf));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (NS_WARN_IF(NS_FAILED(rv))) { return 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 // be done on the thread associated with the PBackground actor. Must be
// cancelable to execute on Worker threads (which can occur when the // cancelable to execute on Worker threads (which can occur when the
// ReadStream is constructed on a child process Worker thread). // ReadStream is constructed on a child process Worker thread).
class ReadStream::Inner::NoteClosedRunnable final : public nsCancelableRunnable class ReadStream::Inner::NoteClosedRunnable final : public CancelableRunnable
{ {
public: public:
explicit NoteClosedRunnable(ReadStream::Inner* aStream) explicit NoteClosedRunnable(ReadStream::Inner* aStream)
@@ -152,7 +152,7 @@ private:
// it on the thread associated with the PBackground actor. Must be // it on the thread associated with the PBackground actor. Must be
// cancelable to execute on Worker threads (which can occur when the // cancelable to execute on Worker threads (which can occur when the
// ReadStream is constructed on a child process Worker thread). // ReadStream is constructed on a child process Worker thread).
class ReadStream::Inner::ForgetRunnable final : public nsCancelableRunnable class ReadStream::Inner::ForgetRunnable final : public CancelableRunnable
{ {
public: public:
explicit ForgetRunnable(ReadStream::Inner* aStream) explicit ForgetRunnable(ReadStream::Inner* aStream)
+2 -1
View File
@@ -419,7 +419,8 @@ TypeUtils::ProcessURL(nsACString& aUrl, bool* aSchemeValidOut,
if (aSchemeValidOut) { if (aSchemeValidOut) {
nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen)); nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
*aSchemeValidOut = scheme.LowerCaseEqualsLiteral("http") || *aSchemeValidOut = scheme.LowerCaseEqualsLiteral("http") ||
scheme.LowerCaseEqualsLiteral("https"); scheme.LowerCaseEqualsLiteral("https") ||
scheme.LowerCaseEqualsLiteral("app");
} }
uint32_t queryPos; uint32_t queryPos;
+2 -1
View File
@@ -89,7 +89,8 @@ function runTests(testFile, order) {
SimpleTest.waitForExplicitFinish(); SimpleTest.waitForExplicitFinish();
if (typeof order == "undefined") { 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", 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'] var hash = Cc['@mozilla.org/security/hash;1']
.createInstance(Ci.nsICryptoHash); .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 // Expose Cache and Fetch symbols on the global
Cu.importGlobalProperties(['caches', 'fetch']); Cu.importGlobalProperties(['caches', 'fetch']);
+10 -2
View File
@@ -431,7 +431,9 @@ static bool
IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature) IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature)
{ {
int32_t status; 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 false;
return status != nsIGfxInfo::FEATURE_STATUS_OK; return status != nsIGfxInfo::FEATURE_STATUS_OK;
@@ -442,28 +444,34 @@ HasAcceleratedLayers(const nsCOMPtr<nsIGfxInfo>& gfxInfo)
{ {
int32_t status; int32_t status;
nsCString discardFailureId;
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS,
discardFailureId,
&status); &status);
if (status) if (status)
return true; return true;
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS, nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS,
discardFailureId,
&status); &status);
if (status) if (status)
return true; return true;
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS, nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS,
discardFailureId,
&status); &status);
if (status) if (status)
return true; return true;
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS,
discardFailureId,
&status); &status);
if (status) if (status)
return true; return true;
gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_OPENGL_LAYERS,
discardFailureId,
&status); &status);
if (status) if (status)
return true; return true;
@@ -1527,7 +1535,7 @@ WebGLContext::RunContextLossTimer()
mContextLossHandler->RunTimer(); mContextLossHandler->RunTimer();
} }
class UpdateContextLossStatusTask : public nsCancelableRunnable class UpdateContextLossStatusTask : public CancelableRunnable
{ {
RefPtr<WebGLContext> mWebGL; RefPtr<WebGLContext> mWebGL;
+1 -1
View File
@@ -38,7 +38,7 @@ private:
nsCOMPtr<nsIEventTarget> mEventTarget; nsCOMPtr<nsIEventTarget> mEventTarget;
}; };
class ContextLossWorkerRunnable final : public nsCancelableRunnable class ContextLossWorkerRunnable final : public CancelableRunnable
{ {
public: public:
explicit ContextLossWorkerRunnable(nsIRunnable* aRunnable) explicit ContextLossWorkerRunnable(nsIRunnable* aRunnable)
+1 -1
View File
@@ -57,7 +57,7 @@ if (NS_FAILED(rv)) { \
return; \ return; \
} }
class WebCryptoTask : public nsCancelableRunnable, class WebCryptoTask : public CancelableRunnable,
public nsNSSShutDownObject public nsNSSShutDownObject
{ {
public: public:
+1 -1
View File
@@ -30,7 +30,7 @@ AsyncEventDispatcher::AsyncEventDispatcher(EventTarget* aTarget,
mEvent = do_QueryInterface(event); mEvent = do_QueryInterface(event);
NS_ASSERTION(mEvent, "Should never fail to create an event"); NS_ASSERTION(mEvent, "Should never fail to create an event");
mEvent->DuplicatePrivateData(); mEvent->DuplicatePrivateData();
mEvent->SetTrusted(aEvent.mFlags.mIsTrusted); mEvent->SetTrusted(aEvent.IsTrusted());
} }
NS_IMETHODIMP 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 * want to ensure that the event handler doesn't mutate the DOM at
* the wrong time, in order to avoid resulting instability. * the wrong time, in order to avoid resulting instability.
*/ */
class AsyncEventDispatcher : public nsCancelableRunnable class AsyncEventDispatcher : public CancelableRunnable
{ {
public: public:
/** /**
@@ -95,7 +95,7 @@ public:
mBlockedDoc->BlockOnload(); mBlockedDoc->BlockOnload();
} }
} }
~LoadBlockingAsyncEventDispatcher(); ~LoadBlockingAsyncEventDispatcher();
private: private:
+9 -20
View File
@@ -466,22 +466,21 @@ Event::GetTimeStamp(uint64_t* aTimeStamp)
NS_IMETHODIMP NS_IMETHODIMP
Event::StopPropagation() Event::StopPropagation()
{ {
mEvent->mFlags.mPropagationStopped = true; mEvent->StopPropagation();
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
Event::StopImmediatePropagation() Event::StopImmediatePropagation()
{ {
mEvent->mFlags.mPropagationStopped = true; mEvent->StopImmediatePropagation();
mEvent->mFlags.mImmediatePropagationStopped = true;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
Event::StopCrossProcessForwarding() Event::StopCrossProcessForwarding()
{ {
mEvent->mFlags.mNoCrossProcessBoundaryForwarding = true; mEvent->StopCrossProcessForwarding();
return NS_OK; return NS_OK;
} }
@@ -520,17 +519,7 @@ Event::PreventDefaultInternal(bool aCalledByDefaultHandler)
return; return;
} }
mEvent->mFlags.mDefaultPrevented = true; mEvent->PreventDefault(aCalledByDefaultHandler);
// 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;
}
if (!IsTrusted()) { if (!IsTrusted()) {
return; return;
@@ -763,7 +752,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
} }
break; break;
case eKeyboardEventClass: case eKeyboardEventClass:
if (aEvent->mFlags.mIsTrusted) { if (aEvent->IsTrusted()) {
uint32_t key = aEvent->AsKeyboardEvent()->keyCode; uint32_t key = aEvent->AsKeyboardEvent()->keyCode;
switch(aEvent->mMessage) { switch(aEvent->mMessage) {
case eKeyPress: case eKeyPress:
@@ -793,7 +782,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
} }
break; break;
case eTouchEventClass: case eTouchEventClass:
if (aEvent->mFlags.mIsTrusted) { if (aEvent->IsTrusted()) {
switch (aEvent->mMessage) { switch (aEvent->mMessage) {
case eTouchStart: case eTouchStart:
if (PopupAllowedForEvent("touchstart")) { if (PopupAllowedForEvent("touchstart")) {
@@ -811,7 +800,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
} }
break; break;
case eMouseEventClass: case eMouseEventClass:
if (aEvent->mFlags.mIsTrusted && if (aEvent->IsTrusted() &&
aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) { aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
switch(aEvent->mMessage) { switch(aEvent->mMessage) {
case eMouseUp: case eMouseUp:
@@ -1082,14 +1071,14 @@ Event::DefaultPrevented(JSContext* aCx) const
NS_ENSURE_TRUE(mEvent, false); NS_ENSURE_TRUE(mEvent, false);
// If preventDefault() has never been called, just return false. // If preventDefault() has never been called, just return false.
if (!mEvent->mFlags.mDefaultPrevented) { if (!mEvent->DefaultPrevented()) {
return false; return false;
} }
// If preventDefault() has been called by content, return true. Otherwise, // If preventDefault() has been called by content, return true. Otherwise,
// i.e., preventDefault() has been called by chrome, return true only when // i.e., preventDefault() has been called by chrome, return true only when
// this is called by chrome. // this is called by chrome.
return mEvent->mFlags.mDefaultPreventedByContent || IsChrome(aCx); return mEvent->DefaultPreventedByContent() || IsChrome(aCx);
} }
double double
+2 -2
View File
@@ -186,7 +186,7 @@ public:
bool DefaultPrevented() const bool DefaultPrevented() const
{ {
return mEvent->mFlags.mDefaultPrevented; return mEvent->DefaultPrevented();
} }
bool MultipleActionsPrevented() const bool MultipleActionsPrevented() const
@@ -196,7 +196,7 @@ public:
bool IsTrusted() const bool IsTrusted() const
{ {
return mEvent->mFlags.mIsTrusted; return mEvent->IsTrusted();
} }
bool IsSynthesized() const bool IsSynthesized() const
+59 -12
View File
@@ -85,9 +85,46 @@ private:
uint32_t mInitialCount; 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_FORCE_CONTENT_DISPATCH (1 << 0)
#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1) #define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
#define NS_TARGET_CHAIN_MAY_HAVE_MANAGER (1 << 2) #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. // EventTargetChainItem represents a single item in the event target chain.
class EventTargetChainItem class EventTargetChainItem
@@ -210,6 +247,11 @@ public:
if (aVisitor.mEvent->mFlags.mPropagationStopped) { if (aVisitor.mEvent->mFlags.mPropagationStopped) {
return; return;
} }
if (aVisitor.mEvent->mFlags.mOnlySystemGroupDispatchInContent &&
!aVisitor.mEvent->mFlags.mInSystemGroup &&
!IsCurrentTargetChrome()) {
return;
}
if (!mManager) { if (!mManager) {
if (!MayHaveListenerManager() && !aCd.MayHaveNewListenerManager()) { if (!MayHaveListenerManager() && !aCd.MayHaveNewListenerManager()) {
return; return;
@@ -233,6 +275,7 @@ public:
*/ */
void PostHandleEvent(EventChainPostVisitor& aVisitor); void PostHandleEvent(EventChainPostVisitor& aVisitor);
private:
nsCOMPtr<EventTarget> mTarget; nsCOMPtr<EventTarget> mTarget;
uint16_t mFlags; uint16_t mFlags;
uint16_t mItemFlags; uint16_t mItemFlags;
@@ -241,6 +284,17 @@ public:
nsCOMPtr<EventTarget> mNewTarget; nsCOMPtr<EventTarget> mNewTarget;
// Cache mTarget's event listener manager. // Cache mTarget's event listener manager.
RefPtr<EventListenerManager> mManager; 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) EventTargetChainItem::EventTargetChainItem(EventTarget* aTarget)
@@ -468,18 +522,9 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
} }
if (aEvent->mFlags.mOnlyChromeDispatch) { if (aEvent->mFlags.mOnlyChromeDispatch) {
nsCOMPtr<nsINode> node = do_QueryInterface(aTarget); nsCOMPtr<nsIDocument> doc;
if (!node) { if (!IsEventTargetChrome(target, getter_AddRefs(doc)) && doc) {
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aTarget); nsPIDOMWindow* win = doc->GetInnerWindow();
if (win) {
node = win->GetExtantDoc();
}
}
NS_ENSURE_STATE(node);
nsIDocument* doc = node->OwnerDoc();
if (!nsContentUtils::IsChromeDoc(doc)) {
nsPIDOMWindow* win = doc ? doc->GetInnerWindow() : nullptr;
// If we can't dispatch the event to chrome, do nothing. // If we can't dispatch the event to chrome, do nothing.
EventTarget* piTarget = win ? win->GetParentTarget() : nullptr; EventTarget* piTarget = win ? win->GetParentTarget() : nullptr;
if (!piTarget) { if (!piTarget) {
@@ -490,6 +535,8 @@ EventDispatcher::Dispatch(nsISupports* aTarget,
aEvent->target = target; aEvent->target = target;
// but use chrome event handler or TabChildGlobal for event target chain. // but use chrome event handler or TabChildGlobal for event target chain.
target = piTarget; 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) nsEventStatus* aEventStatus)
{ {
//Set the value of the internal PreventDefault flag properly based on aEventStatus //Set the value of the internal PreventDefault flag properly based on aEventStatus
if (*aEventStatus == nsEventStatus_eConsumeNoDefault) { if (!aEvent->DefaultPrevented() &&
aEvent->mFlags.mDefaultPrevented = true; *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); nsAutoTObserverArray<Listener, 2>::EndLimitedIterator iter(mListeners);
@@ -1174,8 +1177,7 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
if (ListenerCanHandle(listener, aEvent)) { if (ListenerCanHandle(listener, aEvent)) {
hasListener = true; hasListener = true;
if (listener->IsListening(aEvent) && if (listener->IsListening(aEvent) &&
(aEvent->mFlags.mIsTrusted || (aEvent->IsTrusted() || listener->mFlags.mAllowUntrustedEvents)) {
listener->mFlags.mAllowUntrustedEvents)) {
if (!*aDOMEvent) { if (!*aDOMEvent) {
// This is tiny bit slow, but happens only once per event. // This is tiny bit slow, but happens only once per event.
nsCOMPtr<EventTarget> et = nsCOMPtr<EventTarget> et =
@@ -1237,7 +1239,7 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
mNoListenerForEventAtom = aEvent->userType; mNoListenerForEventAtom = aEvent->userType;
} }
if (aEvent->mFlags.mDefaultPrevented) { if (aEvent->DefaultPrevented()) {
*aEventStatus = nsEventStatus_eConsumeNoDefault; *aEventStatus = nsEventStatus_eConsumeNoDefault;
} }
} }
+36 -36
View File
@@ -537,7 +537,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
// Do not take account eMouseEnterIntoWidget/ExitFromWidget so that loading // Do not take account eMouseEnterIntoWidget/ExitFromWidget so that loading
// a page when user is not active doesn't change the state to active. // a page when user is not active doesn't change the state to active.
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
if (aEvent->mFlags.mIsTrusted && if (aEvent->IsTrusted() &&
((mouseEvent && mouseEvent->IsReal() && ((mouseEvent && mouseEvent->IsReal() &&
IsMessageMouseUserActivity(mouseEvent->mMessage)) || IsMessageMouseUserActivity(mouseEvent->mMessage)) ||
aEvent->mClass == eWheelEventClass || aEvent->mClass == eWheelEventClass ||
@@ -585,7 +585,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
#endif #endif
// Store last known screenPoint and clientPoint so pointer lock // Store last known screenPoint and clientPoint so pointer lock
// can use these values as constants. // can use these values as constants.
if (aEvent->mFlags.mIsTrusted && if (aEvent->IsTrusted() &&
((mouseEvent && mouseEvent->IsReal()) || ((mouseEvent && mouseEvent->IsReal()) ||
aEvent->mClass == eWheelEventClass) && aEvent->mClass == eWheelEventClass) &&
!sIsPointerLocked) { !sIsPointerLocked) {
@@ -651,7 +651,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
// from ESM::DispatchMouseOrPointerEvent (sending is permanent)). // from ESM::DispatchMouseOrPointerEvent (sending is permanent)).
// Flag mNoCrossProcessBoundaryForwarding helps to // Flag mNoCrossProcessBoundaryForwarding helps to
// suppress sending accidental event from widget code. // suppress sending accidental event from widget code.
aEvent->mFlags.mNoCrossProcessBoundaryForwarding = true; aEvent->StopCrossProcessForwarding();
break; break;
case eMouseExitFromWidget: case eMouseExitFromWidget:
// If this is a remote frame, we receive eMouseExitFromWidget from the // 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. // Flag helps to suppress double event sending into process of content.
// For more information see comment above, at eMouseEnterIntoWidget case. // 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 // If the event is not a top-level window exit, then it's not
// really an exit --- we may have traversed widget boundaries but // really an exit --- we may have traversed widget boundaries but
@@ -742,10 +742,10 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
(modifierMask == Prefs::ChromeAccessModifierMask() || (modifierMask == Prefs::ChromeAccessModifierMask() ||
modifierMask == Prefs::ContentAccessModifierMask())) { modifierMask == Prefs::ContentAccessModifierMask())) {
AutoTArray<uint32_t, 10> accessCharCodes; AutoTArray<uint32_t, 10> accessCharCodes;
nsContentUtils::GetAccessKeyCandidates(keyEvent, accessCharCodes); keyEvent->GetAccessKeyCandidates(accessCharCodes);
if (HandleAccessKey(aPresContext, accessCharCodes, if (HandleAccessKey(aPresContext, accessCharCodes,
keyEvent->mFlags.mIsTrusted, modifierMask)) { keyEvent->IsTrusted(), modifierMask)) {
*aStatus = nsEventStatus_eConsumeNoDefault; *aStatus = nsEventStatus_eConsumeNoDefault;
} }
} }
@@ -780,7 +780,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
case eWheelOperationStart: case eWheelOperationStart:
case eWheelOperationEnd: case eWheelOperationEnd:
{ {
NS_ASSERTION(aEvent->mFlags.mIsTrusted, NS_ASSERTION(aEvent->IsTrusted(),
"Untrusted wheel event shouldn't be here"); "Untrusted wheel event shouldn't be here");
nsIContent* content = GetFocusedContent(); nsIContent* content = GetFocusedContent();
@@ -825,7 +825,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
DoContentCommandScrollEvent(aEvent->AsContentCommandEvent()); DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
break; break;
case eCompositionStart: case eCompositionStart:
if (aEvent->mFlags.mIsTrusted) { if (aEvent->IsTrusted()) {
// If the event is trusted event, set the selected text to data of // If the event is trusted event, set the selected text to data of
// composition event. // composition event.
WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent(); WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
@@ -1382,7 +1382,7 @@ EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
nsIFrame* inDownFrame, nsIFrame* inDownFrame,
WidgetGUIEvent* inMouseDownEvent) WidgetGUIEvent* inMouseDownEvent)
{ {
if (!inMouseDownEvent->mFlags.mIsTrusted || if (!inMouseDownEvent->IsTrusted() ||
IsRemoteTarget(mGestureDownContent) || IsRemoteTarget(mGestureDownContent) ||
sIsPointerLocked) { sIsPointerLocked) {
return; return;
@@ -1740,11 +1740,10 @@ EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget(); nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
// get the widget from the target frame // get the widget from the target frame
WidgetDragEvent startEvent(aEvent->mFlags.mIsTrusted, WidgetDragEvent startEvent(aEvent->IsTrusted(), eDragStart, widget);
eDragStart, widget);
FillInEventFromGestureDown(&startEvent); FillInEventFromGestureDown(&startEvent);
WidgetDragEvent gestureEvent(aEvent->mFlags.mIsTrusted, WidgetDragEvent gestureEvent(aEvent->IsTrusted(),
eLegacyDragGesture, widget); eLegacyDragGesture, widget);
FillInEventFromGestureDown(&gestureEvent); FillInEventFromGestureDown(&gestureEvent);
@@ -1800,7 +1799,7 @@ EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
targetContent, selection); targetContent, selection);
if (dragStarted) { if (dragStarted) {
sActiveESM = nullptr; sActiveESM = nullptr;
aEvent->mFlags.mPropagationStopped = true; aEvent->StopPropagation();
} }
} }
@@ -2232,7 +2231,7 @@ EventStateManager::DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
nsWeakFrame targetFrame(aTargetFrame); nsWeakFrame targetFrame(aTargetFrame);
MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault && MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->mFlags.mDefaultPrevented, !aEvent->DefaultPrevented(),
"If you make legacy events dispatched for default prevented wheel " "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY"); "event, you need to initialize stateX and stateY");
EventState stateX, stateY; EventState stateX, stateY;
@@ -2272,11 +2271,14 @@ EventStateManager::DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
} }
} }
if (stateY.mDefaultPrevented || stateX.mDefaultPrevented) { if (stateY.mDefaultPrevented) {
*aStatus = nsEventStatus_eConsumeNoDefault; *aStatus = nsEventStatus_eConsumeNoDefault;
aEvent->mFlags.mDefaultPrevented = true; aEvent->PreventDefault(!stateY.mDefaultPreventedByContent);
aEvent->mFlags.mDefaultPreventedByContent |= }
stateY.mDefaultPreventedByContent || stateX.mDefaultPreventedByContent;
if (stateX.mDefaultPrevented) {
*aStatus = nsEventStatus_eConsumeNoDefault;
aEvent->PreventDefault(!stateX.mDefaultPreventedByContent);
} }
} }
@@ -2297,7 +2299,7 @@ EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
targetContent = targetContent->GetParent(); targetContent = targetContent->GetParent();
} }
WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted, WidgetMouseScrollEvent event(aEvent->IsTrusted(),
eLegacyMouseLineOrPageScroll, aEvent->widget); eLegacyMouseLineOrPageScroll, aEvent->widget);
event.mFlags.mDefaultPrevented = aState.mDefaultPrevented; event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent; event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
@@ -2315,8 +2317,8 @@ EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(), EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
&event, nullptr, &status); &event, nullptr, &status);
aState.mDefaultPrevented = aState.mDefaultPrevented =
event.mFlags.mDefaultPrevented || status == nsEventStatus_eConsumeNoDefault; event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
aState.mDefaultPreventedByContent = event.mFlags.mDefaultPreventedByContent; aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
} }
void void
@@ -2337,7 +2339,7 @@ EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
targetContent = targetContent->GetParent(); targetContent = targetContent->GetParent();
} }
WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted, WidgetMouseScrollEvent event(aEvent->IsTrusted(),
eLegacyMousePixelScroll, aEvent->widget); eLegacyMousePixelScroll, aEvent->widget);
event.mFlags.mDefaultPrevented = aState.mDefaultPrevented; event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent; event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
@@ -2355,8 +2357,8 @@ EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(), EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
&event, nullptr, &status); &event, nullptr, &status);
aState.mDefaultPrevented = aState.mDefaultPrevented =
event.mFlags.mDefaultPrevented || status == nsEventStatus_eConsumeNoDefault; event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
aState.mDefaultPreventedByContent = event.mFlags.mDefaultPreventedByContent; aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
} }
nsIFrame* nsIFrame*
@@ -3133,7 +3135,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
break; break;
case eWheelOperationEnd: case eWheelOperationEnd:
{ {
MOZ_ASSERT(aEvent->mFlags.mIsTrusted); MOZ_ASSERT(aEvent->IsTrusted());
ScrollbarsForWheel::MayInactivate(); ScrollbarsForWheel::MayInactivate();
WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent(); WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
nsIScrollableFrame* scrollTarget = nsIScrollableFrame* scrollTarget =
@@ -3147,7 +3149,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
case eWheel: case eWheel:
case eWheelOperationStart: case eWheelOperationStart:
{ {
MOZ_ASSERT(aEvent->mFlags.mIsTrusted); MOZ_ASSERT(aEvent->IsTrusted());
if (*aStatus == nsEventStatus_eConsumeNoDefault) { if (*aStatus == nsEventStatus_eConsumeNoDefault) {
ScrollbarsForWheel::Inactivate(); ScrollbarsForWheel::Inactivate();
@@ -3180,7 +3182,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
// APZ to handle it, because it will track the velocity and predicted // APZ to handle it, because it will track the velocity and predicted
// destination from the momentum. // destination from the momentum.
if (wheelEvent->mFlags.mHandledByAPZ) { if (wheelEvent->mFlags.mHandledByAPZ) {
wheelEvent->mFlags.mDefaultPrevented = true; wheelEvent->PreventDefault();
} }
action = WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent); action = WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
} else if (wheelEvent->mFlags.mHandledByAPZ) { } else if (wheelEvent->mFlags.mHandledByAPZ) {
@@ -3426,8 +3428,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
getter_AddRefs(targetContent)); getter_AddRefs(targetContent));
nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget(); nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
WidgetDragEvent event(aEvent->mFlags.mIsTrusted, WidgetDragEvent event(aEvent->IsTrusted(), eLegacyDragDrop, widget);
eLegacyDragDrop, widget);
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
event.refPoint = mouseEvent->refPoint; event.refPoint = mouseEvent->refPoint;
@@ -3853,7 +3854,7 @@ CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent,
nsAutoPtr<WidgetPointerEvent> newPointerEvent; nsAutoPtr<WidgetPointerEvent> newPointerEvent;
newPointerEvent = newPointerEvent =
new WidgetPointerEvent(aMouseEvent->mFlags.mIsTrusted, aMessage, new WidgetPointerEvent(aMouseEvent->IsTrusted(), aMessage,
aMouseEvent->widget); aMouseEvent->widget);
newPointerEvent->isPrimary = sourcePointer->isPrimary; newPointerEvent->isPrimary = sourcePointer->isPrimary;
newPointerEvent->pointerId = sourcePointer->pointerId; newPointerEvent->pointerId = sourcePointer->pointerId;
@@ -3867,7 +3868,7 @@ CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent,
aNewEvent = newPointerEvent.forget(); aNewEvent = newPointerEvent.forget();
} else { } else {
aNewEvent = aNewEvent =
new WidgetMouseEvent(aMouseEvent->mFlags.mIsTrusted, aMessage, new WidgetMouseEvent(aMouseEvent->IsTrusted(), aMessage,
aMouseEvent->widget, WidgetMouseEvent::eReal); aMouseEvent->widget, WidgetMouseEvent::eReal);
aNewEvent->relatedTarget = aRelatedContent; aNewEvent->relatedTarget = aRelatedContent;
} }
@@ -4263,7 +4264,7 @@ EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent)
} else if (aMouseEvent->refPoint == sSynthCenteringPoint) { } else if (aMouseEvent->refPoint == sSynthCenteringPoint) {
// This is the "synthetic native" event we dispatched to re-center the // 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. // 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 // Clear sSynthCenteringPoint so we don't cancel other events
// targeted at the center. // targeted at the center.
sSynthCenteringPoint = kInvalidRefPoint; sSynthCenteringPoint = kInvalidRefPoint;
@@ -4509,8 +4510,7 @@ EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
nsWeakFrame& aTargetFrame) nsWeakFrame& aTargetFrame)
{ {
nsEventStatus status = nsEventStatus_eIgnore; nsEventStatus status = nsEventStatus_eIgnore;
WidgetDragEvent event(aDragEvent->mFlags.mIsTrusted, aMessage, WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->widget);
aDragEvent->widget);
event.refPoint = aDragEvent->refPoint; event.refPoint = aDragEvent->refPoint;
event.modifiers = aDragEvent->modifiers; event.modifiers = aDragEvent->modifiers;
event.buttons = aDragEvent->buttons; event.buttons = aDragEvent->buttons;
@@ -4654,7 +4654,7 @@ EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
nsWeakFrame aCurrentTarget, nsWeakFrame aCurrentTarget,
bool aNoContentDispatch) bool aNoContentDispatch)
{ {
WidgetMouseEvent event(aEvent->mFlags.mIsTrusted, aMessage, WidgetMouseEvent event(aEvent->IsTrusted(), aMessage,
aEvent->widget, WidgetMouseEvent::eReal); aEvent->widget, WidgetMouseEvent::eReal);
event.refPoint = aEvent->refPoint; event.refPoint = aEvent->refPoint;
@@ -5918,7 +5918,7 @@ AutoHandlingUserInputStatePusher::AutoHandlingUserInputStatePusher(
nsIPresShell::SetCapturingContent(nullptr, 0); nsIPresShell::SetCapturingContent(nullptr, 0);
nsIPresShell::AllowMouseCapture(true); nsIPresShell::AllowMouseCapture(true);
} }
if (!aDocument || !aEvent || !aEvent->mFlags.mIsTrusted) { if (!aDocument || !aEvent || !aEvent->IsTrusted()) {
return; return;
} }
mResetFMMouseButtonHandlingState = mResetFMMouseButtonHandlingState =
+5 -3
View File
@@ -755,8 +755,8 @@ IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext,
if (!mUpdatePreference.WantMouseButtonEventOnChar()) { if (!mUpdatePreference.WantMouseButtonEventOnChar()) {
return false; return false;
} }
if (!aMouseEvent->mFlags.mIsTrusted || if (!aMouseEvent->IsTrusted() ||
aMouseEvent->mFlags.mDefaultPrevented || aMouseEvent->DefaultPrevented() ||
!aMouseEvent->widget) { !aMouseEvent->widget) {
return false; return false;
} }
@@ -822,7 +822,9 @@ IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext,
} }
bool consumed = (rv == NS_SUCCESS_EVENT_CONSUMED); bool consumed = (rv == NS_SUCCESS_EVENT_CONSUMED);
aMouseEvent->mFlags.mDefaultPrevented = consumed; if (consumed) {
aMouseEvent->PreventDefault();
}
return consumed; return consumed;
} }
+3 -3
View File
@@ -1164,7 +1164,7 @@ IMEStateManager::DispatchCompositionEvent(
GetBoolName(aCompositionEvent->mFlags.mPropagationStopped), GetBoolName(aCompositionEvent->mFlags.mPropagationStopped),
GetBoolName(aIsSynthesized), tabParent.get())); GetBoolName(aIsSynthesized), tabParent.get()));
if (!aCompositionEvent->mFlags.mIsTrusted || if (!aCompositionEvent->IsTrusted() ||
aCompositionEvent->mFlags.mPropagationStopped) { aCompositionEvent->mFlags.mPropagationStopped) {
return; return;
} }
@@ -1261,7 +1261,7 @@ IMEStateManager::HandleSelectionEvent(nsPresContext* aPresContext,
GetBoolName(aSelectionEvent->mFlags.mIsTrusted), GetBoolName(aSelectionEvent->mFlags.mIsTrusted),
tabParent.get())); tabParent.get()));
if (!aSelectionEvent->mFlags.mIsTrusted) { if (!aSelectionEvent->IsTrusted()) {
return; return;
} }
@@ -1303,7 +1303,7 @@ IMEStateManager::OnCompositionEventDiscarded(
GetBoolName(aCompositionEvent->widget->Destroyed()), GetBoolName(aCompositionEvent->widget->Destroyed()),
GetBoolName(aCompositionEvent->mFlags.mIsTrusted))); GetBoolName(aCompositionEvent->mFlags.mIsTrusted)));
if (!aCompositionEvent->mFlags.mIsTrusted) { if (!aCompositionEvent->IsTrusted()) {
return; return;
} }
+4 -4
View File
@@ -118,7 +118,7 @@ TextComposition::CloneAndDispatchAs(
MOZ_ASSERT(IsValidStateForComposition(aCompositionEvent->widget), MOZ_ASSERT(IsValidStateForComposition(aCompositionEvent->widget),
"Should be called only when it's safe to dispatch an event"); "Should be called only when it's safe to dispatch an event");
WidgetCompositionEvent compositionEvent(aCompositionEvent->mFlags.mIsTrusted, WidgetCompositionEvent compositionEvent(aCompositionEvent->IsTrusted(),
aMessage, aCompositionEvent->widget); aMessage, aCompositionEvent->widget);
compositionEvent.time = aCompositionEvent->time; compositionEvent.time = aCompositionEvent->time;
compositionEvent.timeStamp = aCompositionEvent->timeStamp; compositionEvent.timeStamp = aCompositionEvent->timeStamp;
@@ -159,7 +159,7 @@ TextComposition::OnCompositionEventDiscarded(
// Note that this method is never called for synthesized events for emulating // Note that this method is never called for synthesized events for emulating
// commit or cancel composition. // commit or cancel composition.
MOZ_ASSERT(aCompositionEvent->mFlags.mIsTrusted, MOZ_ASSERT(aCompositionEvent->IsTrusted(),
"Shouldn't be called with untrusted event"); "Shouldn't be called with untrusted event");
if (mTabParent) { if (mTabParent) {
@@ -243,7 +243,7 @@ TextComposition::DispatchCompositionEvent(
// remote process. // remote process.
if (mTabParent) { if (mTabParent) {
Unused << mTabParent->SendCompositionEvent(*aCompositionEvent); Unused << mTabParent->SendCompositionEvent(*aCompositionEvent);
aCompositionEvent->mFlags.mPropagationStopped = true; aCompositionEvent->StopPropagation();
if (aCompositionEvent->CausesDOMTextEvent()) { if (aCompositionEvent->CausesDOMTextEvent()) {
mLastData = aCompositionEvent->mData; mLastData = aCompositionEvent->mData;
mLastRanges = aCompositionEvent->mRanges; mLastRanges = aCompositionEvent->mRanges;
@@ -411,7 +411,7 @@ TextComposition::HandleSelectionEvent(nsPresContext* aPresContext,
// remote process. // remote process.
if (aTabParent) { if (aTabParent) {
Unused << aTabParent->SendSelectionEvent(*aSelectionEvent); Unused << aTabParent->SendSelectionEvent(*aSelectionEvent);
aSelectionEvent->mFlags.mPropagationStopped = true; aSelectionEvent->StopPropagation();
return; return;
} }
+6 -21
View File
@@ -64,25 +64,6 @@ Request::RequestContextEnabled(JSContext* aCx, JSObject* aObj)
return workerPrivate->RequestContextEnabled(); 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> already_AddRefed<InternalRequest>
Request::GetInternalRequest() Request::GetInternalRequest()
{ {
@@ -384,7 +365,10 @@ Request::Constructor(const GlobalObject& aGlobal,
nsresult rv = principal->CheckMayLoad(uri, /* report */ false, nsresult rv = principal->CheckMayLoad(uri, /* report */ false,
/* allowIfInheritsPrincipal */ false); /* allowIfInheritsPrincipal */ false);
if (NS_FAILED(rv)) { 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; return nullptr;
} }
} }
@@ -412,7 +396,8 @@ Request::Constructor(const GlobalObject& aGlobal,
new ReferrerSameOriginChecker(worker, referrerURL, rv); new ReferrerSameOriginChecker(worker, referrerURL, rv);
checker->Dispatch(aRv); checker->Dispatch(aRv);
if (aRv.Failed() || NS_FAILED(rv)) { 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; return nullptr;
} }
} }
-2
View File
@@ -36,8 +36,6 @@ public:
static bool static bool
RequestContextEnabled(JSContext* aCx, JSObject* aObj); RequestContextEnabled(JSContext* aCx, JSObject* aObj);
static bool
RequestCacheEnabled(JSContext* aCx, JSObject* aObj);
JSObject* JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
+109 -88
View File
@@ -9,23 +9,32 @@
#include "mozilla/dom/Directory.h" #include "mozilla/dom/Directory.h"
#include "mozilla/dom/FileSystemBase.h" #include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h" #include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/PFileSystemParams.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "nsIFile.h" #include "nsIFile.h"
#include "nsStringGlue.h" #include "nsStringGlue.h"
namespace mozilla { namespace mozilla {
using namespace ipc;
namespace dom { namespace dom {
/* static */ already_AddRefed<CreateDirectoryTask> /**
CreateDirectoryTask::Create(FileSystemBase* aFileSystem, * CreateDirectoryTaskChild
nsIFile* aTargetPath, */
ErrorResult& aRv)
/* static */ already_AddRefed<CreateDirectoryTaskChild>
CreateDirectoryTaskChild::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
ErrorResult& aRv)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem); MOZ_ASSERT(aFileSystem);
RefPtr<CreateDirectoryTask> task = RefPtr<CreateDirectoryTaskChild> task =
new CreateDirectoryTask(aFileSystem, aTargetPath); new CreateDirectoryTaskChild(aFileSystem, aTargetPath);
// aTargetPath can be null. In this case SetError will be called. // aTargetPath can be null. In this case SetError will be called.
@@ -44,63 +53,30 @@ CreateDirectoryTask::Create(FileSystemBase* aFileSystem,
return task.forget(); return task.forget();
} }
/* static */ already_AddRefed<CreateDirectoryTask> CreateDirectoryTaskChild::CreateDirectoryTaskChild(FileSystemBase* aFileSystem,
CreateDirectoryTask::Create(FileSystemBase* aFileSystem, nsIFile* aTargetPath)
const FileSystemCreateDirectoryParams& aParam, : FileSystemTaskChildBase(aFileSystem)
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)
, mTargetPath(aTargetPath) , mTargetPath(aTargetPath)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem); MOZ_ASSERT(aFileSystem);
} }
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem, CreateDirectoryTaskChild::~CreateDirectoryTaskChild()
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
{ {
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!"); MOZ_ASSERT(NS_IsMainThread());
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!");
} }
already_AddRefed<Promise> already_AddRefed<Promise>
CreateDirectoryTask::GetPromise() CreateDirectoryTaskChild::GetPromise()
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return RefPtr<Promise>(mPromise).forget(); return RefPtr<Promise>(mPromise).forget();
} }
FileSystemParams FileSystemParams
CreateDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath, CreateDirectoryTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const ErrorResult& aRv) const
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
@@ -113,11 +89,92 @@ CreateDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
return FileSystemCreateDirectoryParams(aSerializedDOMPath, path); return FileSystemCreateDirectoryParams(aSerializedDOMPath, path);
} }
FileSystemResponseValue void
CreateDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const CreateDirectoryTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); 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; nsAutoString path;
aRv = mTargetPath->GetPath(path); aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
@@ -127,20 +184,8 @@ CreateDirectoryTask::GetSuccessRequestResult(ErrorResult& aRv) const
return FileSystemDirectoryResponse(path); 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 nsresult
CreateDirectoryTask::Work() CreateDirectoryTaskParent::IOWork()
{ {
MOZ_ASSERT(XRE_IsParentProcess(), MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!"); "Only call from parent process!");
@@ -169,33 +214,9 @@ CreateDirectoryTask::Work()
} }
void void
CreateDirectoryTask::HandlerCallback() CreateDirectoryTaskParent::GetPermissionAccessType(nsCString& aAccess) const
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); aAccess.AssignLiteral(CREATE_DIRECTORY_TASK_PERMISSION);
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");
} }
} // namespace dom } // namespace dom
+38 -23
View File
@@ -11,27 +11,24 @@
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "mozilla/ErrorResult.h" #include "mozilla/ErrorResult.h"
#define CREATE_DIRECTORY_TASK_PERMISSION "create"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
class FileSystemCreateDirectoryParams;
class Promise; class Promise;
class CreateDirectoryTask final : public FileSystemTaskBase class CreateDirectoryTaskChild final : public FileSystemTaskChildBase
{ {
public: public:
static already_AddRefed<CreateDirectoryTask> static already_AddRefed<CreateDirectoryTaskChild>
Create(FileSystemBase* aFileSystem, Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath, nsIFile* aTargetPath,
ErrorResult& aRv); ErrorResult& aRv);
static already_AddRefed<CreateDirectoryTask>
Create(FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual virtual
~CreateDirectoryTask(); ~CreateDirectoryTaskChild();
already_AddRefed<Promise> already_AddRefed<Promise>
GetPromise(); GetPromise();
@@ -39,36 +36,54 @@ public:
virtual void virtual void
GetPermissionAccessType(nsCString& aAccess) const override; GetPermissionAccessType(nsCString& aAccess) const override;
virtual void
HandlerCallback() override;
protected: protected:
virtual FileSystemParams virtual FileSystemParams
GetRequestParams(const nsString& aSerializedDOMPath, GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override; ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue, SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override; ErrorResult& aRv) override;
virtual nsresult
Work() override;
virtual void
HandlerCallback() override;
private: private:
CreateDirectoryTask(FileSystemBase* aFileSystem, CreateDirectoryTaskChild(FileSystemBase* aFileSystem,
nsIFile* aTargetPath); nsIFile* aTargetPath);
CreateDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent);
RefPtr<Promise> mPromise; RefPtr<Promise> mPromise;
nsCOMPtr<nsIFile> mTargetPath; 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 dom
} // namespace mozilla } // namespace mozilla
+170 -152
View File
@@ -5,6 +5,8 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */ * You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CreateFileTask.h" #include "CreateFileTask.h"
#include "CreateDirectoryTask.h"
#include "RemoveTask.h"
#include <algorithm> #include <algorithm>
@@ -12,46 +14,49 @@
#include "mozilla/dom/File.h" #include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemBase.h" #include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h" #include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/PFileSystemParams.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
#include "mozilla/dom/ipc/BlobChild.h" #include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/dom/ipc/BlobParent.h" #include "mozilla/dom/ipc/BlobParent.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "nsIFile.h" #include "nsIFile.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "nsIOutputStream.h" #include "nsIOutputStream.h"
#include "nsStringGlue.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 mozilla {
namespace dom { namespace dom {
uint32_t CreateFileTask::sOutputBufferSize = 0; /**
*CreateFileTaskChild
*/
/* static */ already_AddRefed<CreateFileTask> /* static */ already_AddRefed<CreateFileTaskChild>
CreateFileTask::Create(FileSystemBase* aFileSystem, CreateFileTaskChild::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath, nsIFile* aTargetPath,
Blob* aBlobData, Blob* aBlobData,
InfallibleTArray<uint8_t>& aArrayData, InfallibleTArray<uint8_t>& aArrayData,
bool aReplace, bool aReplace,
ErrorResult& aRv) ErrorResult& aRv)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem); MOZ_ASSERT(aFileSystem);
RefPtr<CreateFileTask> task = RefPtr<CreateFileTaskChild> task =
new CreateFileTask(aFileSystem, aTargetPath, aReplace); new CreateFileTaskChild(aFileSystem, aTargetPath, aReplace);
// aTargetPath can be null. In this case SetError will be called. // aTargetPath can be null. In this case SetError will be called.
task->GetOutputBufferSize();
if (aBlobData) { if (aBlobData) {
if (XRE_IsParentProcess()) { task->mBlobImpl = aBlobData->Impl();
aBlobData->GetInternalStream(getter_AddRefs(task->mBlobStream), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
} else {
task->mBlobData = aBlobData;
}
} }
task->mArrayData.SwapElements(aArrayData); task->mArrayData.SwapElements(aArrayData);
@@ -71,53 +76,10 @@ CreateFileTask::Create(FileSystemBase* aFileSystem,
return task.forget(); return task.forget();
} }
/* static */ already_AddRefed<CreateFileTask> CreateFileTaskChild::CreateFileTaskChild(FileSystemBase* aFileSystem,
CreateFileTask::Create(FileSystemBase* aFileSystem, nsIFile* aTargetPath,
const FileSystemCreateFileParams& aParam, bool aReplace)
FileSystemRequestParent* aParent, : FileSystemTaskChildBase(aFileSystem)
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)
, mTargetPath(aTargetPath) , mTargetPath(aTargetPath)
, mReplace(aReplace) , mReplace(aReplace)
{ {
@@ -125,37 +87,21 @@ CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem,
MOZ_ASSERT(aFileSystem); MOZ_ASSERT(aFileSystem);
} }
CreateFileTask::CreateFileTask(FileSystemBase* aFileSystem, CreateFileTaskChild::~CreateFileTaskChild()
const FileSystemCreateFileParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
, mReplace(false)
{ {
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!"); MOZ_ASSERT(NS_IsMainThread());
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();
}
} }
already_AddRefed<Promise> already_AddRefed<Promise>
CreateFileTask::GetPromise() CreateFileTaskChild::GetPromise()
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return RefPtr<Promise>(mPromise).forget(); return RefPtr<Promise>(mPromise).forget();
} }
FileSystemParams FileSystemParams
CreateFileTask::GetRequestParams(const nsString& aSerializedDOMPath, CreateFileTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const ErrorResult& aRv) const
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
FileSystemCreateFileParams param; FileSystemCreateFileParams param;
@@ -166,12 +112,21 @@ CreateFileTask::GetRequestParams(const nsString& aSerializedDOMPath,
return param; 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; param.replace() = mReplace;
if (mBlobData) { if (mBlobImpl) {
BlobChild* actor = PBlobChild* blobActor =
ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlobData); mozilla::ipc::BackgroundChild::GetOrCreateActorForBlobImpl(actor,
if (actor) { mBlobImpl);
param.data() = actor; if (blobActor) {
param.data() = blobActor;
} }
} else { } else {
param.data() = mArrayData; param.data() = mArrayData;
@@ -179,11 +134,108 @@ CreateFileTask::GetRequestParams(const nsString& aSerializedDOMPath,
return param; return param;
} }
FileSystemResponseValue void
CreateFileTask::GetSuccessRequestResult(ErrorResult& aRv) const CreateFileTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); 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; nsAutoString path;
aRv = mTargetPath->GetPath(path); aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
@@ -193,22 +245,8 @@ CreateFileTask::GetSuccessRequestResult(ErrorResult& aRv) const
return FileSystemFileResponse(path); 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 nsresult
CreateFileTask::Work() CreateFileTaskParent::IOWork()
{ {
class MOZ_RAII AutoClose final class MOZ_RAII AutoClose final
{ {
@@ -280,6 +318,7 @@ CreateFileTask::Work()
} }
AutoClose acOutputStream(outputStream); AutoClose acOutputStream(outputStream);
MOZ_ASSERT(sOutputBufferSize);
nsCOMPtr<nsIOutputStream> bufferedOutputStream; nsCOMPtr<nsIOutputStream> bufferedOutputStream;
rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
@@ -291,11 +330,17 @@ CreateFileTask::Work()
AutoClose acBufferedOutputStream(bufferedOutputStream); 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; uint64_t bufSize = 0;
rv = mBlobStream->Available(&bufSize); rv = blobStream->Available(&bufSize);
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return rv; return rv;
} }
@@ -303,15 +348,14 @@ CreateFileTask::Work()
while (bufSize && !mFileSystem->IsShutdown()) { while (bufSize && !mFileSystem->IsShutdown()) {
uint32_t written = 0; uint32_t written = 0;
uint32_t writeSize = bufSize < UINT32_MAX ? bufSize : UINT32_MAX; 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))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return rv; return rv;
} }
bufSize -= written; bufSize -= written;
} }
mBlobStream->Close(); blobStream->Close();
mBlobStream = nullptr;
if (mFileSystem->IsShutdown()) { if (mFileSystem->IsShutdown()) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@@ -338,49 +382,23 @@ CreateFileTask::Work()
return NS_OK; return NS_OK;
} }
void nsresult
CreateFileTask::HandlerCallback() CreateFileTaskParent::MainThreadWork()
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread());
if (mFileSystem->IsShutdown()) {
mPromise = nullptr; if (!sOutputBufferSize) {
mBlobData = nullptr; sOutputBufferSize =
return; mozilla::Preferences::GetUint("dom.filesystem.outputBufferSize", 4096 * 4);
} }
if (HasError()) { return FileSystemTaskParentBase::MainThreadWork();
mPromise->MaybeReject(mErrorValue);
mPromise = nullptr;
mBlobData = nullptr;
return;
}
RefPtr<File> file = File::CreateFromFile(mFileSystem->GetParentObject(),
mTargetPath);
mPromise->MaybeResolve(file);
mPromise = nullptr;
mBlobData = nullptr;
} }
void void
CreateFileTask::GetPermissionAccessType(nsCString& aAccess) const CreateFileTaskParent::GetPermissionAccessType(nsCString& aAccess) const
{ {
if (mReplace) { GET_PERMISSION_ACCESS_TYPE(aAccess)
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);
} }
} // namespace dom } // namespace dom
+53 -29
View File
@@ -20,10 +20,10 @@ class Blob;
class BlobImpl; class BlobImpl;
class Promise; class Promise;
class CreateFileTask final : public FileSystemTaskBase class CreateFileTaskChild final : public FileSystemTaskChildBase
{ {
public: public:
static already_AddRefed<CreateFileTask> static already_AddRefed<CreateFileTaskChild>
Create(FileSystemBase* aFileSystem, Create(FileSystemBase* aFileSystem,
nsIFile* aFile, nsIFile* aFile,
Blob* aBlobData, Blob* aBlobData,
@@ -31,14 +31,8 @@ public:
bool replace, bool replace,
ErrorResult& aRv); ErrorResult& aRv);
static already_AddRefed<CreateFileTask>
Create(FileSystemBase* aFileSystem,
const FileSystemCreateFileParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual virtual
~CreateFileTask(); ~CreateFileTaskChild();
already_AddRefed<Promise> already_AddRefed<Promise>
GetPromise(); GetPromise();
@@ -51,40 +45,70 @@ protected:
GetRequestParams(const nsString& aSerializedDOMPath, GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override; ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue, SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override; ErrorResult& aRv) override;
virtual nsresult
Work() override;
virtual void virtual void
HandlerCallback() override; HandlerCallback() override;
private: private:
CreateFileTask(FileSystemBase* aFileSystem, CreateFileTaskChild(FileSystemBase* aFileSystem,
nsIFile* aFile, nsIFile* aFile,
bool aReplace); bool aReplace);
CreateFileTask(FileSystemBase* aFileSystem,
const FileSystemCreateFileParams& aParam,
FileSystemRequestParent* aParent);
void
GetOutputBufferSize() const;
static uint32_t sOutputBufferSize;
RefPtr<Promise> mPromise; RefPtr<Promise> mPromise;
nsCOMPtr<nsIFile> mTargetPath; nsCOMPtr<nsIFile> mTargetPath;
// Not thread-safe and should be released on main thread. RefPtr<BlobImpl> mBlobImpl;
RefPtr<Blob> mBlobData;
nsCOMPtr<nsIInputStream> mBlobStream; // This is going to be the content of the file, received by createFile()
// params.
InfallibleTArray<uint8_t> mArrayData; 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; bool mReplace;
}; };
+43 -14
View File
@@ -23,15 +23,21 @@ namespace dom {
DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType, DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType,
const nsAString& aStorageName) const nsAString& aStorageName)
: mWindowId(0) : mStorageType(aStorageType)
, mStorageName(aStorageName)
, mWindowId(0)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); mPermissionCheckType = ePermissionCheckByTestingPref;
mStorageType = aStorageType; if (NS_IsMainThread()) {
mStorageName = aStorageName; if (mozilla::Preferences::GetBool("device.storage.prompt.testing", false)) {
mPermissionCheckType = ePermissionCheckNotRequired;
mRequiresPermissionChecks = } else {
!mozilla::Preferences::GetBool("device.storage.prompt.testing", false); mPermissionCheckType = ePermissionCheckRequired;
}
} else {
AssertIsOnBackgroundThread();
}
// Get the permission name required to access the file system. // Get the permission name required to access the file system.
nsresult rv = nsresult rv =
@@ -53,18 +59,23 @@ DeviceStorageFileSystem::DeviceStorageFileSystem(const nsAString& aStorageType,
// DeviceStorageTypeChecker is a singleton object and must be initialized on // 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 // the main thread. We initialize it here so that we can use it on the worker
// thread. // thread.
DebugOnly<DeviceStorageTypeChecker*> typeChecker if (NS_IsMainThread()) {
= DeviceStorageTypeChecker::CreateOrGet(); DebugOnly<DeviceStorageTypeChecker*> typeChecker =
MOZ_ASSERT(typeChecker); DeviceStorageTypeChecker::CreateOrGet();
MOZ_ASSERT(typeChecker);
}
} }
DeviceStorageFileSystem::~DeviceStorageFileSystem() DeviceStorageFileSystem::~DeviceStorageFileSystem()
{ {
AssertIsOnOwningThread();
} }
already_AddRefed<FileSystemBase> already_AddRefed<FileSystemBase>
DeviceStorageFileSystem::Clone() DeviceStorageFileSystem::Clone()
{ {
AssertIsOnOwningThread();
RefPtr<DeviceStorageFileSystem> fs = RefPtr<DeviceStorageFileSystem> fs =
new DeviceStorageFileSystem(mStorageType, mStorageName); new DeviceStorageFileSystem(mStorageType, mStorageName);
@@ -77,7 +88,9 @@ void
DeviceStorageFileSystem::Init(nsDOMDeviceStorage* aDeviceStorage) DeviceStorageFileSystem::Init(nsDOMDeviceStorage* aDeviceStorage)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
AssertIsOnOwningThread();
MOZ_ASSERT(aDeviceStorage); MOZ_ASSERT(aDeviceStorage);
nsCOMPtr<nsPIDOMWindow> window = aDeviceStorage->GetOwner(); nsCOMPtr<nsPIDOMWindow> window = aDeviceStorage->GetOwner();
MOZ_ASSERT(window->IsInnerWindow()); MOZ_ASSERT(window->IsInnerWindow());
mWindowId = window->WindowID(); mWindowId = window->WindowID();
@@ -86,7 +99,7 @@ DeviceStorageFileSystem::Init(nsDOMDeviceStorage* aDeviceStorage)
void void
DeviceStorageFileSystem::Shutdown() DeviceStorageFileSystem::Shutdown()
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); AssertIsOnOwningThread();
mShutdown = true; mShutdown = true;
} }
@@ -94,6 +107,8 @@ nsISupports*
DeviceStorageFileSystem::GetParentObject() const DeviceStorageFileSystem::GetParentObject() const
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
AssertIsOnOwningThread();
nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId); nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
MOZ_ASSERT_IF(!mShutdown, window); MOZ_ASSERT_IF(!mShutdown, window);
return ToSupports(window); return ToSupports(window);
@@ -102,14 +117,15 @@ DeviceStorageFileSystem::GetParentObject() const
void void
DeviceStorageFileSystem::GetRootName(nsAString& aRetval) const DeviceStorageFileSystem::GetRootName(nsAString& aRetval) const
{ {
AssertIsOnOwningThread();
aRetval = mStorageName; aRetval = mStorageName;
} }
bool bool
DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const
{ {
MOZ_ASSERT(XRE_IsParentProcess(), MOZ_ASSERT(XRE_IsParentProcess(), "Should be on parent process!");
"Should be on parent process!"); MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(aFile); MOZ_ASSERT(aFile);
nsCOMPtr<nsIFile> rootPath; nsCOMPtr<nsIFile> rootPath;
@@ -134,7 +150,7 @@ DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const
bool bool
DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); AssertIsOnOwningThread();
MOZ_ASSERT(aDir); MOZ_ASSERT(aDir);
ErrorResult rv; ErrorResult rv;
@@ -157,6 +173,8 @@ DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const
void void
DeviceStorageFileSystem::SerializeDOMPath(nsAString& aString) const DeviceStorageFileSystem::SerializeDOMPath(nsAString& aString) const
{ {
AssertIsOnOwningThread();
// Generate the string representation of the file system. // Generate the string representation of the file system.
aString.AssignLiteral("devicestorage-"); aString.AssignLiteral("devicestorage-");
aString.Append(mStorageType); aString.Append(mStorageType);
@@ -164,5 +182,16 @@ DeviceStorageFileSystem::SerializeDOMPath(nsAString& aString) const
aString.Append(mStorageName); aString.Append(mStorageName);
} }
nsresult
DeviceStorageFileSystem::MainThreadWork()
{
MOZ_ASSERT(NS_IsMainThread());
DebugOnly<DeviceStorageTypeChecker*> typeChecker =
DeviceStorageTypeChecker::CreateOrGet();
MOZ_ASSERT(typeChecker);
return NS_OK;
}
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla
+6
View File
@@ -48,6 +48,12 @@ public:
virtual void virtual void
SerializeDOMPath(nsAString& aSerializedString) const override; SerializeDOMPath(nsAString& aSerializedString) const override;
virtual bool
NeedToGoToMainThread() const override { return true; }
virtual nsresult
MainThreadWork() override;
private: private:
virtual virtual
~DeviceStorageFileSystem(); ~DeviceStorageFileSystem();
+56 -17
View File
@@ -111,10 +111,21 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Directory)
NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END NS_INTERFACE_MAP_END
// static /* static */ bool
already_AddRefed<Promise> 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) Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
{ {
// Only exposed for DeviceStorage.
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aFileSystem); MOZ_ASSERT(aFileSystem);
nsCOMPtr<nsIFile> path; nsCOMPtr<nsIFile> path;
@@ -124,8 +135,9 @@ Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
return nullptr; return nullptr;
} }
RefPtr<GetFileOrDirectoryTask> task = RefPtr<GetFileOrDirectoryTaskChild> task =
GetFileOrDirectoryTask::Create(aFileSystem, path, eDOMRootDirectory, true, aRv); GetFileOrDirectoryTaskChild::Create(aFileSystem, path, eDOMRootDirectory,
true, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }
@@ -138,7 +150,6 @@ Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
Directory::Create(nsISupports* aParent, nsIFile* aFile, Directory::Create(nsISupports* aParent, nsIFile* aFile,
DirectoryType aType, FileSystemBase* aFileSystem) DirectoryType aType, FileSystemBase* aFileSystem)
{ {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aParent); MOZ_ASSERT(aParent);
MOZ_ASSERT(aFile); MOZ_ASSERT(aFile);
@@ -168,7 +179,6 @@ Directory::Directory(nsISupports* aParent,
, mFile(aFile) , mFile(aFile)
, mType(aType) , mType(aType)
{ {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aFile); MOZ_ASSERT(aFile);
// aFileSystem can be null. In this case we create a OSFileSystem when needed. // 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, Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
ErrorResult& aRv) ErrorResult& aRv)
{ {
// Only exposed for DeviceStorage.
MOZ_ASSERT(NS_IsMainThread());
RefPtr<Blob> blobData; RefPtr<Blob> blobData;
InfallibleTArray<uint8_t> arrayData; InfallibleTArray<uint8_t> arrayData;
bool replace = (aOptions.mIfExists == CreateIfExistsMode::Replace); bool replace = (aOptions.mIfExists == CreateIfExistsMode::Replace);
@@ -252,8 +265,9 @@ Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
return nullptr; return nullptr;
} }
RefPtr<CreateFileTask> task = RefPtr<CreateFileTaskChild> task =
CreateFileTask::Create(fs, realPath, blobData, arrayData, replace, aRv); CreateFileTaskChild::Create(fs, realPath, blobData, arrayData, replace,
aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }
@@ -266,6 +280,9 @@ Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
already_AddRefed<Promise> already_AddRefed<Promise>
Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv) Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
{ {
// Only exposed for DeviceStorage.
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIFile> realPath; nsCOMPtr<nsIFile> realPath;
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath)); nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
@@ -274,8 +291,8 @@ Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
return nullptr; return nullptr;
} }
RefPtr<CreateDirectoryTask> task = RefPtr<CreateDirectoryTaskChild> task =
CreateDirectoryTask::Create(fs, realPath, aRv); CreateDirectoryTaskChild::Create(fs, realPath, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }
@@ -288,6 +305,9 @@ Directory::CreateDirectory(const nsAString& aPath, ErrorResult& aRv)
already_AddRefed<Promise> already_AddRefed<Promise>
Directory::Get(const nsAString& aPath, ErrorResult& aRv) Directory::Get(const nsAString& aPath, ErrorResult& aRv)
{ {
// Only exposed for DeviceStorage.
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIFile> realPath; nsCOMPtr<nsIFile> realPath;
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath)); nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
@@ -296,9 +316,9 @@ Directory::Get(const nsAString& aPath, ErrorResult& aRv)
return nullptr; return nullptr;
} }
RefPtr<GetFileOrDirectoryTask> task = RefPtr<GetFileOrDirectoryTaskChild> task =
GetFileOrDirectoryTask::Create(fs, realPath, eNotDOMRootDirectory, false, GetFileOrDirectoryTaskChild::Create(fs, realPath, eNotDOMRootDirectory,
aRv); false, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }
@@ -311,12 +331,16 @@ Directory::Get(const nsAString& aPath, ErrorResult& aRv)
already_AddRefed<Promise> already_AddRefed<Promise>
Directory::Remove(const StringOrFileOrDirectory& aPath, ErrorResult& aRv) Directory::Remove(const StringOrFileOrDirectory& aPath, ErrorResult& aRv)
{ {
// Only exposed for DeviceStorage.
MOZ_ASSERT(NS_IsMainThread());
return RemoveInternal(aPath, false, aRv); return RemoveInternal(aPath, false, aRv);
} }
already_AddRefed<Promise> already_AddRefed<Promise>
Directory::RemoveDeep(const StringOrFileOrDirectory& aPath, ErrorResult& aRv) Directory::RemoveDeep(const StringOrFileOrDirectory& aPath, ErrorResult& aRv)
{ {
// Only exposed for DeviceStorage.
MOZ_ASSERT(NS_IsMainThread());
return RemoveInternal(aPath, true, aRv); return RemoveInternal(aPath, true, aRv);
} }
@@ -324,6 +348,9 @@ already_AddRefed<Promise>
Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive, Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
ErrorResult& aRv) ErrorResult& aRv)
{ {
// Only exposed for DeviceStorage.
MOZ_ASSERT(NS_IsMainThread());
nsresult error = NS_OK; nsresult error = NS_OK;
nsCOMPtr<nsIFile> realPath; nsCOMPtr<nsIFile> realPath;
@@ -360,8 +387,8 @@ Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR; error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
} }
RefPtr<RemoveTask> task = RefPtr<RemoveTaskChild> task =
RemoveTask::Create(fs, mFile, realPath, aRecursive, aRv); RemoveTaskChild::Create(fs, mFile, realPath, aRecursive, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }
@@ -409,8 +436,8 @@ Directory::GetFilesAndDirectories(ErrorResult& aRv)
return nullptr; return nullptr;
} }
RefPtr<GetDirectoryListingTask> task = RefPtr<GetDirectoryListingTaskChild> task =
GetDirectoryListingTask::Create(fs, mFile, mType, mFilters, aRv); GetDirectoryListingTaskChild::Create(fs, mFile, mType, mFilters, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }
@@ -480,5 +507,17 @@ Directory::DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const
return NS_OK; 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 dom
} // namespace mozilla } // namespace mozilla
+6
View File
@@ -53,6 +53,9 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Directory) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Directory)
static bool
DeviceStorageEnabled(JSContext* aCx, JSObject* aObj);
static already_AddRefed<Promise> static already_AddRefed<Promise>
GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv); GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv);
@@ -144,6 +147,9 @@ public:
return mType; return mType;
} }
bool
ClonableToDifferentThreadOrProcess() const;
private: private:
Directory(nsISupports* aParent, Directory(nsISupports* aParent,
nsIFile* aFile, DirectoryType aType, nsIFile* aFile, DirectoryType aType,
+22 -2
View File
@@ -17,6 +17,9 @@ namespace dom {
already_AddRefed<FileSystemBase> already_AddRefed<FileSystemBase>
FileSystemBase::DeserializeDOMPath(const nsAString& aString) FileSystemBase::DeserializeDOMPath(const nsAString& aString)
{ {
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
AssertIsOnBackgroundThread();
if (StringBeginsWith(aString, NS_LITERAL_STRING("devicestorage-"))) { if (StringBeginsWith(aString, NS_LITERAL_STRING("devicestorage-"))) {
// The string representation of devicestorage file system is of the format: // The string representation of devicestorage file system is of the format:
// devicestorage-StorageType-StorageName // devicestorage-StorageType-StorageName
@@ -39,34 +42,41 @@ FileSystemBase::DeserializeDOMPath(const nsAString& aString)
return f.forget(); return f.forget();
} }
return RefPtr<OSFileSystem>(new OSFileSystem(aString)).forget(); return RefPtr<OSFileSystemParent>(new OSFileSystemParent(aString)).forget();
} }
FileSystemBase::FileSystemBase() FileSystemBase::FileSystemBase()
: mShutdown(false) : mShutdown(false)
, mRequiresPermissionChecks(true) , mPermissionCheckType(eNotSet)
#ifdef DEBUG
, mOwningThread(PR_GetCurrentThread())
#endif
{ {
} }
FileSystemBase::~FileSystemBase() FileSystemBase::~FileSystemBase()
{ {
AssertIsOnOwningThread();
} }
void void
FileSystemBase::Shutdown() FileSystemBase::Shutdown()
{ {
AssertIsOnOwningThread();
mShutdown = true; mShutdown = true;
} }
nsISupports* nsISupports*
FileSystemBase::GetParentObject() const FileSystemBase::GetParentObject() const
{ {
AssertIsOnOwningThread();
return nullptr; return nullptr;
} }
bool bool
FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
{ {
AssertIsOnOwningThread();
MOZ_ASSERT(aFile, "aFile Should not be null."); MOZ_ASSERT(aFile, "aFile Should not be null.");
MOZ_ASSERT(aPath); MOZ_ASSERT(aPath);
@@ -89,12 +99,14 @@ FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
bool bool
FileSystemBase::IsSafeFile(nsIFile* aFile) const FileSystemBase::IsSafeFile(nsIFile* aFile) const
{ {
AssertIsOnOwningThread();
return false; return false;
} }
bool bool
FileSystemBase::IsSafeDirectory(Directory* aDir) const FileSystemBase::IsSafeDirectory(Directory* aDir) const
{ {
AssertIsOnOwningThread();
return false; return false;
} }
@@ -104,6 +116,7 @@ FileSystemBase::GetDOMPath(nsIFile* aFile,
nsAString& aRetval, nsAString& aRetval,
ErrorResult& aRv) const ErrorResult& aRv) const
{ {
AssertIsOnOwningThread();
MOZ_ASSERT(aFile); MOZ_ASSERT(aFile);
if (aType == Directory::eDOMRootDirectory) { 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 dom
} // namespace mozilla } // namespace mozilla
+50 -6
View File
@@ -18,8 +18,8 @@ class BlobImpl;
class FileSystemBase class FileSystemBase
{ {
NS_INLINE_DECL_REFCOUNTING(FileSystemBase)
public: public:
NS_INLINE_DECL_REFCOUNTING(FileSystemBase)
// Create file system object from its string representation. // Create file system object from its string representation.
static already_AddRefed<FileSystemBase> static already_AddRefed<FileSystemBase>
@@ -87,23 +87,63 @@ public:
return mPermission; return mPermission;
} }
bool // The decision about doing or not doing the permission check cannot be done
RequiresPermissionChecks() const // 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 // CC methods
virtual void Unlink() {} virtual void Unlink() {}
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) {} virtual void Traverse(nsCycleCollectionTraversalCallback &cb) {}
void
AssertIsOnOwningThread() const;
protected: protected:
virtual ~FileSystemBase(); virtual ~FileSystemBase();
// The local path of the root (i.e. the OS path, with OS path separators, of // 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). // the OS directory that acts as the root of this OSFileSystem).
// This path must be set by the FileSystem implementation immediately // 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 // 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 // must be considered the OS 'root' of the current FileSystem. Different
// Directory object can have different OS 'root' path. // Directory object can have different OS 'root' path.
@@ -119,7 +159,11 @@ protected:
// The permission name required to access the file system. // The permission name required to access the file system.
nsCString mPermission; nsCString mPermission;
bool mRequiresPermissionChecks; ePermissionCheckType mPermissionCheckType;
#ifdef DEBUG
PRThread* mOwningThread;
#endif
}; };
} // namespace dom } // namespace dom
+120 -8
View File
@@ -8,28 +8,128 @@
#include "mozilla/dom/FileSystemBase.h" #include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemTaskBase.h" #include "mozilla/dom/FileSystemTaskBase.h"
#include "mozilla/dom/FileSystemUtils.h" #include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "nsIDocument.h" #include "nsIDocument.h"
#include "nsIIPCBackgroundChildCreateCallback.h"
#include "nsPIDOMWindow.h" #include "nsPIDOMWindow.h"
#include "nsContentPermissionHelper.h" #include "nsContentPermissionHelper.h"
namespace mozilla { namespace mozilla {
namespace dom { 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, NS_IMPL_ISUPPORTS(FileSystemPermissionRequest, nsIRunnable,
nsIContentPermissionRequest) nsIContentPermissionRequest)
// static /* static */ void
void FileSystemPermissionRequest::RequestForTask(FileSystemTaskChildBase* aTask)
FileSystemPermissionRequest::RequestForTask(FileSystemTaskBase* 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()); MOZ_ASSERT(NS_IsMainThread());
RefPtr<FileSystemPermissionRequest> request = RefPtr<FileSystemPermissionRequest> request =
new FileSystemPermissionRequest(aTask); new FileSystemPermissionRequest(aTask);
NS_DispatchToCurrentThread(request); NS_DispatchToCurrentThread(request);
} }
FileSystemPermissionRequest::FileSystemPermissionRequest(FileSystemTaskBase* aTask) FileSystemPermissionRequest::FileSystemPermissionRequest(FileSystemTaskChildBase* aTask)
: mTask(aTask) : mTask(aTask)
{ {
MOZ_ASSERT(mTask, "aTask should not be null!"); MOZ_ASSERT(mTask, "aTask should not be null!");
@@ -98,7 +198,7 @@ FileSystemPermissionRequest::Cancel()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
mTask->SetError(NS_ERROR_DOM_SECURITY_ERR); mTask->SetError(NS_ERROR_DOM_SECURITY_ERR);
mTask->Start(); ScheduleTask();
return NS_OK; return NS_OK;
} }
@@ -107,7 +207,7 @@ FileSystemPermissionRequest::Allow(JS::HandleValue aChoices)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aChoices.isUndefined()); MOZ_ASSERT(aChoices.isUndefined());
mTask->Start(); ScheduleTask();
return NS_OK; return NS_OK;
} }
@@ -122,7 +222,13 @@ FileSystemPermissionRequest::Run()
return NS_OK; 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); Allow(JS::UndefinedHandleValue);
return NS_OK; return NS_OK;
} }
@@ -146,5 +252,11 @@ FileSystemPermissionRequest::GetRequester(nsIContentPermissionRequester** aReque
return NS_OK; return NS_OK;
} }
void
FileSystemPermissionRequest::ScheduleTask()
{
PBackgroundInitializer::ScheduleTask(mTask);
}
} /* namespace dom */ } /* namespace dom */
} /* namespace mozilla */ } /* namespace mozilla */
+13 -6
View File
@@ -17,7 +17,7 @@ class nsPIDOMWindow;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
class FileSystemTaskBase; class FileSystemTaskChildBase;
class FileSystemPermissionRequest final class FileSystemPermissionRequest final
: public nsIContentPermissionRequest : public nsIContentPermissionRequest
@@ -26,20 +26,27 @@ class FileSystemPermissionRequest final
public: public:
// Request permission for the given task. // Request permission for the given task.
static void static void
RequestForTask(FileSystemTaskBase* aTask); RequestForTask(FileSystemTaskChildBase* aTask);
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONREQUEST NS_DECL_NSICONTENTPERMISSIONREQUEST
NS_DECL_NSIRUNNABLE NS_DECL_NSIRUNNABLE
private:
explicit FileSystemPermissionRequest(FileSystemTaskBase* aTask);
virtual private:
explicit FileSystemPermissionRequest(FileSystemTaskChildBase* aTask);
~FileSystemPermissionRequest(); ~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 mPermissionType;
nsCString mPermissionAccess; nsCString mPermissionAccess;
RefPtr<FileSystemTaskBase> mTask; RefPtr<FileSystemTaskChildBase> mTask;
nsCOMPtr<nsPIDOMWindow> mWindow; nsCOMPtr<nsPIDOMWindow> mWindow;
nsCOMPtr<nsIPrincipal> mPrincipal; nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIContentPermissionRequester> mRequester; nsCOMPtr<nsIContentPermissionRequester> mRequester;
+32 -21
View File
@@ -18,18 +18,22 @@ namespace mozilla {
namespace dom { namespace dom {
FileSystemRequestParent::FileSystemRequestParent() FileSystemRequestParent::FileSystemRequestParent()
: mDestroyed(false)
{ {
AssertIsOnBackgroundThread();
} }
FileSystemRequestParent::~FileSystemRequestParent() FileSystemRequestParent::~FileSystemRequestParent()
{ {
AssertIsOnBackgroundThread();
} }
#define FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(name) \ #define FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(name) \
case FileSystemParams::TFileSystem##name##Params: { \ case FileSystemParams::TFileSystem##name##Params: { \
const FileSystem##name##Params& p = aParams; \ const FileSystem##name##Params& p = aParams; \
mFileSystem = FileSystemBase::DeserializeDOMPath(p.filesystem()); \ 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())) { \ if (NS_WARN_IF(rv.Failed())) { \
return false; \ return false; \
} \ } \
@@ -37,11 +41,10 @@ FileSystemRequestParent::~FileSystemRequestParent()
} }
bool bool
FileSystemRequestParent::Dispatch(ContentParent* aParent, FileSystemRequestParent::Initialize(const FileSystemParams& aParams)
const FileSystemParams& aParams)
{ {
MOZ_ASSERT(aParent, "aParent should not be null."); AssertIsOnBackgroundThread();
RefPtr<FileSystemTaskBase> task;
ErrorResult rv; ErrorResult rv;
switch (aParams.type()) { 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. // Should never reach here.
return false; return false;
} }
if (mFileSystem->RequiresPermissionChecks()) { if (mFileSystem->PermissionCheckType() != FileSystemBase::ePermissionCheckNotRequired) {
// Check the content process permission. nsAutoCString access;
mTask->GetPermissionAccessType(access);
nsCString access; mPermissionName = mFileSystem->GetPermission();
task->GetPermissionAccessType(access); mPermissionName.Append('-');
mPermissionName.Append(access);
nsAutoCString permissionName;
permissionName = mFileSystem->GetPermission();
permissionName.Append('-');
permissionName.Append(access);
if (!AssertAppProcessPermission(aParent, permissionName.get())) {
return false;
}
} }
task->Start();
return true; return true;
} }
void 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) { if (!mFileSystem) {
return; return;
} }
mFileSystem->Shutdown(); mFileSystem->Shutdown();
mFileSystem = nullptr; mFileSystem = nullptr;
mTask = nullptr;
mDestroyed = true;
} }
} // namespace dom } // namespace dom
+29 -11
View File
@@ -8,39 +8,57 @@
#define mozilla_dom_FileSystemRequestParent_h #define mozilla_dom_FileSystemRequestParent_h
#include "mozilla/dom/PFileSystemRequestParent.h" #include "mozilla/dom/PFileSystemRequestParent.h"
#include "mozilla/dom/ContentChild.h" #include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/ContentParent.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
class FileSystemBase; class FileSystemParams;
class FileSystemTaskParentBase;
class FileSystemRequestParent final class FileSystemRequestParent final : public PFileSystemRequestParent
: public PFileSystemRequestParent
{ {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileSystemRequestParent) NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileSystemRequestParent)
public: public:
FileSystemRequestParent(); FileSystemRequestParent();
bool const nsCString&
IsRunning() PermissionName() const
{ {
return state() == PFileSystemRequest::__Start; return mPermissionName;
}
FileSystemBase::ePermissionCheckType
PermissionCheckType() const
{
return mFileSystem ? mFileSystem->PermissionCheckType()
: FileSystemBase::eNotSet;
} }
bool bool
Dispatch(ContentParent* aParent, const FileSystemParams& aParams); Initialize(const FileSystemParams& aParams);
void
Start();
bool Destroyed() const
{
return mDestroyed;
}
virtual void virtual void
ActorDestroy(ActorDestroyReason why) override; ActorDestroy(ActorDestroyReason why) override;
private: private:
// Private destructor, to discourage deletion outside of Release():
virtual
~FileSystemRequestParent(); ~FileSystemRequestParent();
RefPtr<FileSystemBase> mFileSystem; RefPtr<FileSystemBase> mFileSystem;
RefPtr<FileSystemTaskParentBase> mTask;
nsCString mPermissionName;
bool mDestroyed;
}; };
} // namespace dom } // namespace dom
+248 -147
View File
@@ -7,14 +7,13 @@
#include "mozilla/dom/FileSystemTaskBase.h" #include "mozilla/dom/FileSystemTaskBase.h"
#include "nsNetCID.h" #include "nsNetCID.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/File.h" #include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemBase.h" #include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemRequestParent.h" #include "mozilla/dom/FileSystemRequestParent.h"
#include "mozilla/dom/FileSystemUtils.h" #include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
#include "mozilla/dom/PContent.h"
#include "mozilla/dom/ipc/BlobParent.h" #include "mozilla/dom/ipc/BlobParent.h"
#include "mozilla/ipc/BackgroundParent.h"
#include "mozilla/unused.h" #include "mozilla/unused.h"
#include "nsProxyRelease.h" #include "nsProxyRelease.h"
@@ -23,85 +22,124 @@ namespace dom {
namespace { namespace {
class FileSystemReleaseRunnable final : public nsRunnable nsresult
FileSystemErrorFromNsError(const nsresult& aErrorValue)
{ {
public: uint16_t module = NS_ERROR_GET_MODULE(aErrorValue);
explicit FileSystemReleaseRunnable(RefPtr<FileSystemBase>& aDoomed) if (module == NS_ERROR_MODULE_DOM_FILESYSTEM ||
: mDoomed(nullptr) module == NS_ERROR_MODULE_DOM_FILE ||
{ module == NS_ERROR_MODULE_DOM) {
aDoomed.swap(mDoomed); 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; return NS_OK;
} }
private: private:
FileSystemBase* MOZ_OWNING_REF mDoomed; RefPtr<FileSystemTaskChildBase> mTask;
}; };
} // anonymous namespace } // anonymous namespace
FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem) /**
* FileSystemTaskBase class
*/
FileSystemTaskChildBase::FileSystemTaskChildBase(FileSystemBase* aFileSystem)
: mErrorValue(NS_OK) : mErrorValue(NS_OK)
, mFileSystem(aFileSystem) , mFileSystem(aFileSystem)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null."); MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
aFileSystem->AssertIsOnOwningThread();
} }
FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem, FileSystemTaskChildBase::~FileSystemTaskChildBase()
const FileSystemParams& aParam,
FileSystemRequestParent* aParent)
: mErrorValue(NS_OK)
, mFileSystem(aFileSystem)
, mRequestParent(aParent)
{ {
MOZ_ASSERT(XRE_IsParentProcess(), mFileSystem->AssertIsOnOwningThread();
"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);
}
} }
FileSystemBase* FileSystemBase*
FileSystemTaskBase::GetFileSystem() const FileSystemTaskChildBase::GetFileSystem() const
{ {
mFileSystem->AssertIsOnOwningThread();
return mFileSystem.get(); return mFileSystem.get();
} }
void void
FileSystemTaskBase::Start() FileSystemTaskChildBase::Start()
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); mFileSystem->AssertIsOnOwningThread();
if (HasError()) { 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; 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()) { if (mFileSystem->IsShutdown()) {
return; return;
} }
@@ -117,72 +155,24 @@ FileSystemTaskBase::Start()
// Retain a reference so the task object isn't deleted without IPDL's // Retain a reference so the task object isn't deleted without IPDL's
// knowledge. The reference will be released by // knowledge. The reference will be released by
// mozilla::dom::ContentChild::DeallocPFileSystemRequestChild. // mozilla::ipc::BackgroundChildImpl::DeallocPFileSystemRequestChild.
NS_ADDREF_THIS(); NS_ADDREF_THIS();
ContentChild::GetSingleton()->SendPFileSystemRequestConstructor(this, // If we are here, PBackground must be up and running, because Start() is
params); // called only by FileSystemPermissionRequest, and that class takes care of
} // PBackground initialization.
PBackgroundChild* actor =
mozilla::ipc::BackgroundChild::GetForCurrentThread();
MOZ_ASSERT(actor);
NS_IMETHODIMP actor->SendPFileSystemRequestConstructor(this, params);
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;
} }
void void
FileSystemTaskBase::HandleResult() FileSystemTaskChildBase::SetRequestResult(const FileSystemResponseValue& aValue)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); mFileSystem->AssertIsOnOwningThread();
if (mFileSystem->IsShutdown()) {
return;
}
if (mRequestParent && mRequestParent->IsRunning()) {
Unused << mRequestParent->Send__delete__(mRequestParent,
GetRequestResult());
} else {
HandlerCallback();
}
}
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) { if (aValue.type() == FileSystemResponseValue::TFileSystemErrorResponse) {
FileSystemErrorResponse r = aValue; FileSystemErrorResponse r = aValue;
mErrorValue = r.error(); mErrorValue = r.error();
@@ -194,61 +184,172 @@ FileSystemTaskBase::SetRequestResult(const FileSystemResponseValue& aValue)
} }
bool bool
FileSystemTaskBase::Recv__delete__(const FileSystemResponseValue& aValue) FileSystemTaskChildBase::Recv__delete__(const FileSystemResponseValue& aValue)
{ {
mFileSystem->AssertIsOnOwningThread();
SetRequestResult(aValue); SetRequestResult(aValue);
HandlerCallback(); HandlerCallback();
return true; return true;
} }
void void
FileSystemTaskBase::SetError(const nsresult& aErrorValue) FileSystemTaskChildBase::SetError(const nsresult& aErrorValue)
{ {
uint16_t module = NS_ERROR_GET_MODULE(aErrorValue); mErrorValue = FileSystemErrorFromNsError(aErrorValue);
if (module == NS_ERROR_MODULE_DOM_FILESYSTEM || }
module == NS_ERROR_MODULE_DOM_FILE ||
module == NS_ERROR_MODULE_DOM) { /**
mErrorValue = 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; return;
} }
switch (aErrorValue) { nsresult rv = DispatchToIOThread(this);
case NS_OK: NS_WARN_IF(NS_FAILED(rv));
mErrorValue = NS_OK; }
return;
case NS_ERROR_FILE_INVALID_PATH: void
case NS_ERROR_FILE_UNRECOGNIZED_PATH: FileSystemTaskParentBase::HandleResult()
mErrorValue = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR; {
return; AssertIsOnBackgroundThread();
mFileSystem->AssertIsOnOwningThread();
case NS_ERROR_FILE_DESTINATION_NOT_DIR: if (mFileSystem->IsShutdown()) {
mErrorValue = NS_ERROR_DOM_FILESYSTEM_INVALID_MODIFICATION_ERR; return;
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;
} }
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 } // namespace dom
+194 -134
View File
@@ -10,111 +10,118 @@
#include "mozilla/ErrorResult.h" #include "mozilla/ErrorResult.h"
#include "mozilla/dom/FileSystemRequestParent.h" #include "mozilla/dom/FileSystemRequestParent.h"
#include "mozilla/dom/PFileSystemRequestChild.h" #include "mozilla/dom/PFileSystemRequestChild.h"
#include "nsThreadUtils.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
class BlobImpl; class BlobImpl;
class BlobParent;
class FileSystemBase; class FileSystemBase;
class FileSystemParams; class FileSystemParams;
class PBlobParent;
/* /*
* The base class to implement a Task class. * 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. In
* The file system operations can only be performed in the parent process. When * order to avoid duplicated code, we used PBackground for child-parent and
* performing such a parent-process-only operation, a task will delivered the * parent-parent communications.
* operation to the parent process if needed.
* *
* The following diagram illustrates the how a API call from the content page * The following diagram illustrates the how a API call from the content page
* starts a task and gets call back results. * starts a task and gets call back results.
* *
* The left block is the call sequence inside the child process, while the * The left block is the call sequence inside any process loading content, while
* right block is the call sequence inside the parent process. * 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 * Page
* 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'). * | (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. From the process that is handling the request
* | | * Child/Parent (it can be in any process):
* | (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) Call FileSystem API from content page with JS. Create a task and run. * (1) Call FileSystem API from content page with JS. Create a task and run.
* The base constructor [FileSystemTaskBase()] of the task should be called. * The base constructor [FileSystemTaskChildBase()] of the task should be
* (2) Forward the task to the parent process through the IPC and call * 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. * [GetRequestParams] to prepare the parameters of the IPC.
* Parent: * Parent:
* (3) The parent process receives IPC and handle it in * (4) The parent process receives IPC and handle it in
* FileystemRequestParent. * FileystemRequestParent. Get the IPC parameters and create a task to run the
* Get the IPC parameters and create a task to run the IPC task. The base * IPC task. The base constructor [FileSystemTaskParentBase(aParam, aParent)]
* constructor [FileSystemTaskBase(aParam, aParent)] of the task should be * For security reasons, we do an additional permission check if needed. In
* called to set the task as an IPC task. * the check fails, the child process will be killed.
* (4) The task operation will be performed in the member function of [Work]. * of the task should be called to set the task as an IPC task.
* A worker thread will be created to run that function. If error occurs * (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. * 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. * 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 * 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 * Each task only needs to implement its specific success result preparation
* function -[GetSuccessRequestResult]. * function -[GetSuccessRequestResult].
* Child: * Child/Parent:
* (7) The child process receives IPC and calls [SetRequestResult] to get the * (8) The process receives IPC and calls [SetRequestResult] to get the
* task result. Each task needs to implement its specific success result * task result. Each task needs to implement its specific success result
* parsing function [SetSuccessRequestResult] to get the success result. * parsing function [SetSuccessRequestResult] to get the success result.
* (8) Call [HandlerCallback] to send the task result to the content page. * (9) 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).
*/ */
class FileSystemTaskBase class FileSystemTaskChildBase : public PFileSystemRequestChild
: public nsRunnable
, public PFileSystemRequestChild
{ {
public: public:
NS_INLINE_DECL_REFCOUNTING(FileSystemTaskChildBase)
/* /*
* Start the task. If the task is running the child process, it will be * Start the task. It will dispatch all the information to the parent process,
* forwarded to parent process by IPC, or else, creates a worker thread to * PBackground thread. This method must be called from the owning thread.
* do the task work.
*/ */
void void
Start(); Start();
@@ -135,104 +142,157 @@ public:
virtual void virtual void
GetPermissionAccessType(nsCString& aAccess) const = 0; 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 * 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. * Override this function to handle the call back to the content page.
*/ */
virtual void virtual void
HandlerCallback() = 0; 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. * 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 * 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. * @param filesystem The string representation of the file system.
*/ */
virtual FileSystemParams virtual FileSystemParams
GetRequestParams(const nsString& aSerializedDOMPath, GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const = 0; 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 * 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 * It will be called when the task is completed successfully and we need to
* send the task success result back to the child process. * send the task success result back to the child process.
*/ */
virtual FileSystemResponseValue virtual FileSystemResponseValue
GetSuccessRequestResult(ErrorResult& aRv) const = 0; 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. * 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 * If it is an IPC task, send back the IPC result. It runs on the PBackground
* to the content page. * thread.
*/ */
void void
HandleResult(); 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. * Wrap the task result to FileSystemResponseValue for sending it through IPC.
* It will be called when the task is completed and we need to * 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 FileSystemResponseValue
GetRequestResult() const; GetRequestResult() const;
protected:
/* /*
* Unwrap the IPC message to get the task result. * To create a parent process task delivered from the child process through
* It will be called when the task is completed and an IPC message is received * IPC.
* in the child process and we want to get the task result.
*/ */
void FileSystemTaskParentBase(FileSystemBase* aFileSystem,
SetRequestResult(const FileSystemResponseValue& aValue); const FileSystemParams& aParam,
FileSystemRequestParent* aParent);
virtual
~FileSystemTaskParentBase();
nsresult mErrorValue;
RefPtr<FileSystemBase> mFileSystem;
RefPtr<FileSystemRequestParent> mRequestParent;
nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
}; };
} // namespace dom } // namespace dom
+182 -165
View File
@@ -11,27 +11,34 @@
#include "mozilla/dom/File.h" #include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemBase.h" #include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h" #include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/PFileSystemParams.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
#include "mozilla/dom/ipc/BlobChild.h" #include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/dom/ipc/BlobParent.h" #include "mozilla/dom/ipc/BlobParent.h"
#include "nsIFile.h" #include "nsIFile.h"
#include "nsStringGlue.h" #include "nsStringGlue.h"
#define GET_DIRECTORY_LISTING_PERMISSION "read"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
/* static */ already_AddRefed<GetDirectoryListingTask> /**
GetDirectoryListingTask::Create(FileSystemBase* aFileSystem, * GetDirectoryListingTaskChild
nsIFile* aTargetPath, */
Directory::DirectoryType aType,
const nsAString& aFilters,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<GetDirectoryListingTask> task = /* static */ already_AddRefed<GetDirectoryListingTaskChild>
new GetDirectoryListingTask(aFileSystem, aTargetPath, aType, aFilters); 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. // aTargetPath can be null. In this case SetError will be called.
@@ -50,72 +57,36 @@ GetDirectoryListingTask::Create(FileSystemBase* aFileSystem,
return task.forget(); return task.forget();
} }
/* static */ already_AddRefed<GetDirectoryListingTask> GetDirectoryListingTaskChild::GetDirectoryListingTaskChild(FileSystemBase* aFileSystem,
GetDirectoryListingTask::Create(FileSystemBase* aFileSystem, nsIFile* aTargetPath,
const FileSystemGetDirectoryListingParams& aParam, Directory::DirectoryType aType,
FileSystemRequestParent* aParent, const nsAString& aFilters)
ErrorResult& aRv) : FileSystemTaskChildBase(aFileSystem)
{
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)
, mTargetPath(aTargetPath) , mTargetPath(aTargetPath)
, mFilters(aFilters) , mFilters(aFilters)
, mType(aType) , mType(aType)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem); MOZ_ASSERT(aFileSystem);
aFileSystem->AssertIsOnOwningThread();
} }
GetDirectoryListingTask::GetDirectoryListingTask(FileSystemBase* aFileSystem, GetDirectoryListingTaskChild::~GetDirectoryListingTaskChild()
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
, mFilters(aParam.filters())
{ {
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!"); mFileSystem->AssertIsOnOwningThread();
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!");
} }
already_AddRefed<Promise> already_AddRefed<Promise>
GetDirectoryListingTask::GetPromise() GetDirectoryListingTaskChild::GetPromise()
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); mFileSystem->AssertIsOnOwningThread();
return RefPtr<Promise>(mPromise).forget(); return RefPtr<Promise>(mPromise).forget();
} }
FileSystemParams FileSystemParams
GetDirectoryListingTask::GetRequestParams(const nsString& aSerializedDOMPath, GetDirectoryListingTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const ErrorResult& aRv) const
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); mFileSystem->AssertIsOnOwningThread();
nsAutoString path; nsAutoString path;
aRv = mTargetPath->GetPath(path); aRv = mTargetPath->GetPath(path);
@@ -128,38 +99,11 @@ GetDirectoryListingTask::GetRequestParams(const nsString& aSerializedDOMPath,
mFilters); 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 void
GetDirectoryListingTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue, GetDirectoryListingTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) ErrorResult& aRv)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); mFileSystem->AssertIsOnOwningThread();
MOZ_ASSERT(aValue.type() == MOZ_ASSERT(aValue.type() ==
FileSystemResponseValue::TFileSystemDirectoryListingResponse); 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 nsresult
GetDirectoryListingTask::Work() GetDirectoryListingTaskParent::IOWork()
{ {
MOZ_ASSERT(XRE_IsParentProcess(), MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!"); "Only call from parent process!");
@@ -303,81 +392,9 @@ GetDirectoryListingTask::Work()
} }
void void
GetDirectoryListingTask::HandlerCallback() GetDirectoryListingTaskParent::GetPermissionAccessType(nsCString& aAccess) const
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); aAccess.AssignLiteral(GET_DIRECTORY_LISTING_PERMISSION);
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");
} }
} // namespace dom } // namespace dom
+39 -23
View File
@@ -17,24 +17,18 @@ namespace dom {
class BlobImpl; class BlobImpl;
class GetDirectoryListingTask final : public FileSystemTaskBase class GetDirectoryListingTaskChild final : public FileSystemTaskChildBase
{ {
public: public:
static already_AddRefed<GetDirectoryListingTask> static already_AddRefed<GetDirectoryListingTaskChild>
Create(FileSystemBase* aFileSystem, Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath, nsIFile* aTargetPath,
Directory::DirectoryType aType, Directory::DirectoryType aType,
const nsAString& aFilters, const nsAString& aFilters,
ErrorResult& aRv); ErrorResult& aRv);
static already_AddRefed<GetDirectoryListingTask>
Create(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual virtual
~GetDirectoryListingTask(); ~GetDirectoryListingTaskChild();
already_AddRefed<Promise> already_AddRefed<Promise>
GetPromise(); GetPromise();
@@ -44,29 +38,19 @@ public:
private: private:
// If aDirectoryOnly is set, we should ensure that the target is a directory. // If aDirectoryOnly is set, we should ensure that the target is a directory.
GetDirectoryListingTask(FileSystemBase* aFileSystem, GetDirectoryListingTaskChild(FileSystemBase* aFileSystem,
nsIFile* aTargetPath, nsIFile* aTargetPath,
Directory::DirectoryType aType, Directory::DirectoryType aType,
const nsAString& aFilters); const nsAString& aFilters);
GetDirectoryListingTask(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent);
virtual FileSystemParams virtual FileSystemParams
GetRequestParams(const nsString& aSerializedDOMPath, GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override; ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue, SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override; ErrorResult& aRv) override;
virtual nsresult
Work() override;
virtual void virtual void
HandlerCallback() override; HandlerCallback() override;
@@ -80,6 +64,38 @@ private:
FallibleTArray<Directory::FileOrDirectoryPath> mTargetData; 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 dom
} // namespace mozilla } // namespace mozilla
+127 -109
View File
@@ -10,27 +10,35 @@
#include "mozilla/dom/File.h" #include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemBase.h" #include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h" #include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/PFileSystemParams.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
#include "mozilla/dom/ipc/BlobChild.h" #include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/dom/ipc/BlobParent.h" #include "mozilla/dom/ipc/BlobParent.h"
#include "nsIFile.h" #include "nsIFile.h"
#include "nsStringGlue.h" #include "nsStringGlue.h"
#define GET_FILE_OR_DIRECTORY_PERMISSION "read"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
/* static */ already_AddRefed<GetFileOrDirectoryTask> /**
GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem, * GetFileOrDirectoryTaskChild
nsIFile* aTargetPath, */
Directory::DirectoryType aType,
bool aDirectoryOnly, /* static */ already_AddRefed<GetFileOrDirectoryTaskChild>
ErrorResult& aRv) GetFileOrDirectoryTaskChild::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
bool aDirectoryOnly,
ErrorResult& aRv)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem); MOZ_ASSERT(aFileSystem);
RefPtr<GetFileOrDirectoryTask> task = RefPtr<GetFileOrDirectoryTaskChild> task =
new GetFileOrDirectoryTask(aFileSystem, aTargetPath, aType, aDirectoryOnly); new GetFileOrDirectoryTaskChild(aFileSystem, aTargetPath, aType,
aDirectoryOnly);
// aTargetPath can be null. In this case SetError will be called. // aTargetPath can be null. In this case SetError will be called.
@@ -49,35 +57,11 @@ GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem,
return task.forget(); return task.forget();
} }
/* static */ already_AddRefed<GetFileOrDirectoryTask> GetFileOrDirectoryTaskChild::GetFileOrDirectoryTaskChild(FileSystemBase* aFileSystem,
GetFileOrDirectoryTask::Create(FileSystemBase* aFileSystem, nsIFile* aTargetPath,
const FileSystemGetFileOrDirectoryParams& aParam, Directory::DirectoryType aType,
FileSystemRequestParent* aParent, bool aDirectoryOnly)
ErrorResult& aRv) : FileSystemTaskChildBase(aFileSystem)
{
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)
, mTargetPath(aTargetPath) , mTargetPath(aTargetPath)
, mIsDirectory(aDirectoryOnly) , mIsDirectory(aDirectoryOnly)
, mType(aType) , mType(aType)
@@ -86,33 +70,21 @@ GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
MOZ_ASSERT(aFileSystem); MOZ_ASSERT(aFileSystem);
} }
GetFileOrDirectoryTask::GetFileOrDirectoryTask(FileSystemBase* aFileSystem, GetFileOrDirectoryTaskChild::~GetFileOrDirectoryTaskChild()
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
, mIsDirectory(false)
{ {
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!"); MOZ_ASSERT(NS_IsMainThread());
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!");
} }
already_AddRefed<Promise> already_AddRefed<Promise>
GetFileOrDirectoryTask::GetPromise() GetFileOrDirectoryTaskChild::GetPromise()
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return RefPtr<Promise>(mPromise).forget(); return RefPtr<Promise>(mPromise).forget();
} }
FileSystemParams FileSystemParams
GetFileOrDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath, GetFileOrDirectoryTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const ErrorResult& aRv) const
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
@@ -126,26 +98,9 @@ GetFileOrDirectoryTask::GetRequestParams(const nsString& aSerializedDOMPath,
mType == Directory::eDOMRootDirectory); 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 void
GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue, GetFileOrDirectoryTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) ErrorResult& aRv)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
switch (aValue.type()) { 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 nsresult
GetFileOrDirectoryTask::Work() GetFileOrDirectoryTaskParent::IOWork()
{ {
MOZ_ASSERT(XRE_IsParentProcess(), MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!"); "Only call from parent process!");
@@ -245,42 +296,9 @@ GetFileOrDirectoryTask::Work()
} }
void void
GetFileOrDirectoryTask::HandlerCallback() GetFileOrDirectoryTaskParent::GetPermissionAccessType(nsCString& aAccess) const
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); aAccess.AssignLiteral(GET_FILE_OR_DIRECTORY_PERMISSION);
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");
} }
} // namespace dom } // namespace dom
+39 -24
View File
@@ -17,58 +17,42 @@ namespace dom {
class BlobImpl; class BlobImpl;
class GetFileOrDirectoryTask final : public FileSystemTaskBase class GetFileOrDirectoryTaskChild final : public FileSystemTaskChildBase
{ {
public: public:
static already_AddRefed<GetFileOrDirectoryTask> static already_AddRefed<GetFileOrDirectoryTaskChild>
Create(FileSystemBase* aFileSystem, Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath, nsIFile* aTargetPath,
Directory::DirectoryType aType, Directory::DirectoryType aType,
bool aDirectoryOnly, bool aDirectoryOnly,
ErrorResult& aRv); ErrorResult& aRv);
static already_AddRefed<GetFileOrDirectoryTask>
Create(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual virtual
~GetFileOrDirectoryTask(); ~GetFileOrDirectoryTaskChild();
already_AddRefed<Promise> already_AddRefed<Promise>
GetPromise(); GetPromise();
virtual void virtual void
GetPermissionAccessType(nsCString& aAccess) const override; GetPermissionAccessType(nsCString& aAccess) const override;
protected: protected:
virtual FileSystemParams virtual FileSystemParams
GetRequestParams(const nsString& aSerializedDOMPath, GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override; ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue, SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override; ErrorResult& aRv) override;
virtual nsresult
Work() override;
virtual void virtual void
HandlerCallback() override; HandlerCallback() override;
private: private:
// If aDirectoryOnly is set, we should ensure that the target is a directory. // If aDirectoryOnly is set, we should ensure that the target is a directory.
GetFileOrDirectoryTask(FileSystemBase* aFileSystem, GetFileOrDirectoryTaskChild(FileSystemBase* aFileSystem,
nsIFile* aTargetPath, nsIFile* aTargetPath,
Directory::DirectoryType aType, Directory::DirectoryType aType,
bool aDirectoryOnly); bool aDirectoryOnly);
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent);
RefPtr<Promise> mPromise; RefPtr<Promise> mPromise;
nsCOMPtr<nsIFile> mTargetPath; nsCOMPtr<nsIFile> mTargetPath;
@@ -78,6 +62,37 @@ private:
Directory::DirectoryType mType; 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 dom
} // namespace mozilla } // namespace mozilla
+25 -6
View File
@@ -20,10 +20,7 @@ namespace dom {
OSFileSystem::OSFileSystem(const nsAString& aRootDir) OSFileSystem::OSFileSystem(const nsAString& aRootDir)
{ {
mLocalOrDeviceStorageRootPath = aRootDir; mLocalOrDeviceStorageRootPath = aRootDir;
mPermissionCheckType = ePermissionCheckNotRequired;
// 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;
#ifdef DEBUG #ifdef DEBUG
mPermission.AssignLiteral("never-used"); mPermission.AssignLiteral("never-used");
@@ -33,6 +30,8 @@ OSFileSystem::OSFileSystem(const nsAString& aRootDir)
already_AddRefed<FileSystemBase> already_AddRefed<FileSystemBase>
OSFileSystem::Clone() OSFileSystem::Clone()
{ {
AssertIsOnOwningThread();
RefPtr<OSFileSystem> fs = new OSFileSystem(mLocalOrDeviceStorageRootPath); RefPtr<OSFileSystem> fs = new OSFileSystem(mLocalOrDeviceStorageRootPath);
if (mParent) { if (mParent) {
fs->Init(mParent); fs->Init(mParent);
@@ -44,9 +43,10 @@ OSFileSystem::Clone()
void void
OSFileSystem::Init(nsISupports* aParent) OSFileSystem::Init(nsISupports* aParent)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); AssertIsOnOwningThread();
MOZ_ASSERT(!mParent, "No duple Init() calls"); MOZ_ASSERT(!mParent, "No duple Init() calls");
MOZ_ASSERT(aParent); MOZ_ASSERT(aParent);
mParent = aParent; mParent = aParent;
#ifdef DEBUG #ifdef DEBUG
@@ -58,13 +58,14 @@ OSFileSystem::Init(nsISupports* aParent)
nsISupports* nsISupports*
OSFileSystem::GetParentObject() const OSFileSystem::GetParentObject() const
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); AssertIsOnOwningThread();
return mParent; return mParent;
} }
void void
OSFileSystem::GetRootName(nsAString& aRetval) const OSFileSystem::GetRootName(nsAString& aRetval) const
{ {
AssertIsOnOwningThread();
aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL); aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
} }
@@ -91,12 +92,15 @@ OSFileSystem::IsSafeDirectory(Directory* aDir) const
void void
OSFileSystem::Unlink() OSFileSystem::Unlink()
{ {
AssertIsOnOwningThread();
mParent = nullptr; mParent = nullptr;
} }
void void
OSFileSystem::Traverse(nsCycleCollectionTraversalCallback &cb) OSFileSystem::Traverse(nsCycleCollectionTraversalCallback &cb)
{ {
AssertIsOnOwningThread();
OSFileSystem* tmp = this; OSFileSystem* tmp = this;
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent); NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent);
} }
@@ -104,8 +108,23 @@ OSFileSystem::Traverse(nsCycleCollectionTraversalCallback &cb)
void void
OSFileSystem::SerializeDOMPath(nsAString& aOutput) const OSFileSystem::SerializeDOMPath(nsAString& aOutput) const
{ {
AssertIsOnOwningThread();
aOutput = mLocalOrDeviceStorageRootPath; aOutput = mLocalOrDeviceStorageRootPath;
} }
/**
* OSFileSystemParent
*/
OSFileSystemParent::OSFileSystemParent(const nsAString& aRootDir)
{
mLocalOrDeviceStorageRootPath = aRootDir;
mPermissionCheckType = ePermissionCheckNotRequired;
#ifdef DEBUG
mPermission.AssignLiteral("never-used");
#endif
}
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla
+68 -1
View File
@@ -40,6 +40,9 @@ public:
virtual void virtual void
SerializeDOMPath(nsAString& aOutput) const override; SerializeDOMPath(nsAString& aOutput) const override;
virtual bool
ClonableToDifferentThreadOrProcess() const override { return true; }
// CC methods // CC methods
virtual void Unlink() override; virtual void Unlink() override;
virtual void Traverse(nsCycleCollectionTraversalCallback &cb) override; virtual void Traverse(nsCycleCollectionTraversalCallback &cb) override;
@@ -47,7 +50,71 @@ public:
private: private:
virtual ~OSFileSystem() {} 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 } // 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, * 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/. */ * You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PBackground;
include protocol PBlob; include protocol PBlob;
include protocol PContent;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@@ -62,9 +62,9 @@ union FileSystemResponseValue
FileSystemErrorResponse; FileSystemErrorResponse;
}; };
sync protocol PFileSystemRequest protocol PFileSystemRequest
{ {
manager PContent; manager PBackground;
child: child:
async __delete__(FileSystemResponseValue response); async __delete__(FileSystemResponseValue response);
+126 -109
View File
@@ -9,6 +9,7 @@
#include "mozilla/dom/File.h" #include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemBase.h" #include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h" #include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/PFileSystemParams.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
#include "mozilla/dom/ipc/BlobChild.h" #include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/dom/ipc/BlobParent.h" #include "mozilla/dom/ipc/BlobParent.h"
@@ -18,20 +19,24 @@
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
/* static */ already_AddRefed<RemoveTask> /**
RemoveTask::Create(FileSystemBase* aFileSystem, * RemoveTaskChild
nsIFile* aDirPath, */
nsIFile* aTargetPath,
bool aRecursive, /* static */ already_AddRefed<RemoveTaskChild>
ErrorResult& aRv) RemoveTaskChild::Create(FileSystemBase* aFileSystem,
nsIFile* aDirPath,
nsIFile* aTargetPath,
bool aRecursive,
ErrorResult& aRv)
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem); MOZ_ASSERT(aFileSystem);
MOZ_ASSERT(aDirPath); MOZ_ASSERT(aDirPath);
MOZ_ASSERT(aTargetPath); MOZ_ASSERT(aTargetPath);
RefPtr<RemoveTask> task = RefPtr<RemoveTaskChild> task =
new RemoveTask(aFileSystem, aDirPath, aTargetPath, aRecursive); new RemoveTaskChild(aFileSystem, aDirPath, aTargetPath, aRecursive);
// aTargetPath can be null. In this case SetError will be called. // aTargetPath can be null. In this case SetError will be called.
@@ -50,18 +55,112 @@ RemoveTask::Create(FileSystemBase* aFileSystem,
return task.forget(); return task.forget();
} }
/* static */ already_AddRefed<RemoveTask> RemoveTaskChild::RemoveTaskChild(FileSystemBase* aFileSystem,
RemoveTask::Create(FileSystemBase* aFileSystem, nsIFile* aDirPath,
const FileSystemRemoveParams& aParam, nsIFile* aTargetPath,
FileSystemRequestParent* aParent, bool aRecursive)
ErrorResult& aRv) : 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(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem); MOZ_ASSERT(aFileSystem);
MOZ_ASSERT(aDirPath);
MOZ_ASSERT(aTargetPath);
}
RefPtr<RemoveTask> task = RemoveTaskChild::~RemoveTaskChild()
new RemoveTask(aFileSystem, aParam, aParent); {
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()); NS_ConvertUTF16toUTF8 directoryPath(aParam.directory());
aRv = NS_NewNativeLocalFile(directoryPath, true, aRv = NS_NewNativeLocalFile(directoryPath, true,
@@ -86,91 +185,28 @@ RemoveTask::Create(FileSystemBase* aFileSystem,
return task.forget(); return task.forget();
} }
RemoveTask::RemoveTask(FileSystemBase* aFileSystem, RemoveTaskParent::RemoveTaskParent(FileSystemBase* aFileSystem,
nsIFile* aDirPath, const FileSystemRemoveParams& aParam,
nsIFile* aTargetPath, FileSystemRequestParent* aParent)
bool aRecursive) : FileSystemTaskParentBase(aFileSystem, aParam, aParent)
: 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)
, mRecursive(false) , mRecursive(false)
, mReturnValue(false) , mReturnValue(false)
{ {
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!"); MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); AssertIsOnBackgroundThread();
MOZ_ASSERT(aFileSystem); 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 FileSystemResponseValue
RemoveTask::GetSuccessRequestResult(ErrorResult& aRv) const RemoveTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); AssertIsOnBackgroundThread();
return FileSystemBooleanResponse(mReturnValue); 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 nsresult
RemoveTask::Work() RemoveTaskParent::IOWork()
{ {
MOZ_ASSERT(XRE_IsParentProcess(), MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!"); "Only call from parent process!");
@@ -214,28 +250,9 @@ RemoveTask::Work()
} }
void void
RemoveTask::HandlerCallback() RemoveTaskParent::GetPermissionAccessType(nsCString& aAccess) const
{ {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); aAccess.AssignLiteral(REMOVE_TASK_PERMISSION);
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");
} }
} // namespace dom } // namespace dom
+43 -23
View File
@@ -11,30 +11,26 @@
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "mozilla/ErrorResult.h" #include "mozilla/ErrorResult.h"
#define REMOVE_TASK_PERMISSION "write"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
class BlobImpl; class BlobImpl;
class Promise; class Promise;
class RemoveTask final : public FileSystemTaskBase class RemoveTaskChild final : public FileSystemTaskChildBase
{ {
public: public:
static already_AddRefed<RemoveTask> static already_AddRefed<RemoveTaskChild>
Create(FileSystemBase* aFileSystem, Create(FileSystemBase* aFileSystem,
nsIFile* aDirPath, nsIFile* aDirPath,
nsIFile* aTargetPath, nsIFile* aTargetPath,
bool aRecursive, bool aRecursive,
ErrorResult& aRv); ErrorResult& aRv);
static already_AddRefed<RemoveTask>
Create(FileSystemBase* aFileSystem,
const FileSystemRemoveParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual virtual
~RemoveTask(); ~RemoveTaskChild();
already_AddRefed<Promise> already_AddRefed<Promise>
GetPromise(); GetPromise();
@@ -47,28 +43,18 @@ protected:
GetRequestParams(const nsString& aSerializedDOMPath, GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override; ErrorResult& aRv) const override;
virtual FileSystemResponseValue
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual void virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue, SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override; ErrorResult& aRv) override;
virtual nsresult
Work() override;
virtual void virtual void
HandlerCallback() override; HandlerCallback() override;
private: private:
RemoveTask(FileSystemBase* aFileSystem, RemoveTaskChild(FileSystemBase* aFileSystem,
nsIFile* aDirPath, nsIFile* aDirPath,
nsIFile* aTargetPath, nsIFile* aTargetPath,
bool aRecursive); bool aRecursive);
RemoveTask(FileSystemBase* aFileSystem,
const FileSystemRemoveParams& aParam,
FileSystemRequestParent* aParent);
RefPtr<Promise> mPromise; RefPtr<Promise> mPromise;
@@ -82,6 +68,40 @@ private:
bool mReturnValue; 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 dom
} // namespace mozilla } // namespace mozilla
+1
View File
@@ -35,6 +35,7 @@ UNIFIED_SOURCES += [
FINAL_LIBRARY = 'xul' FINAL_LIBRARY = 'xul'
IPDL_SOURCES += [ IPDL_SOURCES += [
'PFileSystemParams.ipdlh',
'PFileSystemRequest.ipdl', 'PFileSystemRequest.ipdl',
] ]
+2
View File
@@ -1,5 +1,7 @@
[DEFAULT] [DEFAULT]
support-files = support-files =
script_fileList.js script_fileList.js
worker_basic.js
[test_basic.html] [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) || eKeyPress == aVisitor.mEvent->mMessage) ||
(keyEvent->keyCode == NS_VK_SPACE && (keyEvent->keyCode == NS_VK_SPACE &&
eKeyUp == aVisitor.mEvent->mMessage)) { eKeyUp == aVisitor.mEvent->mMessage)) {
DispatchSimulatedClick(this, aVisitor.mEvent->mFlags.mIsTrusted, DispatchSimulatedClick(this, aVisitor.mEvent->IsTrusted(),
aVisitor.mPresContext); aVisitor.mPresContext);
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
} }
@@ -308,7 +308,7 @@ HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
{ {
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
if (mouseEvent->button == WidgetMouseEvent::eLeftButton) { if (mouseEvent->button == WidgetMouseEvent::eLeftButton) {
if (mouseEvent->mFlags.mIsTrusted) { if (mouseEvent->IsTrusted()) {
EventStateManager* esm = EventStateManager* esm =
aVisitor.mPresContext->EventStateManager(); aVisitor.mPresContext->EventStateManager();
EventStateManager::SetActiveManager( EventStateManager::SetActiveManager(
+2 -2
View File
@@ -1262,7 +1262,7 @@ HTMLCanvasElement::OnVisibilityChange()
} }
if (mOffscreenCanvas) { if (mOffscreenCanvas) {
class Runnable final : public nsCancelableRunnable class Runnable final : public CancelableRunnable
{ {
public: public:
explicit Runnable(AsyncCanvasRenderer* aRenderer) explicit Runnable(AsyncCanvasRenderer* aRenderer)
@@ -1304,7 +1304,7 @@ void
HTMLCanvasElement::OnMemoryPressure() HTMLCanvasElement::OnMemoryPressure()
{ {
if (mOffscreenCanvas) { if (mOffscreenCanvas) {
class Runnable final : public nsCancelableRunnable class Runnable final : public CancelableRunnable
{ {
public: public:
explicit Runnable(AsyncCanvasRenderer* aRenderer) explicit Runnable(AsyncCanvasRenderer* aRenderer)
+1 -1
View File
@@ -527,7 +527,7 @@ HTMLFormElement::WillHandleEvent(EventChainPostVisitor& aVisitor)
aVisitor.mEvent->mMessage == eFormReset) && aVisitor.mEvent->mMessage == eFormReset) &&
aVisitor.mEvent->mFlags.mInBubblingPhase && aVisitor.mEvent->mFlags.mInBubblingPhase &&
aVisitor.mEvent->originalTarget != static_cast<nsIContent*>(this)) { aVisitor.mEvent->originalTarget != static_cast<nsIContent*>(this)) {
aVisitor.mEvent->mFlags.mPropagationStopped = true; aVisitor.mEvent->StopPropagation();
} }
return NS_OK; return NS_OK;
} }
+8 -17
View File
@@ -3361,8 +3361,7 @@ HTMLInputElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
} }
} }
if (mType == NS_FORM_INPUT_NUMBER && if (mType == NS_FORM_INPUT_NUMBER && aVisitor.mEvent->IsTrusted()) {
aVisitor.mEvent->mFlags.mIsTrusted) {
if (mNumberControlSpinnerIsSpinning) { if (mNumberControlSpinnerIsSpinning) {
// If the timer is running the user has depressed the mouse on one of the // 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 // 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 // We do this after calling the base class' PreHandleEvent so that
// nsIContent::PreHandleEvent doesn't reset any change we make to mCanHandle. // nsIContent::PreHandleEvent doesn't reset any change we make to mCanHandle.
if (mType == NS_FORM_INPUT_NUMBER && if (mType == NS_FORM_INPUT_NUMBER &&
aVisitor.mEvent->mFlags.mIsTrusted && aVisitor.mEvent->IsTrusted() &&
aVisitor.mEvent->originalTarget != this) { aVisitor.mEvent->originalTarget != this) {
// <input type=number> has an anonymous <input type=text> descendant. If // <input type=number> has an anonymous <input type=text> descendant. If
// 'input' or 'change' events are fired at that text control then we need // '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. // - it's the left mouse button.
// We do not prevent non-trusted click because authors can already use // We do not prevent non-trusted click because authors can already use
// .click(). However, the pickers will follow the rules of popup-blocking. // .click(). However, the pickers will follow the rules of popup-blocking.
if (aVisitor.mEvent->mFlags.mDefaultPrevented) { if (aVisitor.mEvent->DefaultPrevented()) {
return NS_OK; return NS_OK;
} }
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent(); WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
@@ -3898,7 +3897,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent(); WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
if (mType == NS_FORM_INPUT_NUMBER && if (mType == NS_FORM_INPUT_NUMBER &&
keyEvent && keyEvent->mMessage == eKeyPress && keyEvent && keyEvent->mMessage == eKeyPress &&
aVisitor.mEvent->mFlags.mIsTrusted && aVisitor.mEvent->IsTrusted() &&
(keyEvent->keyCode == NS_VK_UP || keyEvent->keyCode == NS_VK_DOWN) && (keyEvent->keyCode == NS_VK_UP || keyEvent->keyCode == NS_VK_DOWN) &&
!(keyEvent->IsShift() || keyEvent->IsControl() || !(keyEvent->IsShift() || keyEvent->IsControl() ||
keyEvent->IsAlt() || keyEvent->IsMeta() || 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 // the editor's handling of up/down keypress events. For that reason we
// just ignore aVisitor.mEventStatus here and go ahead and handle the // just ignore aVisitor.mEventStatus here and go ahead and handle the
// event to increase/decrease the value of the number control. // 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); StepNumberControlForUserEvent(keyEvent->keyCode == NS_VK_UP ? 1 : -1);
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
} }
@@ -3976,7 +3975,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
case NS_FORM_INPUT_IMAGE: // Bug 34418 case NS_FORM_INPUT_IMAGE: // Bug 34418
case NS_FORM_INPUT_COLOR: case NS_FORM_INPUT_COLOR:
{ {
DispatchSimulatedClick(this, aVisitor.mEvent->mFlags.mIsTrusted, DispatchSimulatedClick(this, aVisitor.mEvent->IsTrusted(),
aVisitor.mPresContext); aVisitor.mPresContext);
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
} // case } // case
@@ -4005,7 +4004,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
rv = selectedRadioButton->Focus(); rv = selectedRadioButton->Focus();
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
rv = DispatchSimulatedClick(selectedRadioButton, rv = DispatchSimulatedClick(selectedRadioButton,
aVisitor.mEvent->mFlags.mIsTrusted, aVisitor.mEvent->IsTrusted(),
aVisitor.mPresContext); aVisitor.mPresContext);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault; aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
@@ -4117,8 +4116,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
} }
} }
} }
if (mType == NS_FORM_INPUT_NUMBER && if (mType == NS_FORM_INPUT_NUMBER && aVisitor.mEvent->IsTrusted()) {
aVisitor.mEvent->mFlags.mIsTrusted) {
if (mouseEvent->button == WidgetMouseEvent::eLeftButton && if (mouseEvent->button == WidgetMouseEvent::eLeftButton &&
!(mouseEvent->IsShift() || mouseEvent->IsControl() || !(mouseEvent->IsShift() || mouseEvent->IsControl() ||
mouseEvent->IsAlt() || mouseEvent->IsMeta() || mouseEvent->IsAlt() || mouseEvent->IsMeta() ||
@@ -5059,13 +5057,6 @@ HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv)
for (uint32_t i = 0; i < filesAndDirs.Length(); ++i) { for (uint32_t i = 0; i < filesAndDirs.Length(); ++i) {
if (filesAndDirs[i].IsDirectory()) { 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(); RefPtr<Directory> directory = filesAndDirs[i].GetAsDirectory();
// In future we could refactor SetFilePickerFiltersFromAccept to return a // In future we could refactor SetFilePickerFiltersFromAccept to return a
+1 -1
View File
@@ -212,7 +212,7 @@ void
HTMLObjectElement::HandleFocusBlurPlugin(Element* aElement, HTMLObjectElement::HandleFocusBlurPlugin(Element* aElement,
WidgetEvent* aEvent) WidgetEvent* aEvent)
{ {
if (!aEvent->mFlags.mIsTrusted) { if (!aEvent->IsTrusted()) {
return; return;
} }
switch (aEvent->mMessage) { switch (aEvent->mMessage) {
+1 -1
View File
@@ -2280,7 +2280,7 @@ nsGenericHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
nsresult nsresult
nsGenericHTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor) nsGenericHTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
{ {
if (aVisitor.mEvent->mFlags.mIsTrusted) { if (aVisitor.mEvent->IsTrusted()) {
switch (aVisitor.mEvent->mMessage) { switch (aVisitor.mEvent->mMessage) {
case eFocus: { case eFocus: {
// Check to see if focus has bubbled up from a form control's // 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 // 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 class BackgroundCursorChild::DelayedActionRunnable final
: public nsCancelableRunnable : public CancelableRunnable
{ {
using ActionFunc = void (BackgroundCursorChild::*)(); using ActionFunc = void (BackgroundCursorChild::*)();
+1 -1
View File
@@ -67,7 +67,7 @@ const char kMemoryPressureObserverTopic[] = "memory-pressure";
const char kWindowObserverTopic[] = "inner-window-destroyed"; const char kWindowObserverTopic[] = "inner-window-destroyed";
class CancelableRunnableWrapper final class CancelableRunnableWrapper final
: public nsCancelableRunnable : public CancelableRunnable
{ {
nsCOMPtr<nsIRunnable> mRunnable; nsCOMPtr<nsIRunnable> mRunnable;
+3
View File
@@ -24,6 +24,9 @@ interface nsIPushNotifier : nsISupports
[array, size_is(dataLen)] in uint8_t data); [array, size_is(dataLen)] in uint8_t data);
void notifySubscriptionChange(in ACString scope, in nsIPrincipal principal); 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 class CancelableRunnableWrapper final
: public nsCancelableRunnable : public CancelableRunnable
{ {
nsCOMPtr<nsIRunnable> mRunnable; nsCOMPtr<nsIRunnable> mRunnable;
#ifdef DEBUG #ifdef DEBUG
@@ -241,7 +241,7 @@ private:
nsresult Cancel() override; nsresult Cancel() override;
}; };
NS_IMPL_ISUPPORTS_INHERITED0(CancelableRunnableWrapper, nsCancelableRunnable) NS_IMPL_ISUPPORTS_INHERITED0(CancelableRunnableWrapper, CancelableRunnable)
NS_IMETHODIMP NS_IMETHODIMP
CancelableRunnableWrapper::Run() CancelableRunnableWrapper::Run()
+3 -3
View File
@@ -60,11 +60,11 @@ ContentBridgeChild::DeferredDestroy()
bool bool
ContentBridgeChild::RecvAsyncMessage(const nsString& aMsg, ContentBridgeChild::RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
InfallibleTArray<jsipc::CpowEntry>&& aCpows, 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* PBlobChild*
+2 -2
View File
@@ -28,9 +28,9 @@ public:
void DeferredDestroy(); void DeferredDestroy();
virtual bool RecvAsyncMessage(const nsString& aMsg, virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
InfallibleTArray<jsipc::CpowEntry>&& aCpows, InfallibleTArray<jsipc::CpowEntry>&& aCpows,
const IPC::Principal& aPrincipal) override; const IPC::Principal& aPrincipal,
const ClonedMessageData& aData) override;
virtual PBlobChild* virtual PBlobChild*
SendPBlobConstructor(PBlobChild* actor, SendPBlobConstructor(PBlobChild* actor,
+4 -4
View File
@@ -84,12 +84,12 @@ ContentBridgeParent::RecvSyncMessage(const nsString& aMsg,
bool bool
ContentBridgeParent::RecvAsyncMessage(const nsString& aMsg, ContentBridgeParent::RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
InfallibleTArray<jsipc::CpowEntry>&& aCpows, InfallibleTArray<jsipc::CpowEntry>&& aCpows,
const IPC::Principal& aPrincipal) const IPC::Principal& aPrincipal,
const ClonedMessageData& aData)
{ {
return nsIContentParent::RecvAsyncMessage(aMsg, aData, Move(aCpows), return nsIContentParent::RecvAsyncMessage(aMsg, Move(aCpows),
aPrincipal); aPrincipal, aData);
} }
PBlobParent* PBlobParent*
+2 -2
View File
@@ -88,9 +88,9 @@ protected:
nsTArray<StructuredCloneData>* aRetvals) override; nsTArray<StructuredCloneData>* aRetvals) override;
virtual bool RecvAsyncMessage(const nsString& aMsg, virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
InfallibleTArray<jsipc::CpowEntry>&& aCpows, InfallibleTArray<jsipc::CpowEntry>&& aCpows,
const IPC::Principal& aPrincipal) override; const IPC::Principal& aPrincipal,
const ClonedMessageData& aData) override;
virtual jsipc::PJavaScriptParent* AllocPJavaScriptParent() override; virtual jsipc::PJavaScriptParent* AllocPJavaScriptParent() override;
+31 -30
View File
@@ -174,8 +174,6 @@
#include "mozilla/dom/mobileconnection/MobileConnectionChild.h" #include "mozilla/dom/mobileconnection/MobileConnectionChild.h"
#include "mozilla/dom/mobilemessage/SmsChild.h" #include "mozilla/dom/mobilemessage/SmsChild.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.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/bluetooth/PBluetoothChild.h"
#include "mozilla/dom/PFMRadioChild.h" #include "mozilla/dom/PFMRadioChild.h"
#include "mozilla/dom/PPresentationChild.h" #include "mozilla/dom/PPresentationChild.h"
@@ -850,6 +848,10 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
nsTArray<FrameScriptInfo> frameScripts; nsTArray<FrameScriptInfo> frameScripts;
nsCString urlToLoad; nsCString urlToLoad;
PRenderFrameChild* renderFrame = newChild->SendPRenderFrameConstructor();
TextureFactoryIdentifier textureFactoryIdentifier;
uint64_t layersId = 0;
if (aIframeMoz) { if (aIframeMoz) {
MOZ_ASSERT(aTabOpener); MOZ_ASSERT(aTabOpener);
newChild->SendBrowserFrameOpenWindow(aTabOpener, NS_ConvertUTF8toUTF16(url), newChild->SendBrowserFrameOpenWindow(aTabOpener, NS_ConvertUTF8toUTF16(url),
@@ -883,7 +885,7 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
} }
nsresult rv; nsresult rv;
if (!SendCreateWindow(aTabOpener, newChild, if (!SendCreateWindow(aTabOpener, newChild, renderFrame,
aChromeFlags, aCalledFromJS, aPositionSpecified, aChromeFlags, aCalledFromJS, aPositionSpecified,
aSizeSpecified, url, aSizeSpecified, url,
name, features, name, features,
@@ -895,25 +897,25 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
&rv, &rv,
aWindowIsNew, aWindowIsNew,
&frameScripts, &frameScripts,
&urlToLoad)) { &urlToLoad,
&textureFactoryIdentifier,
&layersId)) {
PRenderFrameChild::Send__delete__(renderFrame);
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
PRenderFrameChild::Send__delete__(renderFrame);
PBrowserChild::Send__delete__(newChild);
return rv; return rv;
} }
} }
if (!*aWindowIsNew) { if (!*aWindowIsNew) {
PRenderFrameChild::Send__delete__(renderFrame);
PBrowserChild::Send__delete__(newChild); PBrowserChild::Send__delete__(newChild);
return NS_ERROR_ABORT; 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. if (layersId == 0) { // if renderFrame is invalid.
PRenderFrameChild::Send__delete__(renderFrame); PRenderFrameChild::Send__delete__(renderFrame);
renderFrame = nullptr; renderFrame = nullptr;
@@ -1821,24 +1823,6 @@ ContentChild::DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild* aDev
return true; 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* PMobileConnectionChild*
ContentChild::SendPMobileConnectionConstructor(PMobileConnectionChild* aActor, ContentChild::SendPMobileConnectionConstructor(PMobileConnectionChild* aActor,
const uint32_t& aClientId) const uint32_t& aClientId)
@@ -2426,9 +2410,9 @@ ContentChild::RecvLoadProcessScript(const nsString& aURL)
bool bool
ContentChild::RecvAsyncMessage(const nsString& aMsg, ContentChild::RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
InfallibleTArray<CpowEntry>&& aCpows, InfallibleTArray<CpowEntry>&& aCpows,
const IPC::Principal& aPrincipal) const IPC::Principal& aPrincipal,
const ClonedMessageData& aData)
{ {
RefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::GetChildProcessManager(); RefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::GetChildProcessManager();
if (cpm) { if (cpm) {
@@ -3287,5 +3271,22 @@ ContentChild::RecvPushSubscriptionChange(const nsCString& aScope,
return true; 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 dom
} // namespace mozilla } // namespace mozilla
+6 -8
View File
@@ -192,12 +192,6 @@ public:
virtual bool virtual bool
DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild*) override; DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild*) override;
virtual PFileSystemRequestChild*
AllocPFileSystemRequestChild(const FileSystemParams&) override;
virtual bool
DeallocPFileSystemRequestChild(PFileSystemRequestChild*) override;
virtual PBlobChild* virtual PBlobChild*
AllocPBlobChild(const BlobConstructorParams& aParams) override; AllocPBlobChild(const BlobConstructorParams& aParams) override;
@@ -419,9 +413,9 @@ public:
virtual bool RecvLoadProcessScript(const nsString& aURL) override; virtual bool RecvLoadProcessScript(const nsString& aURL) override;
virtual bool RecvAsyncMessage(const nsString& aMsg, virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
InfallibleTArray<CpowEntry>&& aCpows, InfallibleTArray<CpowEntry>&& aCpows,
const IPC::Principal& aPrincipal) override; const IPC::Principal& aPrincipal,
const ClonedMessageData& aData) override;
virtual bool RecvGeolocationUpdate(const GeoPosition& somewhere) override; virtual bool RecvGeolocationUpdate(const GeoPosition& somewhere) override;
@@ -534,6 +528,10 @@ public:
RecvPushSubscriptionChange(const nsCString& aScope, RecvPushSubscriptionChange(const nsCString& aScope,
const IPC::Principal& aPrincipal) override; 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 // Get the directory for IndexedDB files. We query the parent for this and
// cache the value // cache the value
nsString &GetIndexedDBPath(); nsString &GetIndexedDBPath();
+37 -49
View File
@@ -47,7 +47,6 @@
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/dom/File.h" #include "mozilla/dom/File.h"
#include "mozilla/dom/ExternalHelperAppParent.h" #include "mozilla/dom/ExternalHelperAppParent.h"
#include "mozilla/dom/FileSystemRequestParent.h"
#include "mozilla/dom/GeolocationBinding.h" #include "mozilla/dom/GeolocationBinding.h"
#include "mozilla/dom/Notification.h" #include "mozilla/dom/Notification.h"
#include "mozilla/dom/NuwaParent.h" #include "mozilla/dom/NuwaParent.h"
@@ -85,6 +84,7 @@
#include "mozilla/layers/CompositorBridgeParent.h" #include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/ImageBridgeParent.h" #include "mozilla/layers/ImageBridgeParent.h"
#include "mozilla/layers/SharedBufferManagerParent.h" #include "mozilla/layers/SharedBufferManagerParent.h"
#include "mozilla/layout/RenderFrameParent.h"
#include "mozilla/LookAndFeel.h" #include "mozilla/LookAndFeel.h"
#include "mozilla/media/MediaParent.h" #include "mozilla/media/MediaParent.h"
#include "mozilla/Move.h" #include "mozilla/Move.h"
@@ -297,6 +297,7 @@ using namespace mozilla::gmp;
using namespace mozilla::hal; using namespace mozilla::hal;
using namespace mozilla::ipc; using namespace mozilla::ipc;
using namespace mozilla::layers; using namespace mozilla::layers;
using namespace mozilla::layout;
using namespace mozilla::net; using namespace mozilla::net;
using namespace mozilla::jsipc; using namespace mozilla::jsipc;
using namespace mozilla::psm; using namespace mozilla::psm;
@@ -1176,7 +1177,6 @@ ContentParent::CreateBrowserOrApp(const TabContext& aContext,
RefPtr<TabParent> tp(new TabParent(constructorSender, tabId, RefPtr<TabParent> tp(new TabParent(constructorSender, tabId,
aContext, chromeFlags)); aContext, chromeFlags));
tp->SetInitedByParent(); tp->SetInitedByParent();
tp->SetOwnerElement(aFrameElement);
PBrowserParent* browser = PBrowserParent* browser =
constructorSender->SendPBrowserConstructor( constructorSender->SendPBrowserConstructor(
@@ -1187,7 +1187,10 @@ ContentParent::CreateBrowserOrApp(const TabContext& aContext,
constructorSender->ChildID(), constructorSender->ChildID(),
constructorSender->IsForApp(), constructorSender->IsForApp(),
constructorSender->IsForBrowser()); constructorSender->IsForBrowser());
return TabParent::GetFrom(browser);
RefPtr<TabParent> constructedTabParent = TabParent::GetFrom(browser);
constructedTabParent->SetOwnerElement(aFrameElement);
return constructedTabParent;
} }
return nullptr; return nullptr;
} }
@@ -1285,7 +1288,6 @@ ContentParent::CreateBrowserOrApp(const TabContext& aContext,
RefPtr<TabParent> tp = new TabParent(parent, tabId, aContext, chromeFlags); RefPtr<TabParent> tp = new TabParent(parent, tabId, aContext, chromeFlags);
tp->SetInitedByParent(); tp->SetInitedByParent();
tp->SetOwnerElement(aFrameElement);
PBrowserParent* browser = parent->SendPBrowserConstructor( PBrowserParent* browser = parent->SendPBrowserConstructor(
// DeallocPBrowserParent() releases this ref. // DeallocPBrowserParent() releases this ref.
RefPtr<TabParent>(tp).forget().take(), RefPtr<TabParent>(tp).forget().take(),
@@ -1296,6 +1298,11 @@ ContentParent::CreateBrowserOrApp(const TabContext& aContext,
parent->IsForApp(), parent->IsForApp(),
parent->IsForBrowser()); parent->IsForBrowser());
if (browser) {
RefPtr<TabParent> constructedTabParent = TabParent::GetFrom(browser);
constructedTabParent->SetOwnerElement(aFrameElement);
}
if (isInContentProcess) { if (isInContentProcess) {
// Just return directly without the following check in content process. // Just return directly without the following check in content process.
return TabParent::GetFrom(browser); return TabParent::GetFrom(browser);
@@ -3496,24 +3503,6 @@ ContentParent::DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent* d
return true; 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* PBlobParent*
ContentParent::AllocPBlobParent(const BlobConstructorParams& aParams) ContentParent::AllocPBlobParent(const BlobConstructorParams& aParams)
{ {
@@ -4240,25 +4229,6 @@ ContentParent::RecvSetURITitle(const URIParams& uri,
return true; 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 bool
ContentParent::RecvGetSystemMemory(const uint64_t& aGetterId) ContentParent::RecvGetSystemMemory(const uint64_t& aGetterId)
{ {
@@ -4423,12 +4393,12 @@ ContentParent::RecvRpcMessage(const nsString& aMsg,
bool bool
ContentParent::RecvAsyncMessage(const nsString& aMsg, ContentParent::RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
InfallibleTArray<CpowEntry>&& aCpows, InfallibleTArray<CpowEntry>&& aCpows,
const IPC::Principal& aPrincipal) const IPC::Principal& aPrincipal,
const ClonedMessageData& aData)
{ {
return nsIContentParent::RecvAsyncMessage(aMsg, aData, Move(aCpows), return nsIContentParent::RecvAsyncMessage(aMsg, Move(aCpows), aPrincipal,
aPrincipal); aData);
} }
bool bool
@@ -4672,7 +4642,7 @@ ContentParent::DoSendAsyncMessage(JSContext* aCx,
// Nuwa won't receive frame messages after it is frozen. // Nuwa won't receive frame messages after it is frozen.
return NS_OK; 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_ERROR_UNEXPECTED;
} }
return NS_OK; return NS_OK;
@@ -4897,6 +4867,7 @@ ContentParent::RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
bool bool
ContentParent::RecvGetGraphicsFeatureStatus(const int32_t& aFeature, ContentParent::RecvGetGraphicsFeatureStatus(const int32_t& aFeature,
int32_t* aStatus, int32_t* aStatus,
nsCString* aFailureId,
bool* aSuccess) bool* aSuccess)
{ {
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
@@ -4905,7 +4876,7 @@ ContentParent::RecvGetGraphicsFeatureStatus(const int32_t& aFeature,
return true; return true;
} }
*aSuccess = NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aStatus)); *aSuccess = NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, *aFailureId, aStatus));
return true; return true;
} }
@@ -5378,6 +5349,7 @@ ContentParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestP
bool bool
ContentParent::RecvCreateWindow(PBrowserParent* aThisTab, ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
PBrowserParent* aNewTab, PBrowserParent* aNewTab,
PRenderFrameParent* aRenderFrame,
const uint32_t& aChromeFlags, const uint32_t& aChromeFlags,
const bool& aCalledFromJS, const bool& aCalledFromJS,
const bool& aPositionSpecified, const bool& aPositionSpecified,
@@ -5391,7 +5363,9 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
nsresult* aResult, nsresult* aResult,
bool* aWindowIsNew, bool* aWindowIsNew,
InfallibleTArray<FrameScriptInfo>* aFrameScripts, 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. // We always expect to open a new window here. If we don't, it's an error.
*aWindowIsNew = true; *aWindowIsNew = true;
@@ -5480,7 +5454,7 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
// Opening new tabs is the easy case... // Opening new tabs is the easy case...
if (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB) { if (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB) {
if (NS_WARN_IF(!browserDOMWin)) { if (NS_WARN_IF(!browserDOMWin)) {
*aResult = NS_ERROR_FAILURE; *aResult = NS_ERROR_ABORT;
return true; return true;
} }
@@ -5506,6 +5480,13 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
} }
newTab->SwapFrameScriptsFrom(*aFrameScripts); newTab->SwapFrameScriptsFrom(*aFrameScripts);
RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame);
if (!newTab->SetRenderFrame(rfp) ||
!newTab->GetRenderFrameInfo(aTextureFactoryIdentifier, aLayersId)) {
*aResult = NS_ERROR_FAILURE;
}
return true; return true;
} }
@@ -5590,6 +5571,13 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
MOZ_ASSERT(TabParent::GetFrom(newRemoteTab) == newTab); MOZ_ASSERT(TabParent::GetFrom(newRemoteTab) == newTab);
newTab->SwapFrameScriptsFrom(*aFrameScripts); newTab->SwapFrameScriptsFrom(*aFrameScripts);
RenderFrameParent* rfp = static_cast<RenderFrameParent*>(aRenderFrame);
if (!newTab->SetRenderFrame(rfp) ||
!newTab->GetRenderFrameInfo(aTextureFactoryIdentifier, aLayersId)) {
*aResult = NS_ERROR_FAILURE;
}
return true; return true;
} }
+12 -12
View File
@@ -63,8 +63,13 @@ class PJavaScriptParent;
namespace layers { namespace layers {
class PCompositorBridgeParent; class PCompositorBridgeParent;
class PSharedBufferManagerParent; class PSharedBufferManagerParent;
struct TextureFactoryIdentifier;
} // namespace layers } // namespace layers
namespace layout {
class PRenderFrameParent;
} // namespace layout
namespace dom { namespace dom {
class Element; class Element;
@@ -489,6 +494,7 @@ public:
virtual bool RecvCreateWindow(PBrowserParent* aThisTabParent, virtual bool RecvCreateWindow(PBrowserParent* aThisTabParent,
PBrowserParent* aOpener, PBrowserParent* aOpener,
layout::PRenderFrameParent* aRenderFrame,
const uint32_t& aChromeFlags, const uint32_t& aChromeFlags,
const bool& aCalledFromJS, const bool& aCalledFromJS,
const bool& aPositionSpecified, const bool& aPositionSpecified,
@@ -502,7 +508,9 @@ public:
nsresult* aResult, nsresult* aResult,
bool* aWindowIsNew, bool* aWindowIsNew,
InfallibleTArray<FrameScriptInfo>* aFrameScripts, InfallibleTArray<FrameScriptInfo>* aFrameScripts,
nsCString* aURLToLoad) override; nsCString* aURLToLoad,
layers::TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint64_t* aLayersId) override;
static bool AllocateLayerTreeId(TabParent* aTabParent, uint64_t* aId); static bool AllocateLayerTreeId(TabParent* aTabParent, uint64_t* aId);
@@ -720,12 +728,6 @@ private:
virtual bool virtual bool
DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent*) override; DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent*) override;
virtual PFileSystemRequestParent*
AllocPFileSystemRequestParent(const FileSystemParams&) override;
virtual bool
DeallocPFileSystemRequestParent(PFileSystemRequestParent*) override;
virtual PBlobParent* virtual PBlobParent*
AllocPBlobParent(const BlobConstructorParams& aParams) override; AllocPBlobParent(const BlobConstructorParams& aParams) override;
@@ -738,9 +740,6 @@ private:
virtual bool virtual bool
DeallocPCrashReporterParent(PCrashReporterParent* crashreporter) override; 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, virtual bool RecvIsSecureURI(const uint32_t& aType, const URIParams& aURI,
const uint32_t& aFlags, bool* aIsSecureURI) override; const uint32_t& aFlags, bool* aIsSecureURI) override;
@@ -925,9 +924,9 @@ private:
nsTArray<StructuredCloneData>* aRetvals) override; nsTArray<StructuredCloneData>* aRetvals) override;
virtual bool RecvAsyncMessage(const nsString& aMsg, virtual bool RecvAsyncMessage(const nsString& aMsg,
const ClonedMessageData& aData,
InfallibleTArray<CpowEntry>&& aCpows, InfallibleTArray<CpowEntry>&& aCpows,
const IPC::Principal& aPrincipal) override; const IPC::Principal& aPrincipal,
const ClonedMessageData& aData) override;
virtual bool RecvFilePathUpdateNotify(const nsString& aType, virtual bool RecvFilePathUpdateNotify(const nsString& aType,
const nsString& aStorageName, const nsString& aStorageName,
@@ -1014,6 +1013,7 @@ private:
virtual bool RecvGetGraphicsFeatureStatus(const int32_t& aFeature, virtual bool RecvGetGraphicsFeatureStatus(const int32_t& aFeature,
int32_t* aStatus, int32_t* aStatus,
nsCString* aFailureId,
bool* aSuccess) override; bool* aSuccess) override;
virtual bool RecvGraphicsError(const nsCString& aError) 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; manages PPluginWidget;
both: both:
async AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows, async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
Principal aPrincipal); Principal aPrincipal, ClonedMessageData aData);
/** /**
* Create a layout frame (encapsulating a remote layer tree) for * Create a layout frame (encapsulating a remote layer tree) for
@@ -482,10 +482,6 @@ parent:
*/ */
async RemotePaintIsReady(); 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 * 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 * dimensions has been requested, likely through win.moveTo or resizeTo
@@ -715,6 +711,13 @@ child:
float aVolume, float aVolume,
bool aMuted); 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! * FIXME: write protocol!
+15 -72
View File
@@ -21,7 +21,6 @@ include protocol PHandlerService;
include protocol PDeviceStorageRequest; include protocol PDeviceStorageRequest;
include protocol PFileDescriptorSet; include protocol PFileDescriptorSet;
include protocol PFMRadio; include protocol PFMRadio;
include protocol PFileSystemRequest;
include protocol PHal; include protocol PHal;
include protocol PHeapSnapshotTempFileHelper; include protocol PHeapSnapshotTempFileHelper;
include protocol PIcc; include protocol PIcc;
@@ -42,6 +41,7 @@ include protocol PPluginModule;
include protocol PGMP; include protocol PGMP;
include protocol PPrinting; include protocol PPrinting;
include protocol POfflineCacheUpdate; include protocol POfflineCacheUpdate;
include protocol PRenderFrame;
include protocol PScreenManager; include protocol PScreenManager;
include protocol PSharedBufferManager; include protocol PSharedBufferManager;
include protocol PSms; 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 struct LookAndFeelInt from "mozilla/widget/WidgetMessageUtils.h";
using class mozilla::dom::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h"; using class mozilla::dom::ipc::StructuredCloneData from "ipc/IPCMessageUtils.h";
using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h"; using mozilla::DataStorageType from "ipc/DataStorageIPCUtils.h";
using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
union ChromeRegistryItem union ChromeRegistryItem
{ {
@@ -266,67 +267,6 @@ union FMRadioRequestParams
FMRadioRequestCancelSeekParams; 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 { union PrefValue {
nsCString; nsCString;
int32_t; int32_t;
@@ -473,7 +413,6 @@ prio(normal upto urgent) sync protocol PContent
manages PCrashReporter; manages PCrashReporter;
manages PCycleCollectWithLogs; manages PCycleCollectWithLogs;
manages PDeviceStorageRequest; manages PDeviceStorageRequest;
manages PFileSystemRequest;
manages PPSMContentDownloader; manages PPSMContentDownloader;
manages PExternalHelperApp; manages PExternalHelperApp;
manages PFileDescriptorSet; manages PFileDescriptorSet;
@@ -730,6 +669,11 @@ child:
*/ */
async PushSubscriptionChange(nsCString scope, Principal principal); 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 * Windows specific: associate this content process with the browsers
* audio session. * audio session.
@@ -811,13 +755,8 @@ parent:
async PRemoteSpellcheckEngine(); async PRemoteSpellcheckEngine();
async PDeviceStorageRequest(DeviceStorageParams params); async PDeviceStorageRequest(DeviceStorageParams params);
async PFileSystemRequest(FileSystemParams params);
sync PCrashReporter(NativeThreadId tid, uint32_t processType); sync PCrashReporter(NativeThreadId tid, uint32_t processType);
prio(urgent) sync GetRandomValues(uint32_t length)
returns (uint8_t[] randomValues);
async GetSystemMemory(uint64_t getterId); async GetSystemMemory(uint64_t getterId);
sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags) sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags)
@@ -1008,7 +947,8 @@ parent:
bool isAudio, bool isAudio,
bool isVideo); 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 // Graphics errors
async GraphicsError(nsCString aError); async GraphicsError(nsCString aError);
@@ -1166,6 +1106,7 @@ parent:
sync CreateWindow(nullable PBrowser aThisTab, sync CreateWindow(nullable PBrowser aThisTab,
PBrowser aNewTab, PBrowser aNewTab,
PRenderFrame aRenderFrame,
uint32_t aChromeFlags, uint32_t aChromeFlags,
bool aCalledFromJS, bool aCalledFromJS,
bool aPositionSpecified, bool aPositionSpecified,
@@ -1179,7 +1120,9 @@ parent:
returns (nsresult rv, returns (nsresult rv,
bool windowOpened, bool windowOpened,
FrameScriptInfo[] frameScripts, FrameScriptInfo[] frameScripts,
nsCString urlToLoad); nsCString urlToLoad,
TextureFactoryIdentifier textureFactoryIdentifier,
uint64_t layersId);
sync GetDeviceStorageLocation(nsString type) sync GetDeviceStorageLocation(nsString type)
returns (nsString path); returns (nsString path);
@@ -1198,8 +1141,8 @@ parent:
*/ */
sync UngrabPointer(uint32_t time); sync UngrabPointer(uint32_t time);
both: both:
async AsyncMessage(nsString aMessage, ClonedMessageData aData, async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
CpowEntry[] aCpows, Principal aPrincipal); Principal aPrincipal, ClonedMessageData aData);
}; };
} }

Some files were not shown because too many files have changed in this diff Show More