зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
afe4d4b240
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Touch clobber again because of bug 1336456
|
||||
Touching clobber for Telemetry IPC refactor in bug 1339749.
|
||||
|
|
|
@ -152,7 +152,7 @@ DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID,
|
|||
if (mShutdown)
|
||||
return IPC_OK();
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
|
||||
MOZ_ASSERT(CheckDocTree());
|
||||
|
||||
// We shouldn't actually need this because mAccessibles shouldn't have an
|
||||
// entry for the document itself, but it doesn't hurt to be explicit.
|
||||
|
@ -587,8 +587,10 @@ DocAccessibleParent::SetCOMProxy(const RefPtr<IAccessible>& aCOMProxy)
|
|||
}
|
||||
}
|
||||
}
|
||||
Unused << SendParentCOMProxy(holder, reinterpret_cast<uintptr_t>(
|
||||
mEmulatedWindowHandle), hWndAccHolder);
|
||||
|
||||
Unused << SendEmulatedWindow(reinterpret_cast<uintptr_t>(mEmulatedWindowHandle),
|
||||
hWndAccHolder);
|
||||
Unused << SendParentCOMProxy(holder);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -46,19 +46,11 @@ DocAccessibleChild::Shutdown()
|
|||
}
|
||||
|
||||
ipc::IPCResult
|
||||
DocAccessibleChild::RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy,
|
||||
const WindowsHandle& aEmulatedWindowHandle,
|
||||
const IAccessibleHolder& aEmulatedWindowCOMProxy)
|
||||
DocAccessibleChild::RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy)
|
||||
{
|
||||
MOZ_ASSERT(!mParentProxy && !aParentCOMProxy.IsNull());
|
||||
mParentProxy.reset(const_cast<IAccessibleHolder&>(aParentCOMProxy).Release());
|
||||
SetConstructedInParentProcess();
|
||||
mEmulatedWindowHandle = reinterpret_cast<HWND>(aEmulatedWindowHandle);
|
||||
if (!aEmulatedWindowCOMProxy.IsNull()) {
|
||||
MOZ_ASSERT(!mEmulatedWindowProxy);
|
||||
mEmulatedWindowProxy.reset(
|
||||
const_cast<IAccessibleHolder&>(aEmulatedWindowCOMProxy).Release());
|
||||
}
|
||||
|
||||
for (uint32_t i = 0, l = mDeferredEvents.Length(); i < l; ++i) {
|
||||
mDeferredEvents[i]->Dispatch();
|
||||
|
@ -69,6 +61,20 @@ DocAccessibleChild::RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
ipc::IPCResult
|
||||
DocAccessibleChild::RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandle,
|
||||
const IAccessibleHolder& aEmulatedWindowCOMProxy)
|
||||
{
|
||||
mEmulatedWindowHandle = reinterpret_cast<HWND>(aEmulatedWindowHandle);
|
||||
if (!aEmulatedWindowCOMProxy.IsNull()) {
|
||||
MOZ_ASSERT(!mEmulatedWindowProxy);
|
||||
mEmulatedWindowProxy.reset(
|
||||
const_cast<IAccessibleHolder&>(aEmulatedWindowCOMProxy).Release());
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void
|
||||
DocAccessibleChild::PushDeferredEvent(UniquePtr<DeferredEvent> aEvent)
|
||||
{
|
||||
|
|
|
@ -28,9 +28,10 @@ public:
|
|||
virtual void Shutdown() override;
|
||||
|
||||
virtual ipc::IPCResult
|
||||
RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy,
|
||||
const WindowsHandle& aEmulatedWindowHandle,
|
||||
const IAccessibleHolder& aEmulatedWindowCOMProxy) override;
|
||||
RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy) override;
|
||||
virtual ipc::IPCResult
|
||||
RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandle,
|
||||
const IAccessibleHolder& aEmulatedWindowCOMProxy) override;
|
||||
|
||||
HWND GetEmulatedWindowHandle() const { return mEmulatedWindowHandle; }
|
||||
IAccessible* GetEmulatedWindowIAccessible() const { return mEmulatedWindowProxy.get(); }
|
||||
|
|
|
@ -66,8 +66,8 @@ parent:
|
|||
returns (IAccessibleHolder aPluginCOMProxy);
|
||||
|
||||
child:
|
||||
async ParentCOMProxy(IAccessibleHolder aParentCOMProxy,
|
||||
WindowsHandle aEmulatedWindowHandle,
|
||||
async ParentCOMProxy(IAccessibleHolder aParentCOMProxy);
|
||||
async EmulatedWindow(WindowsHandle aEmulatedWindowHandle,
|
||||
IAccessibleHolder aEmulatedWindowCOMProxy);
|
||||
|
||||
async __delete__();
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
hidden="true"
|
||||
orient="vertical"
|
||||
noautofocus="true"
|
||||
followanchor="false"
|
||||
role="alert"/>
|
||||
|
||||
<popupnotification id="webRTC-shareDevices-notification" hidden="true">
|
||||
|
|
|
@ -204,23 +204,24 @@
|
|||
# define _LARGEFILE_SOURCE 1
|
||||
#endif
|
||||
|
||||
/* The GCC_VERSION, CLANG_VERSION, and MSVC_VERSION macros are used to
|
||||
/* The GCC_VERSION and MSVC_VERSION macros are used to
|
||||
** conditionally include optimizations for each of these compilers. A
|
||||
** value of 0 means that compiler is not being used. The
|
||||
** SQLITE_DISABLE_INTRINSIC macro means do not use any compiler-specific
|
||||
** optimizations, and hence set all compiler macros to 0
|
||||
**
|
||||
** There was once also a CLANG_VERSION macro. However, we learn that the
|
||||
** version numbers in clang are for "marketing" only and are inconsistent
|
||||
** and unreliable. Fortunately, all versions of clang also recognize the
|
||||
** gcc version numbers and have reasonable settings for gcc version numbers,
|
||||
** so the GCC_VERSION macro will be set to a correct non-zero value even
|
||||
** when compiling with clang.
|
||||
*/
|
||||
#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
|
||||
#else
|
||||
# define GCC_VERSION 0
|
||||
#endif
|
||||
#if defined(__clang__) && !defined(_WIN32) && !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
# define CLANG_VERSION \
|
||||
(__clang_major__*1000000+__clang_minor__*1000+__clang_patchlevel__)
|
||||
#else
|
||||
# define CLANG_VERSION 0
|
||||
#endif
|
||||
#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
# define MSVC_VERSION _MSC_VER
|
||||
#else
|
||||
|
@ -28697,7 +28698,7 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
|
|||
u32 x;
|
||||
memcpy(&x,p,4);
|
||||
return x;
|
||||
#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000)
|
||||
#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
|
||||
u32 x;
|
||||
memcpy(&x,p,4);
|
||||
return __builtin_bswap32(x);
|
||||
|
@ -28713,7 +28714,7 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
|
|||
SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){
|
||||
#if SQLITE_BYTEORDER==4321
|
||||
memcpy(p,&v,4);
|
||||
#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000)
|
||||
#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
|
||||
u32 x = __builtin_bswap32(v);
|
||||
memcpy(p,&x,4);
|
||||
#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
|
||||
|
@ -28832,7 +28833,7 @@ SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
|
|||
** overflow, leave *pA unchanged and return 1.
|
||||
*/
|
||||
SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){
|
||||
#if GCC_VERSION>=5004000 || CLANG_VERSION>=4000000
|
||||
#if GCC_VERSION>=5004000
|
||||
return __builtin_add_overflow(*pA, iB, pA);
|
||||
#else
|
||||
i64 iA = *pA;
|
||||
|
@ -28852,7 +28853,7 @@ SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){
|
|||
#endif
|
||||
}
|
||||
SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
|
||||
#if GCC_VERSION>=5004000 || CLANG_VERSION>=4000000
|
||||
#if GCC_VERSION>=5004000
|
||||
return __builtin_sub_overflow(*pA, iB, pA);
|
||||
#else
|
||||
testcase( iB==SMALLEST_INT64+1 );
|
||||
|
@ -28867,7 +28868,7 @@ SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
|
|||
#endif
|
||||
}
|
||||
SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){
|
||||
#if GCC_VERSION>=5004000 || CLANG_VERSION>=4000000
|
||||
#if GCC_VERSION>=5004000
|
||||
return __builtin_mul_overflow(*pA, iB, pA);
|
||||
#else
|
||||
i64 iA = *pA;
|
||||
|
@ -163304,7 +163305,11 @@ struct RtreeMatchArg {
|
|||
# define MIN(x,y) ((x) > (y) ? (y) : (x))
|
||||
#endif
|
||||
|
||||
/* What version of GCC is being used. 0 means GCC is not being used */
|
||||
/* What version of GCC is being used. 0 means GCC is not being used .
|
||||
** Note that the GCC_VERSION macro will also be set correctly when using
|
||||
** clang, since clang works hard to be gcc compatible. So the gcc
|
||||
** optimizations will also work when compiling with clang.
|
||||
*/
|
||||
#ifndef GCC_VERSION
|
||||
#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__)
|
||||
|
@ -163313,16 +163318,6 @@ struct RtreeMatchArg {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/* What version of CLANG is being used. 0 means CLANG is not being used */
|
||||
#ifndef CLANG_VERSION
|
||||
#if defined(__clang__) && !defined(_WIN32) && !defined(SQLITE_DISABLE_INTRINSIC)
|
||||
# define CLANG_VERSION \
|
||||
(__clang_major__*1000000+__clang_minor__*1000+__clang_patchlevel__)
|
||||
#else
|
||||
# define CLANG_VERSION 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The testcase() macro should already be defined in the amalgamation. If
|
||||
** it is not, make it a no-op.
|
||||
*/
|
||||
|
@ -163373,7 +163368,7 @@ static void readCoord(u8 *p, RtreeCoord *pCoord){
|
|||
assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */
|
||||
#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
|
||||
pCoord->u = _byteswap_ulong(*(u32*)p);
|
||||
#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000)
|
||||
#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
|
||||
pCoord->u = __builtin_bswap32(*(u32*)p);
|
||||
#elif SQLITE_BYTEORDER==4321
|
||||
pCoord->u = *(u32*)p;
|
||||
|
@ -163391,7 +163386,7 @@ static i64 readInt64(u8 *p){
|
|||
u64 x;
|
||||
memcpy(&x, p, 8);
|
||||
return (i64)_byteswap_uint64(x);
|
||||
#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000)
|
||||
#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
|
||||
u64 x;
|
||||
memcpy(&x, p, 8);
|
||||
return (i64)__builtin_bswap64(x);
|
||||
|
@ -163427,7 +163422,7 @@ static int writeCoord(u8 *p, RtreeCoord *pCoord){
|
|||
assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */
|
||||
assert( sizeof(RtreeCoord)==4 );
|
||||
assert( sizeof(u32)==4 );
|
||||
#if SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000)
|
||||
#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
|
||||
i = __builtin_bswap32(pCoord->u);
|
||||
memcpy(p, &i, 4);
|
||||
#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
|
||||
|
@ -163446,7 +163441,7 @@ static int writeCoord(u8 *p, RtreeCoord *pCoord){
|
|||
return 4;
|
||||
}
|
||||
static int writeInt64(u8 *p, i64 i){
|
||||
#if SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000)
|
||||
#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
|
||||
i = (i64)__builtin_bswap64((u64)i);
|
||||
memcpy(p, &i, 8);
|
||||
#elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
|
||||
|
@ -164002,7 +163997,7 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){
|
|||
c.u = _byteswap_ulong(*(u32*)a); \
|
||||
r = eInt ? (sqlite3_rtree_dbl)c.i : (sqlite3_rtree_dbl)c.f; \
|
||||
}
|
||||
#elif SQLITE_BYTEORDER==1234 && (GCC_VERSION>=4003000 || CLANG_VERSION>=3000000)
|
||||
#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
|
||||
#define RTREE_DECODE_COORD(eInt, a, r) { \
|
||||
RtreeCoord c; /* Coordinate decoded */ \
|
||||
c.u = __builtin_bswap32(*(u32*)a); \
|
||||
|
|
|
@ -460,4 +460,4 @@ skip-if = e10s && debug
|
|||
[browser_dbg_WorkerActor.attachThread.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_split-console-keypress.js]
|
||||
skip-if = e10s && (debug || os == "linux") # Bug 1214439
|
||||
skip-if = (debug || os == "linux") # Bug 1214439
|
||||
|
|
|
@ -161,7 +161,7 @@ const Message = createClass({
|
|||
|
||||
let notesNodes;
|
||||
if (notes) {
|
||||
notes.map(note => dom.span(
|
||||
notesNodes = notes.map(note => dom.span(
|
||||
{ className: "message-flex-body error-note" },
|
||||
dom.span({ className: "message-body devtools-monospace" },
|
||||
"note: " + note.messageBody
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "nsCExternalHandlerService.h"
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/BaseBlobImpl.h"
|
||||
|
||||
#include "ArchiveReader.h"
|
||||
|
||||
|
@ -21,7 +21,7 @@ BEGIN_ARCHIVEREADER_NAMESPACE
|
|||
/**
|
||||
* ArchiveZipBlobImpl to BlobImpl
|
||||
*/
|
||||
class ArchiveZipBlobImpl : public BlobImplBase
|
||||
class ArchiveZipBlobImpl : public BaseBlobImpl
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
@ -31,7 +31,7 @@ public:
|
|||
uint64_t aLength,
|
||||
ZipCentral& aCentral,
|
||||
BlobImpl* aBlobImpl)
|
||||
: BlobImplBase(aName, aContentType, aLength),
|
||||
: BaseBlobImpl(aName, aContentType, aLength),
|
||||
mCentral(aCentral),
|
||||
mBlobImpl(aBlobImpl),
|
||||
mFilename(aName)
|
||||
|
@ -45,7 +45,7 @@ public:
|
|||
uint64_t aLength,
|
||||
ZipCentral& aCentral,
|
||||
BlobImpl* aBlobImpl)
|
||||
: BlobImplBase(aContentType, aStart, aLength),
|
||||
: BaseBlobImpl(aContentType, aStart, aLength),
|
||||
mCentral(aCentral),
|
||||
mBlobImpl(aBlobImpl),
|
||||
mFilename(aName)
|
||||
|
|
|
@ -829,6 +829,10 @@ AudioChannelService::GetAudioChannelVolume(mozIDOMWindowProxy* aWindow,
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
auto* window = nsPIDOMWindowOuter::From(aWindow)->GetScriptableTop();
|
||||
if (!window) {
|
||||
*aVolume = 0.f;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aVolume = GetAudioChannelVolume(window, (AudioChannel)aAudioChannel);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -859,6 +863,9 @@ AudioChannelService::SetAudioChannelVolume(mozIDOMWindowProxy* aWindow,
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
auto* window = nsPIDOMWindowOuter::From(aWindow)->GetScriptableTop();
|
||||
if (!window) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
SetAudioChannelVolume(window, (AudioChannel)aAudioChannel, aVolume);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -883,6 +890,10 @@ AudioChannelService::GetAudioChannelMuted(mozIDOMWindowProxy* aWindow,
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
auto* window = nsPIDOMWindowOuter::From(aWindow)->GetScriptableTop();
|
||||
if (!window) {
|
||||
*aMuted = false;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aMuted = GetAudioChannelMuted(window, (AudioChannel)aAudioChannel);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -918,6 +929,9 @@ AudioChannelService::SetAudioChannelMuted(mozIDOMWindowProxy* aWindow,
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
auto* window = nsPIDOMWindowOuter::From(aWindow)->GetScriptableTop();
|
||||
if (!window) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
SetAudioChannelMuted(window, (AudioChannel)aAudioChannel, aMuted);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -942,6 +956,10 @@ AudioChannelService::IsAudioChannelActive(mozIDOMWindowProxy* aWindow,
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
auto* window = nsPIDOMWindowOuter::From(aWindow)->GetScriptableTop();
|
||||
if (!window) {
|
||||
*aActive = false;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aActive = IsAudioChannelActive(window, (AudioChannel)aAudioChannel);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -952,6 +970,9 @@ AudioChannelService::IsWindowActive(nsPIDOMWindowOuter* aWindow)
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
auto* window = nsPIDOMWindowOuter::From(aWindow)->GetScriptableTop();
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
AudioChannelWindow* winData = GetOrCreateWindowData(window);
|
||||
return !winData->mAudibleAgents.IsEmpty();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script>
|
||||
window.onload = function(){
|
||||
let x = document.getElementsByTagName("iframe")[0];
|
||||
let w = window.open();
|
||||
let o = window.frames[0];
|
||||
x.remove();
|
||||
o.requestIdleCallback(function(){});
|
||||
w.close();
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<iframe></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -1 +1,2 @@
|
|||
load 1223734.html
|
||||
load 1339930.html
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "mozilla/dom/DocumentFragment.h"
|
||||
#include "mozilla/dom/DOMTypes.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/FileBlobImpl.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/dom/HTMLTemplateElement.h"
|
||||
#include "mozilla/dom/HTMLContentElement.h"
|
||||
|
@ -7876,12 +7877,21 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
|
|||
continue;
|
||||
}
|
||||
|
||||
blobImpl = new BlobImplFile(file);
|
||||
ErrorResult rv;
|
||||
blobImpl = new FileBlobImpl(file);
|
||||
|
||||
IgnoredErrorResult rv;
|
||||
|
||||
// Ensure that file data is cached no that the content process
|
||||
// has this data available to it when passed over:
|
||||
blobImpl->GetSize(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
blobImpl->GetLastModified(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (aInSyncMessage) {
|
||||
// Can't do anything.
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "nsNetUtil.h"
|
||||
#include "nsScriptLoader.h"
|
||||
#include "nsFrameLoader.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIConsoleService.h"
|
||||
|
|
|
@ -395,6 +395,7 @@ GK_ATOM(floor, "floor")
|
|||
GK_ATOM(flowlength, "flowlength")
|
||||
GK_ATOM(focus, "focus")
|
||||
GK_ATOM(focused, "focused")
|
||||
GK_ATOM(followanchor, "followanchor")
|
||||
GK_ATOM(following, "following")
|
||||
GK_ATOM(followingSibling, "following-sibling")
|
||||
GK_ATOM(font, "font")
|
||||
|
|
|
@ -4189,7 +4189,13 @@ nsPIDOMWindowInner::IsPlayingAudio()
|
|||
if (!acs) {
|
||||
return false;
|
||||
}
|
||||
return acs->IsWindowActive(GetOuterWindow());
|
||||
auto outer = GetOuterWindow();
|
||||
if (!outer) {
|
||||
// We've been unlinked and are about to die. Not a good time to pretend to
|
||||
// be playing audio.
|
||||
return false;
|
||||
}
|
||||
return acs->IsWindowActive(outer);
|
||||
}
|
||||
|
||||
mozilla::dom::TimeoutManager&
|
||||
|
@ -14320,6 +14326,18 @@ nsPIDOMWindowOuter::SetLargeAllocStatus(LargeAllocStatus aStatus)
|
|||
mLargeAllocStatus = aStatus;
|
||||
}
|
||||
|
||||
bool
|
||||
nsPIDOMWindowOuter::IsTopLevelWindow()
|
||||
{
|
||||
return nsGlobalWindow::Cast(this)->IsTopLevelWindow();
|
||||
}
|
||||
|
||||
bool
|
||||
nsPIDOMWindowOuter::HadOriginalOpener() const
|
||||
{
|
||||
return nsGlobalWindow::Cast(this)->HadOriginalOpener();
|
||||
}
|
||||
|
||||
void
|
||||
nsGlobalWindow::ReportLargeAllocStatus()
|
||||
{
|
||||
|
|
|
@ -292,6 +292,10 @@ public:
|
|||
return static_cast<nsGlobalWindow*>(
|
||||
reinterpret_cast<nsPIDOMWindow<nsISupports>*>(aPIWin));
|
||||
}
|
||||
static const nsGlobalWindow* Cast(const nsPIDOMWindowOuter* aPIWin) {
|
||||
return static_cast<const nsGlobalWindow*>(
|
||||
reinterpret_cast<const nsPIDOMWindow<nsISupports>*>(aPIWin));
|
||||
}
|
||||
static nsGlobalWindow* Cast(mozIDOMWindowProxy* aWin) {
|
||||
return Cast(nsPIDOMWindowOuter::From(aWin));
|
||||
}
|
||||
|
|
|
@ -1631,7 +1631,7 @@ nsJSContext::EndCycleCollectionCallback(CycleCollectorResults &aResults)
|
|||
gcMsg.AssignLiteral(", forced a GC");
|
||||
}
|
||||
|
||||
NS_NAMED_MULTILINE_LITERAL_STRING(kFmt,
|
||||
NS_NAMED_LITERAL_STRING(kFmt,
|
||||
u"CC(T+%.1f)[%s-%i] max pause: %lums, total time: %lums, slices: %lu, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu|%lu|%lu waiting for GC)%s\n"
|
||||
u"ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, max sync: %lu ms, removed: %lu");
|
||||
nsString msg;
|
||||
|
@ -1663,7 +1663,7 @@ nsJSContext::EndCycleCollectionCallback(CycleCollectorResults &aResults)
|
|||
}
|
||||
|
||||
if (sPostGCEventsToObserver) {
|
||||
NS_NAMED_MULTILINE_LITERAL_STRING(kJSONFmt,
|
||||
NS_NAMED_LITERAL_STRING(kJSONFmt,
|
||||
u"{ \"timestamp\": %llu, "
|
||||
u"\"duration\": %lu, "
|
||||
u"\"max_slice_pause\": %lu, "
|
||||
|
|
|
@ -974,6 +974,9 @@ public:
|
|||
float GetDevicePixelRatio(mozilla::dom::CallerType aCallerType);
|
||||
|
||||
void SetLargeAllocStatus(mozilla::dom::LargeAllocStatus aStatus);
|
||||
|
||||
bool IsTopLevelWindow();
|
||||
bool HadOriginalOpener() const;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsPIDOMWindowOuter, NS_PIDOMWINDOWOUTER_IID)
|
||||
|
|
|
@ -107,10 +107,6 @@ DOMInterfaces = {
|
|||
'nativeType': 'mozilla::dom::AudioContext',
|
||||
},
|
||||
|
||||
'Blob': {
|
||||
'headerFile': 'mozilla/dom/File.h',
|
||||
},
|
||||
|
||||
'BatteryManager': {
|
||||
'nativeType': 'mozilla::dom::battery::BatteryManager',
|
||||
'headerFile': 'BatteryManager.h'
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include "nsIMIMEService.h"
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileBlobImpl.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "ContentParent.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
@ -281,7 +281,7 @@ DeviceStorageRequestParent::PostBlobSuccessEvent::CancelableRun() {
|
|||
nsString fullPath;
|
||||
mFile->GetFullPath(fullPath);
|
||||
RefPtr<BlobImpl> blob =
|
||||
new BlobImplFile(fullPath, mime, mLength, mFile->mFile,
|
||||
new FileBlobImpl(fullPath, mime, mLength, mFile->mFile,
|
||||
mLastModificationDate);
|
||||
|
||||
ContentParent* cp = static_cast<ContentParent*>(mParent->Manager());
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "mozilla/dom/DeviceStorageFileSystem.h"
|
||||
#include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
|
||||
#include "mozilla/dom/Directory.h"
|
||||
#include "mozilla/dom/FileBlobImpl.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/PBrowserChild.h"
|
||||
|
@ -34,6 +35,7 @@
|
|||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIDirectoryEnumerator.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
@ -3995,9 +3997,9 @@ DeviceStorageRequestManager::Resolve(uint32_t aId, DeviceStorageFile* aFile,
|
|||
MOZ_ASSERT(aFile->mLength != UINT64_MAX);
|
||||
MOZ_ASSERT(aFile->mLastModifiedDate != UINT64_MAX);
|
||||
|
||||
RefPtr<BlobImpl> blobImpl = new BlobImplFile(fullPath, aFile->mMimeType,
|
||||
aFile->mLength, aFile->mFile,
|
||||
aFile->mLastModifiedDate);
|
||||
RefPtr<BlobImpl> blobImpl = new FileBlobImpl(fullPath, aFile->mMimeType,
|
||||
aFile->mLength, aFile->mFile,
|
||||
aFile->mLastModifiedDate);
|
||||
|
||||
/* File should start out as mutable by default but we should turn
|
||||
that off if it wasn't requested. */
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/BaseBlobImpl.h"
|
||||
#include "prtime.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
void
|
||||
BaseBlobImpl::GetName(nsAString& aName) const
|
||||
{
|
||||
MOZ_ASSERT(mIsFile, "Should only be called on files");
|
||||
aName = mName;
|
||||
}
|
||||
|
||||
void
|
||||
BaseBlobImpl::GetDOMPath(nsAString& aPath) const
|
||||
{
|
||||
MOZ_ASSERT(mIsFile, "Should only be called on files");
|
||||
aPath = mPath;
|
||||
}
|
||||
|
||||
void
|
||||
BaseBlobImpl::SetDOMPath(const nsAString& aPath)
|
||||
{
|
||||
MOZ_ASSERT(mIsFile, "Should only be called on files");
|
||||
mPath = aPath;
|
||||
}
|
||||
|
||||
void
|
||||
BaseBlobImpl::GetMozFullPath(nsAString& aFileName,
|
||||
SystemCallerGuarantee /* unused */,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(mIsFile, "Should only be called on files");
|
||||
|
||||
GetMozFullPathInternal(aFileName, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
BaseBlobImpl::GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) const
|
||||
{
|
||||
if (!mIsFile) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
aFileName.Truncate();
|
||||
}
|
||||
|
||||
void
|
||||
BaseBlobImpl::GetType(nsAString& aType)
|
||||
{
|
||||
aType = mContentType;
|
||||
}
|
||||
|
||||
int64_t
|
||||
BaseBlobImpl::GetLastModified(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(mIsFile, "Should only be called on files");
|
||||
if (IsDateUnknown()) {
|
||||
mLastModificationDate = PR_Now();
|
||||
}
|
||||
|
||||
return mLastModificationDate / PR_USEC_PER_MSEC;
|
||||
}
|
||||
|
||||
void
|
||||
BaseBlobImpl::SetLastModified(int64_t aLastModified)
|
||||
{
|
||||
mLastModificationDate = aLastModified * PR_USEC_PER_MSEC;
|
||||
}
|
||||
|
||||
int64_t
|
||||
BaseBlobImpl::GetFileId()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
nsresult
|
||||
BaseBlobImpl::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
|
||||
nsACString& aContentType, nsACString& aCharset)
|
||||
{
|
||||
MOZ_ASSERT(aContentLength);
|
||||
|
||||
ErrorResult rv;
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
GetInternalStream(getter_AddRefs(stream), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
*aContentLength = GetSize(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
nsAutoString contentType;
|
||||
GetType(contentType);
|
||||
|
||||
if (contentType.IsEmpty()) {
|
||||
aContentType.SetIsVoid(true);
|
||||
} else {
|
||||
CopyUTF16toUTF8(contentType, aContentType);
|
||||
}
|
||||
|
||||
aCharset.Truncate();
|
||||
|
||||
stream.forget(aBody);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
BaseBlobImpl::GetMutable(bool* aMutable) const
|
||||
{
|
||||
*aMutable = !mImmutable;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
BaseBlobImpl::SetMutable(bool aMutable)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
NS_ENSURE_ARG(!mImmutable || !aMutable);
|
||||
|
||||
if (!mImmutable && !aMutable) {
|
||||
// Force the content type and size to be cached
|
||||
nsAutoString dummyString;
|
||||
GetType(dummyString);
|
||||
|
||||
ErrorResult error;
|
||||
GetSize(error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
}
|
||||
|
||||
mImmutable = !aMutable;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* static */ uint64_t
|
||||
BaseBlobImpl::NextSerialNumber()
|
||||
{
|
||||
static Atomic<uint64_t> nextSerialNumber;
|
||||
return nextSerialNumber++;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,191 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_BaseBlobImpl_h
|
||||
#define mozilla_dom_BaseBlobImpl_h
|
||||
|
||||
#include "mozilla/dom/BlobImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class BaseBlobImpl : public BlobImpl
|
||||
{
|
||||
public:
|
||||
BaseBlobImpl(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength, int64_t aLastModifiedDate)
|
||||
: mIsFile(true)
|
||||
, mImmutable(false)
|
||||
, mContentType(aContentType)
|
||||
, mName(aName)
|
||||
, mStart(0)
|
||||
, mLength(aLength)
|
||||
, mLastModificationDate(aLastModifiedDate)
|
||||
, mSerialNumber(NextSerialNumber())
|
||||
{
|
||||
// Ensure non-null mContentType by default
|
||||
mContentType.SetIsVoid(false);
|
||||
}
|
||||
|
||||
BaseBlobImpl(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength)
|
||||
: mIsFile(true)
|
||||
, mImmutable(false)
|
||||
, mContentType(aContentType)
|
||||
, mName(aName)
|
||||
, mStart(0)
|
||||
, mLength(aLength)
|
||||
, mLastModificationDate(INT64_MAX)
|
||||
, mSerialNumber(NextSerialNumber())
|
||||
{
|
||||
// Ensure non-null mContentType by default
|
||||
mContentType.SetIsVoid(false);
|
||||
}
|
||||
|
||||
BaseBlobImpl(const nsAString& aContentType, uint64_t aLength)
|
||||
: mIsFile(false)
|
||||
, mImmutable(false)
|
||||
, mContentType(aContentType)
|
||||
, mStart(0)
|
||||
, mLength(aLength)
|
||||
, mLastModificationDate(INT64_MAX)
|
||||
, mSerialNumber(NextSerialNumber())
|
||||
{
|
||||
// Ensure non-null mContentType by default
|
||||
mContentType.SetIsVoid(false);
|
||||
}
|
||||
|
||||
BaseBlobImpl(const nsAString& aContentType, uint64_t aStart,
|
||||
uint64_t aLength)
|
||||
: mIsFile(false)
|
||||
, mImmutable(false)
|
||||
, mContentType(aContentType)
|
||||
, mStart(aStart)
|
||||
, mLength(aLength)
|
||||
, mLastModificationDate(INT64_MAX)
|
||||
, mSerialNumber(NextSerialNumber())
|
||||
{
|
||||
MOZ_ASSERT(aLength != UINT64_MAX, "Must know length when creating slice");
|
||||
// Ensure non-null mContentType by default
|
||||
mContentType.SetIsVoid(false);
|
||||
}
|
||||
|
||||
virtual void GetName(nsAString& aName) const override;
|
||||
|
||||
virtual void GetDOMPath(nsAString& aName) const override;
|
||||
|
||||
virtual void SetDOMPath(const nsAString& aName) override;
|
||||
|
||||
virtual int64_t GetLastModified(ErrorResult& aRv) override;
|
||||
|
||||
virtual void SetLastModified(int64_t aLastModified) override;
|
||||
|
||||
virtual void GetMozFullPath(nsAString& aName,
|
||||
SystemCallerGuarantee /* unused */,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual void GetMozFullPathInternal(nsAString& aFileName,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual uint64_t GetSize(ErrorResult& aRv) override
|
||||
{
|
||||
return mLength;
|
||||
}
|
||||
|
||||
virtual void GetType(nsAString& aType) override;
|
||||
|
||||
virtual uint64_t GetSerialNumber() const override { return mSerialNumber; }
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual const nsTArray<RefPtr<BlobImpl>>*
|
||||
GetSubBlobImpls() const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
virtual int64_t GetFileId() override;
|
||||
|
||||
virtual nsresult GetSendInfo(nsIInputStream** aBody,
|
||||
uint64_t* aContentLength,
|
||||
nsACString& aContentType,
|
||||
nsACString& aCharset) override;
|
||||
|
||||
virtual nsresult GetMutable(bool* aMutable) const override;
|
||||
|
||||
virtual nsresult SetMutable(bool aMutable) override;
|
||||
|
||||
virtual void
|
||||
SetLazyData(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength, int64_t aLastModifiedDate) override
|
||||
{
|
||||
mName = aName;
|
||||
mContentType = aContentType;
|
||||
mLength = aLength;
|
||||
mLastModificationDate = aLastModifiedDate;
|
||||
mIsFile = !aName.IsVoid();
|
||||
}
|
||||
|
||||
virtual bool IsMemoryFile() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsDateUnknown() const override
|
||||
{
|
||||
return mIsFile && mLastModificationDate == INT64_MAX;
|
||||
}
|
||||
|
||||
virtual bool IsFile() const override
|
||||
{
|
||||
return mIsFile;
|
||||
}
|
||||
|
||||
virtual bool IsSizeUnknown() const override
|
||||
{
|
||||
return mLength == UINT64_MAX;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~BaseBlobImpl() {}
|
||||
|
||||
/**
|
||||
* Returns a new, effectively-unique serial number. This should be used
|
||||
* by implementations to obtain a serial number for GetSerialNumber().
|
||||
* The implementation is thread safe.
|
||||
*/
|
||||
static uint64_t NextSerialNumber();
|
||||
|
||||
bool mIsFile;
|
||||
bool mImmutable;
|
||||
|
||||
nsString mContentType;
|
||||
nsString mName;
|
||||
nsString mPath; // The path relative to a directory chosen by the user
|
||||
|
||||
uint64_t mStart;
|
||||
uint64_t mLength;
|
||||
|
||||
int64_t mLastModificationDate;
|
||||
|
||||
const uint64_t mSerialNumber;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_BaseBlobImpl_h
|
|
@ -0,0 +1,294 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "Blob.h"
|
||||
#include "File.h"
|
||||
#include "MemoryBlobImpl.h"
|
||||
#include "mozilla/dom/BlobBinding.h"
|
||||
#include "MultipartBlobImpl.h"
|
||||
#include "ipc/nsIRemoteBlob.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "TemporaryBlobImpl.h"
|
||||
#include "StreamBlobImpl.h"
|
||||
#include "StringBlobImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(Blob)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Blob)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Blob)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Blob)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Blob)
|
||||
// This class should not receive any nsIRemoteBlob QI!
|
||||
MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsIRemoteBlob)));
|
||||
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMBlob)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIMutable)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(Blob)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(Blob)
|
||||
|
||||
void
|
||||
Blob::MakeValidBlobType(nsAString& aType)
|
||||
{
|
||||
char16_t* iter = aType.BeginWriting();
|
||||
char16_t* end = aType.EndWriting();
|
||||
|
||||
for ( ; iter != end; ++iter) {
|
||||
char16_t c = *iter;
|
||||
if (c < 0x20 || c > 0x7E) {
|
||||
// Non-ASCII char, bail out.
|
||||
aType.Truncate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
*iter = c + ('a' - 'A');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ Blob*
|
||||
Blob::Create(nsISupports* aParent, BlobImpl* aImpl)
|
||||
{
|
||||
MOZ_ASSERT(aImpl);
|
||||
|
||||
return aImpl->IsFile() ? new File(aParent, aImpl)
|
||||
: new Blob(aParent, aImpl);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Blob>
|
||||
Blob::CreateStringBlob(nsISupports* aParent, const nsACString& aData,
|
||||
const nsAString& aContentType)
|
||||
{
|
||||
RefPtr<BlobImpl> blobImpl = StringBlobImpl::Create(aData, aContentType);
|
||||
RefPtr<Blob> blob = Blob::Create(aParent, blobImpl);
|
||||
MOZ_ASSERT(!blob->mImpl->IsFile());
|
||||
return blob.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Blob>
|
||||
Blob::CreateMemoryBlob(nsISupports* aParent, void* aMemoryBuffer,
|
||||
uint64_t aLength, const nsAString& aContentType)
|
||||
{
|
||||
RefPtr<Blob> blob = Blob::Create(aParent,
|
||||
new MemoryBlobImpl(aMemoryBuffer, aLength, aContentType));
|
||||
MOZ_ASSERT(!blob->mImpl->IsFile());
|
||||
return blob.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Blob>
|
||||
Blob::CreateTemporaryBlob(nsISupports* aParent, PRFileDesc* aFD,
|
||||
uint64_t aStartPos, uint64_t aLength,
|
||||
const nsAString& aContentType)
|
||||
{
|
||||
RefPtr<Blob> blob = Blob::Create(aParent,
|
||||
new TemporaryBlobImpl(aFD, aStartPos, aLength, aContentType));
|
||||
MOZ_ASSERT(!blob->mImpl->IsFile());
|
||||
return blob.forget();
|
||||
}
|
||||
|
||||
Blob::Blob(nsISupports* aParent, BlobImpl* aImpl)
|
||||
: mImpl(aImpl)
|
||||
, mParent(aParent)
|
||||
{
|
||||
MOZ_ASSERT(mImpl);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aParent);
|
||||
if (win) {
|
||||
MOZ_ASSERT(win->IsInnerWindow());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Blob::~Blob()
|
||||
{}
|
||||
|
||||
bool
|
||||
Blob::IsFile() const
|
||||
{
|
||||
return mImpl->IsFile();
|
||||
}
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>*
|
||||
Blob::GetSubBlobImpls() const
|
||||
{
|
||||
return mImpl->GetSubBlobImpls();
|
||||
}
|
||||
|
||||
already_AddRefed<File>
|
||||
Blob::ToFile()
|
||||
{
|
||||
if (!mImpl->IsFile()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<File> file;
|
||||
if (HasFileInterface()) {
|
||||
file = static_cast<File*>(this);
|
||||
} else {
|
||||
file = new File(mParent, mImpl);
|
||||
}
|
||||
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<File>
|
||||
Blob::ToFile(const nsAString& aName, ErrorResult& aRv) const
|
||||
{
|
||||
AutoTArray<RefPtr<BlobImpl>, 1> blobImpls({mImpl});
|
||||
|
||||
nsAutoString contentType;
|
||||
mImpl->GetType(contentType);
|
||||
|
||||
RefPtr<MultipartBlobImpl> impl =
|
||||
MultipartBlobImpl::Create(Move(blobImpls), aName, contentType, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<File> file = new File(mParent, impl);
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Blob>
|
||||
Blob::CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<BlobImpl> impl = mImpl->CreateSlice(aStart, aLength,
|
||||
aContentType, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<Blob> blob = Blob::Create(mParent, impl);
|
||||
return blob.forget();
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Blob::GetSize(ErrorResult& aRv)
|
||||
{
|
||||
return mImpl->GetSize(aRv);
|
||||
}
|
||||
|
||||
void
|
||||
Blob::GetType(nsAString &aType)
|
||||
{
|
||||
mImpl->GetType(aType);
|
||||
}
|
||||
|
||||
already_AddRefed<Blob>
|
||||
Blob::Slice(const Optional<int64_t>& aStart,
|
||||
const Optional<int64_t>& aEnd,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<BlobImpl> impl =
|
||||
mImpl->Slice(aStart, aEnd, aContentType, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<Blob> blob = Blob::Create(mParent, impl);
|
||||
return blob.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Blob::GetSendInfo(nsIInputStream** aBody,
|
||||
uint64_t* aContentLength,
|
||||
nsACString& aContentType,
|
||||
nsACString& aCharset)
|
||||
{
|
||||
return mImpl->GetSendInfo(aBody, aContentLength, aContentType, aCharset);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Blob::GetMutable(bool* aMutable)
|
||||
{
|
||||
return mImpl->GetMutable(aMutable);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Blob::SetMutable(bool aMutable)
|
||||
{
|
||||
return mImpl->SetMutable(aMutable);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
Blob::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return BlobBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Blob>
|
||||
Blob::Constructor(const GlobalObject& aGlobal,
|
||||
const Optional<Sequence<BlobPart>>& aData,
|
||||
const BlobPropertyBag& aBag,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl();
|
||||
|
||||
if (aData.WasPassed()) {
|
||||
nsAutoString type(aBag.mType);
|
||||
MakeValidBlobType(type);
|
||||
impl->InitializeBlob(aGlobal.Context(), aData.Value(), type,
|
||||
aBag.mEndings == EndingTypes::Native, aRv);
|
||||
} else {
|
||||
impl->InitializeBlob(aRv);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!impl->IsFile());
|
||||
|
||||
RefPtr<Blob> blob = Blob::Create(aGlobal.GetAsSupports(), impl);
|
||||
return blob.forget();
|
||||
}
|
||||
|
||||
int64_t
|
||||
Blob::GetFileId()
|
||||
{
|
||||
return mImpl->GetFileId();
|
||||
}
|
||||
|
||||
bool
|
||||
Blob::IsMemoryFile() const
|
||||
{
|
||||
return mImpl->IsMemoryFile();
|
||||
}
|
||||
|
||||
void
|
||||
Blob::GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv)
|
||||
{
|
||||
mImpl->GetInternalStream(aStream, aRv);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,153 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_Blob_h
|
||||
#define mozilla_dom_Blob_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/BlobImpl.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDOMBlob.h"
|
||||
#include "nsIMutable.h"
|
||||
#include "nsIXMLHttpRequest.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
class nsIInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct BlobPropertyBag;
|
||||
class File;
|
||||
class OwningArrayBufferViewOrArrayBufferOrBlobOrUSVString;
|
||||
|
||||
class Blob : public nsIDOMBlob
|
||||
, public nsIXHRSendable
|
||||
, public nsIMutable
|
||||
, public nsSupportsWeakReference
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIDOMBLOB
|
||||
NS_DECL_NSIXHRSENDABLE
|
||||
NS_DECL_NSIMUTABLE
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Blob, nsIDOMBlob)
|
||||
|
||||
typedef OwningArrayBufferViewOrArrayBufferOrBlobOrUSVString BlobPart;
|
||||
|
||||
// This creates a Blob or a File based on the type of BlobImpl.
|
||||
static Blob*
|
||||
Create(nsISupports* aParent, BlobImpl* aImpl);
|
||||
|
||||
static already_AddRefed<Blob>
|
||||
CreateStringBlob(nsISupports* aParent, const nsACString& aData,
|
||||
const nsAString& aContentType);
|
||||
|
||||
// The returned Blob takes ownership of aMemoryBuffer. aMemoryBuffer will be
|
||||
// freed by free so it must be allocated by malloc or something
|
||||
// compatible with it.
|
||||
static already_AddRefed<Blob>
|
||||
CreateMemoryBlob(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
|
||||
const nsAString& aContentType);
|
||||
|
||||
static already_AddRefed<Blob>
|
||||
CreateTemporaryBlob(nsISupports* aParent, PRFileDesc* aFD,
|
||||
uint64_t aStartPos, uint64_t aLength,
|
||||
const nsAString& aContentType);
|
||||
|
||||
BlobImpl* Impl() const
|
||||
{
|
||||
return mImpl;
|
||||
}
|
||||
|
||||
bool IsFile() const;
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>* GetSubBlobImpls() const;
|
||||
|
||||
// This method returns null if this Blob is not a File; it returns
|
||||
// the same object in case this Blob already implements the File interface;
|
||||
// otherwise it returns a new File object with the same BlobImpl.
|
||||
already_AddRefed<File> ToFile();
|
||||
|
||||
// This method creates a new File object with the given name and the same
|
||||
// BlobImpl.
|
||||
already_AddRefed<File> ToFile(const nsAString& aName,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
already_AddRefed<Blob>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv);
|
||||
|
||||
int64_t
|
||||
GetFileId();
|
||||
|
||||
// A utility function that enforces the spec constraints on the type of a
|
||||
// blob: no codepoints outside the ASCII range (otherwise type becomes empty)
|
||||
// and lowercase ASCII only. We can't just use our existing nsContentUtils
|
||||
// ASCII-related helpers because we need the "outside ASCII range" check, and
|
||||
// we can't use NS_IsAscii because its definition of "ASCII" (chars all <=
|
||||
// 0x7E) differs from the file API definition (which excludes control chars).
|
||||
static void
|
||||
MakeValidBlobType(nsAString& aType);
|
||||
|
||||
// WebIDL methods
|
||||
nsISupports* GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
bool
|
||||
IsMemoryFile() const;
|
||||
|
||||
// Blob constructor
|
||||
static already_AddRefed<Blob>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const Optional<Sequence<BlobPart>>& aData,
|
||||
const BlobPropertyBag& aBag,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
uint64_t GetSize(ErrorResult& aRv);
|
||||
|
||||
void GetType(nsAString& aType);
|
||||
|
||||
already_AddRefed<Blob> Slice(const Optional<int64_t>& aStart,
|
||||
const Optional<int64_t>& aEnd,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
// File constructor should never be used directly. Use Blob::Create instead.
|
||||
Blob(nsISupports* aParent, BlobImpl* aImpl);
|
||||
virtual ~Blob();
|
||||
|
||||
virtual bool HasFileInterface() const { return false; }
|
||||
|
||||
// The member is the real backend implementation of this File/Blob.
|
||||
// It's thread-safe and not CC-able and it's the only element that is moved
|
||||
// between threads.
|
||||
// Note: we should not store any other state in this class!
|
||||
RefPtr<BlobImpl> mImpl;
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_Blob_h
|
|
@ -0,0 +1,76 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "BlobImpl.h"
|
||||
#include "File.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// Makes sure that aStart and aEnd is less then or equal to aSize and greater
|
||||
// than 0
|
||||
static void
|
||||
ParseSize(int64_t aSize, int64_t& aStart, int64_t& aEnd)
|
||||
{
|
||||
CheckedInt64 newStartOffset = aStart;
|
||||
if (aStart < -aSize) {
|
||||
newStartOffset = 0;
|
||||
}
|
||||
else if (aStart < 0) {
|
||||
newStartOffset += aSize;
|
||||
}
|
||||
else if (aStart > aSize) {
|
||||
newStartOffset = aSize;
|
||||
}
|
||||
|
||||
CheckedInt64 newEndOffset = aEnd;
|
||||
if (aEnd < -aSize) {
|
||||
newEndOffset = 0;
|
||||
}
|
||||
else if (aEnd < 0) {
|
||||
newEndOffset += aSize;
|
||||
}
|
||||
else if (aEnd > aSize) {
|
||||
newEndOffset = aSize;
|
||||
}
|
||||
|
||||
if (!newStartOffset.isValid() || !newEndOffset.isValid() ||
|
||||
newStartOffset.value() >= newEndOffset.value()) {
|
||||
aStart = aEnd = 0;
|
||||
}
|
||||
else {
|
||||
aStart = newStartOffset.value();
|
||||
aEnd = newEndOffset.value();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<BlobImpl>
|
||||
BlobImpl::Slice(const Optional<int64_t>& aStart,
|
||||
const Optional<int64_t>& aEnd,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// Truncate aStart and aEnd so that we stay within this file.
|
||||
uint64_t thisLength = GetSize(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int64_t start = aStart.WasPassed() ? aStart.Value() : 0;
|
||||
int64_t end = aEnd.WasPassed() ? aEnd.Value() : (int64_t)thisLength;
|
||||
|
||||
ParseSize((int64_t)thisLength, start, end);
|
||||
|
||||
nsAutoString type(aContentType);
|
||||
Blob::MakeValidBlobType(type);
|
||||
return CreateSlice((uint64_t)start, (uint64_t)(end - start), type, aRv);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(BlobImpl, BlobImpl)
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,122 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_BlobImpl_h
|
||||
#define mozilla_dom_BlobImpl_h
|
||||
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#define BLOBIMPL_IID \
|
||||
{ 0xbccb3275, 0x6778, 0x4ac5, \
|
||||
{ 0xaf, 0x03, 0x90, 0xed, 0x37, 0xad, 0xdf, 0x5d } }
|
||||
|
||||
class nsIInputStream;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// This is the abstract class for any File backend. It must be nsISupports
|
||||
// because this class must be ref-counted and it has to work with IPC.
|
||||
class BlobImpl : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(BLOBIMPL_IID)
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
BlobImpl() {}
|
||||
|
||||
virtual void GetName(nsAString& aName) const = 0;
|
||||
|
||||
virtual void GetDOMPath(nsAString& aName) const = 0;
|
||||
|
||||
virtual void SetDOMPath(const nsAString& aName) = 0;
|
||||
|
||||
virtual int64_t GetLastModified(ErrorResult& aRv) = 0;
|
||||
|
||||
virtual void SetLastModified(int64_t aLastModified) = 0;
|
||||
|
||||
virtual void GetMozFullPath(nsAString& aName,
|
||||
SystemCallerGuarantee /* unused */,
|
||||
ErrorResult& aRv) const = 0;
|
||||
|
||||
virtual void GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) const = 0;
|
||||
|
||||
virtual uint64_t GetSize(ErrorResult& aRv) = 0;
|
||||
|
||||
virtual void GetType(nsAString& aType) = 0;
|
||||
|
||||
/**
|
||||
* An effectively-unique serial number identifying this instance of FileImpl.
|
||||
*
|
||||
* Implementations should obtain a serial number from
|
||||
* FileImplBase::NextSerialNumber().
|
||||
*/
|
||||
virtual uint64_t GetSerialNumber() const = 0;
|
||||
|
||||
already_AddRefed<BlobImpl>
|
||||
Slice(const Optional<int64_t>& aStart, const Optional<int64_t>& aEnd,
|
||||
const nsAString& aContentType, ErrorResult& aRv);
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) = 0;
|
||||
|
||||
virtual const nsTArray<RefPtr<BlobImpl>>*
|
||||
GetSubBlobImpls() const = 0;
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) = 0;
|
||||
|
||||
virtual int64_t GetFileId() = 0;
|
||||
|
||||
virtual nsresult GetSendInfo(nsIInputStream** aBody,
|
||||
uint64_t* aContentLength,
|
||||
nsACString& aContentType,
|
||||
nsACString& aCharset) = 0;
|
||||
|
||||
virtual nsresult GetMutable(bool* aMutable) const = 0;
|
||||
|
||||
virtual nsresult SetMutable(bool aMutable) = 0;
|
||||
|
||||
virtual void SetLazyData(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aLastModifiedDate) = 0;
|
||||
|
||||
virtual bool IsMemoryFile() const = 0;
|
||||
|
||||
virtual bool IsSizeUnknown() const = 0;
|
||||
|
||||
virtual bool IsDateUnknown() const = 0;
|
||||
|
||||
virtual bool IsFile() const = 0;
|
||||
|
||||
// Returns true if the BlobImpl is backed by an nsIFile and the underlying
|
||||
// file is a directory.
|
||||
virtual bool IsDirectory() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// True if this implementation can be sent to other threads.
|
||||
virtual bool MayBeClonedToOtherThreads() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~BlobImpl() {}
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(BlobImpl, BLOBIMPL_IID)
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_BlobImpl_h
|
|
@ -7,6 +7,7 @@
|
|||
#include "mozilla/dom/BlobSet.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "MemoryBlobImpl.h"
|
||||
#include "MultipartBlobImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -27,7 +28,7 @@ BlobSet::AppendVoidPtr(const void* aData, uint32_t aLength)
|
|||
|
||||
memcpy((char*)data, aData, aLength);
|
||||
|
||||
RefPtr<BlobImpl> blobImpl = new BlobImplMemory(data, aLength, EmptyString());
|
||||
RefPtr<BlobImpl> blobImpl = new MemoryBlobImpl(data, aLength, EmptyString());
|
||||
mBlobImpls.AppendElement(blobImpl);
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "EmptyBlobImpl.h"
|
||||
#include "nsStringStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(EmptyBlobImpl, BlobImpl)
|
||||
|
||||
already_AddRefed<BlobImpl>
|
||||
EmptyBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!aStart && !aLength);
|
||||
RefPtr<BlobImpl> impl = new EmptyBlobImpl(aContentType);
|
||||
|
||||
DebugOnly<bool> isMutable;
|
||||
MOZ_ASSERT(NS_SUCCEEDED(impl->GetMutable(&isMutable)));
|
||||
MOZ_ASSERT(!isMutable);
|
||||
|
||||
return impl.forget();
|
||||
}
|
||||
|
||||
void
|
||||
EmptyBlobImpl::GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(!aStream)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = NS_NewCStringInputStream(aStream, EmptyCString());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_EmptyBlobImpl_h
|
||||
#define mozilla_dom_EmptyBlobImpl_h
|
||||
|
||||
#include "BaseBlobImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class EmptyBlobImpl final : public BaseBlobImpl
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
explicit EmptyBlobImpl(const nsAString& aContentType)
|
||||
: BaseBlobImpl(aContentType, 0 /* aLength */)
|
||||
{
|
||||
mImmutable = true;
|
||||
}
|
||||
|
||||
EmptyBlobImpl(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
int64_t aLastModifiedDate)
|
||||
: BaseBlobImpl(aName, aContentType, 0, aLastModifiedDate)
|
||||
{
|
||||
mImmutable = true;
|
||||
}
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override;
|
||||
|
||||
virtual bool IsMemoryFile() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
~EmptyBlobImpl() {}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_EmptyBlobImpl_h
|
1171
dom/file/File.cpp
1171
dom/file/File.cpp
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
750
dom/file/File.h
750
dom/file/File.h
|
@ -7,154 +7,18 @@
|
|||
#ifndef mozilla_dom_File_h
|
||||
#define mozilla_dom_File_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/GuardObjects.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/Blob.h"
|
||||
#include "mozilla/dom/Date.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDOMBlob.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsIMutable.h"
|
||||
#include "nsIXMLHttpRequest.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTemporaryFileInputStream.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
class nsIFile;
|
||||
class nsIInputStream;
|
||||
|
||||
#define BLOBIMPL_IID \
|
||||
{ 0xbccb3275, 0x6778, 0x4ac5, \
|
||||
{ 0xaf, 0x03, 0x90, 0xed, 0x37, 0xad, 0xdf, 0x5d } }
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct BlobPropertyBag;
|
||||
struct ChromeFilePropertyBag;
|
||||
struct FilePropertyBag;
|
||||
class BlobImpl;
|
||||
class File;
|
||||
class OwningArrayBufferViewOrArrayBufferOrBlobOrUSVString;
|
||||
class Promise;
|
||||
|
||||
class Blob : public nsIDOMBlob
|
||||
, public nsIXHRSendable
|
||||
, public nsIMutable
|
||||
, public nsSupportsWeakReference
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSIDOMBLOB
|
||||
NS_DECL_NSIXHRSENDABLE
|
||||
NS_DECL_NSIMUTABLE
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Blob, nsIDOMBlob)
|
||||
|
||||
typedef OwningArrayBufferViewOrArrayBufferOrBlobOrUSVString BlobPart;
|
||||
|
||||
// This creates a Blob or a File based on the type of BlobImpl.
|
||||
static Blob*
|
||||
Create(nsISupports* aParent, BlobImpl* aImpl);
|
||||
|
||||
static already_AddRefed<Blob>
|
||||
CreateStringBlob(nsISupports* aParent, const nsACString& aData,
|
||||
const nsAString& aContentType);
|
||||
|
||||
// The returned Blob takes ownership of aMemoryBuffer. aMemoryBuffer will be
|
||||
// freed by free so it must be allocated by malloc or something
|
||||
// compatible with it.
|
||||
static already_AddRefed<Blob>
|
||||
CreateMemoryBlob(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
|
||||
const nsAString& aContentType);
|
||||
|
||||
static already_AddRefed<Blob>
|
||||
CreateTemporaryBlob(nsISupports* aParent, PRFileDesc* aFD,
|
||||
uint64_t aStartPos, uint64_t aLength,
|
||||
const nsAString& aContentType);
|
||||
|
||||
BlobImpl* Impl() const
|
||||
{
|
||||
return mImpl;
|
||||
}
|
||||
|
||||
bool IsFile() const;
|
||||
|
||||
const nsTArray<RefPtr<BlobImpl>>* GetSubBlobImpls() const;
|
||||
|
||||
// This method returns null if this Blob is not a File; it returns
|
||||
// the same object in case this Blob already implements the File interface;
|
||||
// otherwise it returns a new File object with the same BlobImpl.
|
||||
already_AddRefed<File> ToFile();
|
||||
|
||||
// This method creates a new File object with the given name and the same
|
||||
// BlobImpl.
|
||||
already_AddRefed<File> ToFile(const nsAString& aName,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
already_AddRefed<Blob>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv);
|
||||
|
||||
int64_t
|
||||
GetFileId();
|
||||
|
||||
// WebIDL methods
|
||||
nsISupports* GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
bool
|
||||
IsMemoryFile() const;
|
||||
|
||||
// Blob constructor
|
||||
static already_AddRefed<Blob>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const Optional<Sequence<BlobPart>>& aData,
|
||||
const BlobPropertyBag& aBag,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
uint64_t GetSize(ErrorResult& aRv);
|
||||
|
||||
void GetType(nsAString& aType);
|
||||
|
||||
already_AddRefed<Blob> Slice(const Optional<int64_t>& aStart,
|
||||
const Optional<int64_t>& aEnd,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
// File constructor should never be used directly. Use Blob::Create instead.
|
||||
Blob(nsISupports* aParent, BlobImpl* aImpl);
|
||||
virtual ~Blob() {};
|
||||
|
||||
virtual bool HasFileInterface() const { return false; }
|
||||
|
||||
// The member is the real backend implementation of this File/Blob.
|
||||
// It's thread-safe and not CC-able and it's the only element that is moved
|
||||
// between threads.
|
||||
// Note: we should not store any other state in this class!
|
||||
RefPtr<BlobImpl> mImpl;
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
};
|
||||
|
||||
class File final : public Blob
|
||||
{
|
||||
friend class Blob;
|
||||
|
@ -240,617 +104,7 @@ private:
|
|||
// File constructor should never be used directly. Use Blob::Create or
|
||||
// File::Create.
|
||||
File(nsISupports* aParent, BlobImpl* aImpl);
|
||||
~File() {};
|
||||
};
|
||||
|
||||
// This is the abstract class for any File backend. It must be nsISupports
|
||||
// because this class must be ref-counted and it has to work with IPC.
|
||||
class BlobImpl : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(BLOBIMPL_IID)
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
BlobImpl() {}
|
||||
|
||||
virtual void GetName(nsAString& aName) const = 0;
|
||||
|
||||
virtual void GetDOMPath(nsAString& aName) const = 0;
|
||||
|
||||
virtual void SetDOMPath(const nsAString& aName) = 0;
|
||||
|
||||
virtual int64_t GetLastModified(ErrorResult& aRv) = 0;
|
||||
|
||||
virtual void SetLastModified(int64_t aLastModified) = 0;
|
||||
|
||||
virtual void GetMozFullPath(nsAString& aName,
|
||||
SystemCallerGuarantee /* unused */,
|
||||
ErrorResult& aRv) const = 0;
|
||||
|
||||
virtual void GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) const = 0;
|
||||
|
||||
virtual uint64_t GetSize(ErrorResult& aRv) = 0;
|
||||
|
||||
virtual void GetType(nsAString& aType) = 0;
|
||||
|
||||
/**
|
||||
* An effectively-unique serial number identifying this instance of FileImpl.
|
||||
*
|
||||
* Implementations should obtain a serial number from
|
||||
* FileImplBase::NextSerialNumber().
|
||||
*/
|
||||
virtual uint64_t GetSerialNumber() const = 0;
|
||||
|
||||
already_AddRefed<BlobImpl>
|
||||
Slice(const Optional<int64_t>& aStart, const Optional<int64_t>& aEnd,
|
||||
const nsAString& aContentType, ErrorResult& aRv);
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) = 0;
|
||||
|
||||
virtual const nsTArray<RefPtr<BlobImpl>>*
|
||||
GetSubBlobImpls() const = 0;
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) = 0;
|
||||
|
||||
virtual int64_t GetFileId() = 0;
|
||||
|
||||
virtual nsresult GetSendInfo(nsIInputStream** aBody,
|
||||
uint64_t* aContentLength,
|
||||
nsACString& aContentType,
|
||||
nsACString& aCharset) = 0;
|
||||
|
||||
virtual nsresult GetMutable(bool* aMutable) const = 0;
|
||||
|
||||
virtual nsresult SetMutable(bool aMutable) = 0;
|
||||
|
||||
virtual void SetLazyData(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength,
|
||||
int64_t aLastModifiedDate) = 0;
|
||||
|
||||
virtual bool IsMemoryFile() const = 0;
|
||||
|
||||
virtual bool IsSizeUnknown() const = 0;
|
||||
|
||||
virtual bool IsDateUnknown() const = 0;
|
||||
|
||||
virtual bool IsFile() const = 0;
|
||||
|
||||
// Returns true if the BlobImpl is backed by an nsIFile and the underlying
|
||||
// file is a directory.
|
||||
virtual bool IsDirectory() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// True if this implementation can be sent to other threads.
|
||||
virtual bool MayBeClonedToOtherThreads() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~BlobImpl() {}
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(BlobImpl, BLOBIMPL_IID)
|
||||
|
||||
class BlobImplBase : public BlobImpl
|
||||
{
|
||||
public:
|
||||
BlobImplBase(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength, int64_t aLastModifiedDate)
|
||||
: mIsFile(true)
|
||||
, mImmutable(false)
|
||||
, mContentType(aContentType)
|
||||
, mName(aName)
|
||||
, mStart(0)
|
||||
, mLength(aLength)
|
||||
, mLastModificationDate(aLastModifiedDate)
|
||||
, mSerialNumber(NextSerialNumber())
|
||||
{
|
||||
// Ensure non-null mContentType by default
|
||||
mContentType.SetIsVoid(false);
|
||||
}
|
||||
|
||||
BlobImplBase(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength)
|
||||
: mIsFile(true)
|
||||
, mImmutable(false)
|
||||
, mContentType(aContentType)
|
||||
, mName(aName)
|
||||
, mStart(0)
|
||||
, mLength(aLength)
|
||||
, mLastModificationDate(INT64_MAX)
|
||||
, mSerialNumber(NextSerialNumber())
|
||||
{
|
||||
// Ensure non-null mContentType by default
|
||||
mContentType.SetIsVoid(false);
|
||||
}
|
||||
|
||||
BlobImplBase(const nsAString& aContentType, uint64_t aLength)
|
||||
: mIsFile(false)
|
||||
, mImmutable(false)
|
||||
, mContentType(aContentType)
|
||||
, mStart(0)
|
||||
, mLength(aLength)
|
||||
, mLastModificationDate(INT64_MAX)
|
||||
, mSerialNumber(NextSerialNumber())
|
||||
{
|
||||
// Ensure non-null mContentType by default
|
||||
mContentType.SetIsVoid(false);
|
||||
}
|
||||
|
||||
BlobImplBase(const nsAString& aContentType, uint64_t aStart,
|
||||
uint64_t aLength)
|
||||
: mIsFile(false)
|
||||
, mImmutable(false)
|
||||
, mContentType(aContentType)
|
||||
, mStart(aStart)
|
||||
, mLength(aLength)
|
||||
, mLastModificationDate(INT64_MAX)
|
||||
, mSerialNumber(NextSerialNumber())
|
||||
{
|
||||
MOZ_ASSERT(aLength != UINT64_MAX, "Must know length when creating slice");
|
||||
// Ensure non-null mContentType by default
|
||||
mContentType.SetIsVoid(false);
|
||||
}
|
||||
|
||||
virtual void GetName(nsAString& aName) const override;
|
||||
|
||||
virtual void GetDOMPath(nsAString& aName) const override;
|
||||
|
||||
virtual void SetDOMPath(const nsAString& aName) override;
|
||||
|
||||
virtual int64_t GetLastModified(ErrorResult& aRv) override;
|
||||
|
||||
virtual void SetLastModified(int64_t aLastModified) override;
|
||||
|
||||
virtual void GetMozFullPath(nsAString& aName,
|
||||
SystemCallerGuarantee /* unused */,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual void GetMozFullPathInternal(nsAString& aFileName,
|
||||
ErrorResult& aRv) const override;
|
||||
|
||||
virtual uint64_t GetSize(ErrorResult& aRv) override
|
||||
{
|
||||
return mLength;
|
||||
}
|
||||
|
||||
virtual void GetType(nsAString& aType) override;
|
||||
|
||||
virtual uint64_t GetSerialNumber() const override { return mSerialNumber; }
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual const nsTArray<RefPtr<BlobImpl>>*
|
||||
GetSubBlobImpls() const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
virtual int64_t GetFileId() override;
|
||||
|
||||
virtual nsresult GetSendInfo(nsIInputStream** aBody,
|
||||
uint64_t* aContentLength,
|
||||
nsACString& aContentType,
|
||||
nsACString& aCharset) override;
|
||||
|
||||
virtual nsresult GetMutable(bool* aMutable) const override;
|
||||
|
||||
virtual nsresult SetMutable(bool aMutable) override;
|
||||
|
||||
virtual void
|
||||
SetLazyData(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength, int64_t aLastModifiedDate) override
|
||||
{
|
||||
mName = aName;
|
||||
mContentType = aContentType;
|
||||
mLength = aLength;
|
||||
mLastModificationDate = aLastModifiedDate;
|
||||
mIsFile = !aName.IsVoid();
|
||||
}
|
||||
|
||||
virtual bool IsMemoryFile() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsDateUnknown() const override
|
||||
{
|
||||
return mIsFile && mLastModificationDate == INT64_MAX;
|
||||
}
|
||||
|
||||
virtual bool IsFile() const override
|
||||
{
|
||||
return mIsFile;
|
||||
}
|
||||
|
||||
virtual bool IsSizeUnknown() const override
|
||||
{
|
||||
return mLength == UINT64_MAX;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~BlobImplBase() {}
|
||||
|
||||
/**
|
||||
* Returns a new, effectively-unique serial number. This should be used
|
||||
* by implementations to obtain a serial number for GetSerialNumber().
|
||||
* The implementation is thread safe.
|
||||
*/
|
||||
static uint64_t NextSerialNumber();
|
||||
|
||||
bool mIsFile;
|
||||
bool mImmutable;
|
||||
|
||||
nsString mContentType;
|
||||
nsString mName;
|
||||
nsString mPath; // The path relative to a directory chosen by the user
|
||||
|
||||
uint64_t mStart;
|
||||
uint64_t mLength;
|
||||
|
||||
int64_t mLastModificationDate;
|
||||
|
||||
const uint64_t mSerialNumber;
|
||||
};
|
||||
|
||||
class BlobImplString final : public BlobImplBase
|
||||
, public nsIMemoryReporter
|
||||
{
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIMEMORYREPORTER
|
||||
|
||||
static already_AddRefed<BlobImplString>
|
||||
Create(const nsACString& aData, const nsAString& aContentType);
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override;
|
||||
|
||||
private:
|
||||
BlobImplString(const nsACString& aData, const nsAString& aContentType);
|
||||
|
||||
~BlobImplString();
|
||||
|
||||
nsCString mData;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class may be used off the main thread, and in particular, its
|
||||
* constructor and destructor may not run on the same thread. Be careful!
|
||||
*/
|
||||
class BlobImplMemory final : public BlobImplBase
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
BlobImplMemory(void* aMemoryBuffer, uint64_t aLength, const nsAString& aName,
|
||||
const nsAString& aContentType, int64_t aLastModifiedDate)
|
||||
: BlobImplBase(aName, aContentType, aLength, aLastModifiedDate)
|
||||
, mDataOwner(new DataOwner(aMemoryBuffer, aLength))
|
||||
{
|
||||
MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data");
|
||||
}
|
||||
|
||||
BlobImplMemory(void* aMemoryBuffer, uint64_t aLength,
|
||||
const nsAString& aContentType)
|
||||
: BlobImplBase(aContentType, aLength)
|
||||
, mDataOwner(new DataOwner(aMemoryBuffer, aLength))
|
||||
{
|
||||
MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data");
|
||||
}
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override;
|
||||
|
||||
virtual bool IsMemoryFile() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
class DataOwner final : public mozilla::LinkedListElement<DataOwner>
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataOwner)
|
||||
DataOwner(void* aMemoryBuffer, uint64_t aLength)
|
||||
: mData(aMemoryBuffer)
|
||||
, mLength(aLength)
|
||||
{
|
||||
mozilla::StaticMutexAutoLock lock(sDataOwnerMutex);
|
||||
|
||||
if (!sDataOwners) {
|
||||
sDataOwners = new mozilla::LinkedList<DataOwner>();
|
||||
EnsureMemoryReporterRegistered();
|
||||
}
|
||||
sDataOwners->insertBack(this);
|
||||
}
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
~DataOwner() {
|
||||
mozilla::StaticMutexAutoLock lock(sDataOwnerMutex);
|
||||
|
||||
remove();
|
||||
if (sDataOwners->isEmpty()) {
|
||||
// Free the linked list if it's empty.
|
||||
sDataOwners = nullptr;
|
||||
}
|
||||
|
||||
free(mData);
|
||||
}
|
||||
|
||||
public:
|
||||
static void EnsureMemoryReporterRegistered();
|
||||
|
||||
// sDataOwners and sMemoryReporterRegistered may only be accessed while
|
||||
// holding sDataOwnerMutex! You also must hold the mutex while touching
|
||||
// elements of the linked list that DataOwner inherits from.
|
||||
static mozilla::StaticMutex sDataOwnerMutex;
|
||||
static mozilla::StaticAutoPtr<mozilla::LinkedList<DataOwner> > sDataOwners;
|
||||
static bool sMemoryReporterRegistered;
|
||||
|
||||
void* mData;
|
||||
uint64_t mLength;
|
||||
};
|
||||
|
||||
private:
|
||||
// Create slice
|
||||
BlobImplMemory(const BlobImplMemory* aOther, uint64_t aStart,
|
||||
uint64_t aLength, const nsAString& aContentType)
|
||||
: BlobImplBase(aContentType, aOther->mStart + aStart, aLength)
|
||||
, mDataOwner(aOther->mDataOwner)
|
||||
{
|
||||
MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data");
|
||||
mImmutable = aOther->mImmutable;
|
||||
}
|
||||
|
||||
~BlobImplMemory() {}
|
||||
|
||||
// Used when backed by a memory store
|
||||
RefPtr<DataOwner> mDataOwner;
|
||||
};
|
||||
|
||||
class BlobImplTemporaryBlob final : public BlobImplBase
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
BlobImplTemporaryBlob(PRFileDesc* aFD, uint64_t aStartPos,
|
||||
uint64_t aLength, const nsAString& aContentType)
|
||||
: BlobImplBase(aContentType, aLength)
|
||||
, mStartPos(aStartPos)
|
||||
{
|
||||
mFileDescOwner = new nsTemporaryFileInputStream::FileDescOwner(aFD);
|
||||
}
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override;
|
||||
|
||||
private:
|
||||
BlobImplTemporaryBlob(const BlobImplTemporaryBlob* aOther,
|
||||
uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType)
|
||||
: BlobImplBase(aContentType, aLength)
|
||||
, mStartPos(aStart)
|
||||
, mFileDescOwner(aOther->mFileDescOwner)
|
||||
{}
|
||||
|
||||
~BlobImplTemporaryBlob() {}
|
||||
|
||||
uint64_t mStartPos;
|
||||
RefPtr<nsTemporaryFileInputStream::FileDescOwner> mFileDescOwner;
|
||||
};
|
||||
|
||||
class BlobImplFile : public BlobImplBase
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// Create as a file
|
||||
explicit BlobImplFile(nsIFile* aFile)
|
||||
: BlobImplBase(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
|
||||
, mFile(aFile)
|
||||
, mWholeFile(true)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
// Lazily get the content type and size
|
||||
mContentType.SetIsVoid(true);
|
||||
mFile->GetLeafName(mName);
|
||||
}
|
||||
|
||||
// Create as a file
|
||||
BlobImplFile(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength, nsIFile* aFile)
|
||||
: BlobImplBase(aName, aContentType, aLength, UINT64_MAX)
|
||||
, mFile(aFile)
|
||||
, mWholeFile(true)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
}
|
||||
|
||||
BlobImplFile(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength, nsIFile* aFile,
|
||||
int64_t aLastModificationDate)
|
||||
: BlobImplBase(aName, aContentType, aLength, aLastModificationDate)
|
||||
, mFile(aFile)
|
||||
, mWholeFile(true)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
}
|
||||
|
||||
// Create as a file with custom name
|
||||
BlobImplFile(nsIFile* aFile, const nsAString& aName,
|
||||
const nsAString& aContentType)
|
||||
: BlobImplBase(aName, aContentType, UINT64_MAX, INT64_MAX)
|
||||
, mFile(aFile)
|
||||
, mWholeFile(true)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
if (aContentType.IsEmpty()) {
|
||||
// Lazily get the content type and size
|
||||
mContentType.SetIsVoid(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Overrides
|
||||
virtual uint64_t GetSize(ErrorResult& aRv) override;
|
||||
virtual void GetType(nsAString& aType) override;
|
||||
virtual int64_t GetLastModified(ErrorResult& aRv) override;
|
||||
virtual void SetLastModified(int64_t aLastModified) override;
|
||||
virtual void GetMozFullPathInternal(nsAString& aFullPath,
|
||||
ErrorResult& aRv) const override;
|
||||
virtual void GetInternalStream(nsIInputStream** aInputStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual bool IsDirectory() const override;
|
||||
|
||||
// We always have size and date for this kind of blob.
|
||||
virtual bool IsSizeUnknown() const override { return false; }
|
||||
virtual bool IsDateUnknown() const override { return false; }
|
||||
|
||||
protected:
|
||||
virtual ~BlobImplFile() = default;
|
||||
|
||||
private:
|
||||
// Create slice
|
||||
BlobImplFile(const BlobImplFile* aOther, uint64_t aStart,
|
||||
uint64_t aLength, const nsAString& aContentType)
|
||||
: BlobImplBase(aContentType, aOther->mStart + aStart, aLength)
|
||||
, mFile(aOther->mFile)
|
||||
, mWholeFile(false)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
mImmutable = aOther->mImmutable;
|
||||
}
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override;
|
||||
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
bool mWholeFile;
|
||||
};
|
||||
|
||||
class EmptyBlobImpl final : public BlobImplBase
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
explicit EmptyBlobImpl(const nsAString& aContentType)
|
||||
: BlobImplBase(aContentType, 0 /* aLength */)
|
||||
{
|
||||
mImmutable = true;
|
||||
}
|
||||
|
||||
EmptyBlobImpl(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
int64_t aLastModifiedDate)
|
||||
: BlobImplBase(aName, aContentType, 0, aLastModifiedDate)
|
||||
{
|
||||
mImmutable = true;
|
||||
}
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override;
|
||||
|
||||
virtual bool IsMemoryFile() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
~EmptyBlobImpl() {}
|
||||
};
|
||||
|
||||
class BlobImplStream final : public BlobImplBase
|
||||
, public nsIMemoryReporter
|
||||
{
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIMEMORYREPORTER
|
||||
|
||||
static already_AddRefed<BlobImplStream>
|
||||
Create(nsIInputStream* aInputStream,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength);
|
||||
|
||||
static already_AddRefed<BlobImplStream>
|
||||
Create(nsIInputStream* aInputStream,
|
||||
const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
int64_t aLastModifiedDate,
|
||||
uint64_t aLength);
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override;
|
||||
|
||||
virtual bool IsMemoryFile() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
BlobImplStream(nsIInputStream* aInputStream,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength);
|
||||
|
||||
BlobImplStream(nsIInputStream* aInputStream,
|
||||
const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
int64_t aLastModifiedDate,
|
||||
uint64_t aLength);
|
||||
|
||||
BlobImplStream(BlobImplStream* aOther,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aStart,
|
||||
uint64_t aLength);
|
||||
|
||||
~BlobImplStream();
|
||||
|
||||
void MaybeRegisterMemoryReporter();
|
||||
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
~File();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "FileBlobImpl.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/dom/WorkerRunnable.h"
|
||||
#include "nsCExternalHandlerService.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "SlicedInputStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace workers;
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(FileBlobImpl, BlobImpl)
|
||||
|
||||
FileBlobImpl::FileBlobImpl(nsIFile* aFile)
|
||||
: BaseBlobImpl(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
|
||||
, mFile(aFile)
|
||||
, mWholeFile(true)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
// Lazily get the content type and size
|
||||
mContentType.SetIsVoid(true);
|
||||
mFile->GetLeafName(mName);
|
||||
}
|
||||
|
||||
FileBlobImpl::FileBlobImpl(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength, nsIFile* aFile)
|
||||
: BaseBlobImpl(aName, aContentType, aLength, UINT64_MAX)
|
||||
, mFile(aFile)
|
||||
, mWholeFile(true)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
}
|
||||
|
||||
FileBlobImpl::FileBlobImpl(const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength, nsIFile* aFile,
|
||||
int64_t aLastModificationDate)
|
||||
: BaseBlobImpl(aName, aContentType, aLength, aLastModificationDate)
|
||||
, mFile(aFile)
|
||||
, mWholeFile(true)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
}
|
||||
|
||||
FileBlobImpl::FileBlobImpl(nsIFile* aFile, const nsAString& aName,
|
||||
const nsAString& aContentType)
|
||||
: BaseBlobImpl(aName, aContentType, UINT64_MAX, INT64_MAX)
|
||||
, mFile(aFile)
|
||||
, mWholeFile(true)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
if (aContentType.IsEmpty()) {
|
||||
// Lazily get the content type and size
|
||||
mContentType.SetIsVoid(true);
|
||||
}
|
||||
}
|
||||
|
||||
FileBlobImpl::FileBlobImpl(const FileBlobImpl* aOther, uint64_t aStart,
|
||||
uint64_t aLength, const nsAString& aContentType)
|
||||
: BaseBlobImpl(aContentType, aOther->mStart + aStart, aLength)
|
||||
, mFile(aOther->mFile)
|
||||
, mWholeFile(false)
|
||||
{
|
||||
MOZ_ASSERT(mFile, "must have file");
|
||||
mImmutable = aOther->mImmutable;
|
||||
}
|
||||
|
||||
already_AddRefed<BlobImpl>
|
||||
FileBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<BlobImpl> impl =
|
||||
new FileBlobImpl(this, aStart, aLength, aContentType);
|
||||
return impl.forget();
|
||||
}
|
||||
|
||||
void
|
||||
FileBlobImpl::GetMozFullPathInternal(nsAString& aFilename,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(mIsFile, "Should only be called on files");
|
||||
aRv = mFile->GetPath(aFilename);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
FileBlobImpl::GetSize(ErrorResult& aRv)
|
||||
{
|
||||
if (BaseBlobImpl::IsSizeUnknown()) {
|
||||
MOZ_ASSERT(mWholeFile,
|
||||
"Should only use lazy size when using the whole file");
|
||||
int64_t fileSize;
|
||||
aRv = mFile->GetFileSize(&fileSize);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fileSize < 0) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mLength = fileSize;
|
||||
}
|
||||
|
||||
return mLength;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class GetTypeRunnable final : public WorkerMainThreadRunnable
|
||||
{
|
||||
public:
|
||||
GetTypeRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
BlobImpl* aBlobImpl)
|
||||
: WorkerMainThreadRunnable(aWorkerPrivate,
|
||||
NS_LITERAL_CSTRING("FileBlobImpl :: GetType"))
|
||||
, mBlobImpl(aBlobImpl)
|
||||
{
|
||||
MOZ_ASSERT(aBlobImpl);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
bool
|
||||
MainThreadRun() override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsAutoString type;
|
||||
mBlobImpl->GetType(type);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
~GetTypeRunnable() = default;
|
||||
|
||||
RefPtr<BlobImpl> mBlobImpl;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void
|
||||
FileBlobImpl::GetType(nsAString& aType)
|
||||
{
|
||||
aType.Truncate();
|
||||
|
||||
if (mContentType.IsVoid()) {
|
||||
MOZ_ASSERT(mWholeFile,
|
||||
"Should only use lazy ContentType when using the whole file");
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
if (!workerPrivate) {
|
||||
// I have no idea in which thread this method is called. We cannot
|
||||
// return any valid value.
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<GetTypeRunnable> runnable =
|
||||
new GetTypeRunnable(workerPrivate, this);
|
||||
|
||||
ErrorResult rv;
|
||||
runnable->Dispatch(Terminating, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIMIMEService> mimeService =
|
||||
do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString mimeType;
|
||||
rv = mimeService->GetTypeFromFile(mFile, mimeType);
|
||||
if (NS_FAILED(rv)) {
|
||||
mimeType.Truncate();
|
||||
}
|
||||
|
||||
AppendUTF8toUTF16(mimeType, mContentType);
|
||||
mContentType.SetIsVoid(false);
|
||||
}
|
||||
|
||||
aType = mContentType;
|
||||
}
|
||||
|
||||
int64_t
|
||||
FileBlobImpl::GetLastModified(ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(mIsFile, "Should only be called on files");
|
||||
if (BaseBlobImpl::IsDateUnknown()) {
|
||||
PRTime msecs;
|
||||
aRv = mFile->GetLastModifiedTime(&msecs);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mLastModificationDate = msecs;
|
||||
}
|
||||
|
||||
return mLastModificationDate;
|
||||
}
|
||||
|
||||
void
|
||||
FileBlobImpl::SetLastModified(int64_t aLastModified)
|
||||
{
|
||||
MOZ_CRASH("SetLastModified of a real file is not allowed!");
|
||||
}
|
||||
|
||||
const uint32_t sFileStreamFlags =
|
||||
nsIFileInputStream::CLOSE_ON_EOF |
|
||||
nsIFileInputStream::REOPEN_ON_REWIND |
|
||||
nsIFileInputStream::DEFER_OPEN |
|
||||
nsIFileInputStream::SHARE_DELETE;
|
||||
|
||||
void
|
||||
FileBlobImpl::GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv)
|
||||
{
|
||||
if (mWholeFile) {
|
||||
aRv = NS_NewLocalFileInputStream(aStream, mFile, -1, -1, sFileStreamFlags);
|
||||
return;
|
||||
}
|
||||
|
||||
aRv = NS_NewPartialLocalFileInputStream(aStream, mFile, mStart, mLength,
|
||||
-1, -1, sFileStreamFlags);
|
||||
}
|
||||
|
||||
bool
|
||||
FileBlobImpl::IsDirectory() const
|
||||
{
|
||||
bool isDirectory = false;
|
||||
if (mFile) {
|
||||
mFile->IsDirectory(&isDirectory);
|
||||
}
|
||||
return isDirectory;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,72 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_FileBlobImpl_h
|
||||
#define mozilla_dom_FileBlobImpl_h
|
||||
|
||||
#include "mozilla/dom/BaseBlobImpl.h"
|
||||
|
||||
class nsIFile;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class FileBlobImpl : public BaseBlobImpl
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// Create as a file
|
||||
explicit FileBlobImpl(nsIFile* aFile);
|
||||
|
||||
// Create as a file
|
||||
FileBlobImpl(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength, nsIFile* aFile);
|
||||
|
||||
FileBlobImpl(const nsAString& aName, const nsAString& aContentType,
|
||||
uint64_t aLength, nsIFile* aFile,
|
||||
int64_t aLastModificationDate);
|
||||
|
||||
// Create as a file with custom name
|
||||
FileBlobImpl(nsIFile* aFile, const nsAString& aName,
|
||||
const nsAString& aContentType);
|
||||
|
||||
// Overrides
|
||||
virtual uint64_t GetSize(ErrorResult& aRv) override;
|
||||
virtual void GetType(nsAString& aType) override;
|
||||
virtual int64_t GetLastModified(ErrorResult& aRv) override;
|
||||
virtual void SetLastModified(int64_t aLastModified) override;
|
||||
virtual void GetMozFullPathInternal(nsAString& aFullPath,
|
||||
ErrorResult& aRv) const override;
|
||||
virtual void GetInternalStream(nsIInputStream** aInputStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual bool IsDirectory() const override;
|
||||
|
||||
// We always have size and date for this kind of blob.
|
||||
virtual bool IsSizeUnknown() const override { return false; }
|
||||
virtual bool IsDateUnknown() const override { return false; }
|
||||
|
||||
protected:
|
||||
virtual ~FileBlobImpl() = default;
|
||||
|
||||
private:
|
||||
// Create slice
|
||||
FileBlobImpl(const FileBlobImpl* aOther, uint64_t aStart,
|
||||
uint64_t aLength, const nsAString& aContentType);
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override;
|
||||
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
bool mWholeFile;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_FileBlobImpl_h
|
|
@ -0,0 +1,217 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MemoryBlobImpl.h"
|
||||
#include "mozilla/SHA1.h"
|
||||
#include "nsIIPCSerializableInputStream.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// XXXkhuey the input stream that we pass out of a File
|
||||
// can outlive the actual File object. Thus, we must
|
||||
// ensure that the buffer underlying the stream we get
|
||||
// from NS_NewByteInputStream is held alive as long as the
|
||||
// stream is. We do that by passing back this class instead.
|
||||
class DataOwnerAdapter final : public nsIInputStream,
|
||||
public nsISeekableStream,
|
||||
public nsIIPCSerializableInputStream
|
||||
{
|
||||
typedef MemoryBlobImpl::DataOwner DataOwner;
|
||||
public:
|
||||
static nsresult Create(DataOwner* aDataOwner,
|
||||
uint32_t aStart,
|
||||
uint32_t aLength,
|
||||
nsIInputStream** _retval);
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
// These are mandatory.
|
||||
NS_FORWARD_NSIINPUTSTREAM(mStream->)
|
||||
NS_FORWARD_NSISEEKABLESTREAM(mSeekableStream->)
|
||||
|
||||
// This is optional. We use a conditional QI to keep it from being called
|
||||
// if the underlying stream doesn't support it.
|
||||
NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(mSerializableInputStream->)
|
||||
|
||||
private:
|
||||
~DataOwnerAdapter() {}
|
||||
|
||||
DataOwnerAdapter(DataOwner* aDataOwner,
|
||||
nsIInputStream* aStream)
|
||||
: mDataOwner(aDataOwner), mStream(aStream),
|
||||
mSeekableStream(do_QueryInterface(aStream)),
|
||||
mSerializableInputStream(do_QueryInterface(aStream))
|
||||
{
|
||||
MOZ_ASSERT(mSeekableStream, "Somebody gave us the wrong stream!");
|
||||
}
|
||||
|
||||
RefPtr<DataOwner> mDataOwner;
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
nsCOMPtr<nsISeekableStream> mSeekableStream;
|
||||
nsCOMPtr<nsIIPCSerializableInputStream> mSerializableInputStream;
|
||||
};
|
||||
|
||||
NS_IMPL_ADDREF(DataOwnerAdapter)
|
||||
NS_IMPL_RELEASE(DataOwnerAdapter)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(DataOwnerAdapter)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
|
||||
mSerializableInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
nsresult DataOwnerAdapter::Create(DataOwner* aDataOwner,
|
||||
uint32_t aStart,
|
||||
uint32_t aLength,
|
||||
nsIInputStream** _retval)
|
||||
{
|
||||
nsresult rv;
|
||||
MOZ_ASSERT(aDataOwner, "Uh ...");
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
|
||||
rv = NS_NewByteInputStream(getter_AddRefs(stream),
|
||||
static_cast<const char*>(aDataOwner->mData) +
|
||||
aStart,
|
||||
(int32_t)aLength,
|
||||
NS_ASSIGNMENT_DEPEND);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ADDREF(*_retval = new DataOwnerAdapter(aDataOwner, stream));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(MemoryBlobImpl, BlobImpl)
|
||||
|
||||
already_AddRefed<BlobImpl>
|
||||
MemoryBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<BlobImpl> impl =
|
||||
new MemoryBlobImpl(this, aStart, aLength, aContentType);
|
||||
return impl.forget();
|
||||
}
|
||||
|
||||
void
|
||||
MemoryBlobImpl::GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv)
|
||||
{
|
||||
if (mLength > INT32_MAX) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
aRv = DataOwnerAdapter::Create(mDataOwner, mStart, mLength, aStream);
|
||||
}
|
||||
|
||||
/* static */ StaticMutex
|
||||
MemoryBlobImpl::DataOwner::sDataOwnerMutex;
|
||||
|
||||
/* static */ StaticAutoPtr<LinkedList<MemoryBlobImpl::DataOwner>>
|
||||
MemoryBlobImpl::DataOwner::sDataOwners;
|
||||
|
||||
/* static */ bool
|
||||
MemoryBlobImpl::DataOwner::sMemoryReporterRegistered = false;
|
||||
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(MemoryFileDataOwnerMallocSizeOf)
|
||||
|
||||
class MemoryBlobImplDataOwnerMemoryReporter final
|
||||
: public nsIMemoryReporter
|
||||
{
|
||||
~MemoryBlobImplDataOwnerMemoryReporter() {}
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aData, bool aAnonymize) override
|
||||
{
|
||||
typedef MemoryBlobImpl::DataOwner DataOwner;
|
||||
|
||||
StaticMutexAutoLock lock(DataOwner::sDataOwnerMutex);
|
||||
|
||||
if (!DataOwner::sDataOwners) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const size_t LARGE_OBJECT_MIN_SIZE = 8 * 1024;
|
||||
size_t smallObjectsTotal = 0;
|
||||
|
||||
for (DataOwner *owner = DataOwner::sDataOwners->getFirst();
|
||||
owner; owner = owner->getNext()) {
|
||||
|
||||
size_t size = MemoryFileDataOwnerMallocSizeOf(owner->mData);
|
||||
|
||||
if (size < LARGE_OBJECT_MIN_SIZE) {
|
||||
smallObjectsTotal += size;
|
||||
} else {
|
||||
SHA1Sum sha1;
|
||||
sha1.update(owner->mData, owner->mLength);
|
||||
uint8_t digest[SHA1Sum::kHashSize]; // SHA1 digests are 20 bytes long.
|
||||
sha1.finish(digest);
|
||||
|
||||
nsAutoCString digestString;
|
||||
for (size_t i = 0; i < sizeof(digest); i++) {
|
||||
digestString.AppendPrintf("%02x", digest[i]);
|
||||
}
|
||||
|
||||
aHandleReport->Callback(
|
||||
/* process */ NS_LITERAL_CSTRING(""),
|
||||
nsPrintfCString(
|
||||
"explicit/dom/memory-file-data/large/file(length=%llu, sha1=%s)",
|
||||
owner->mLength, aAnonymize ? "<anonymized>" : digestString.get()),
|
||||
KIND_HEAP, UNITS_BYTES, size,
|
||||
nsPrintfCString(
|
||||
"Memory used to back a memory file of length %llu bytes. The file "
|
||||
"has a sha1 of %s.\n\n"
|
||||
"Note that the allocator may round up a memory file's length -- "
|
||||
"that is, an N-byte memory file may take up more than N bytes of "
|
||||
"memory.",
|
||||
owner->mLength, digestString.get()),
|
||||
aData);
|
||||
}
|
||||
}
|
||||
|
||||
if (smallObjectsTotal > 0) {
|
||||
aHandleReport->Callback(
|
||||
/* process */ NS_LITERAL_CSTRING(""),
|
||||
NS_LITERAL_CSTRING("explicit/dom/memory-file-data/small"),
|
||||
KIND_HEAP, UNITS_BYTES, smallObjectsTotal,
|
||||
nsPrintfCString(
|
||||
"Memory used to back small memory files (i.e. those taking up less "
|
||||
"than %zu bytes of memory each).\n\n"
|
||||
"Note that the allocator may round up a memory file's length -- "
|
||||
"that is, an N-byte memory file may take up more than N bytes of "
|
||||
"memory.", LARGE_OBJECT_MIN_SIZE),
|
||||
aData);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(MemoryBlobImplDataOwnerMemoryReporter, nsIMemoryReporter)
|
||||
|
||||
/* static */ void
|
||||
MemoryBlobImpl::DataOwner::EnsureMemoryReporterRegistered()
|
||||
{
|
||||
sDataOwnerMutex.AssertCurrentThreadOwns();
|
||||
if (sMemoryReporterRegistered) {
|
||||
return;
|
||||
}
|
||||
|
||||
RegisterStrongMemoryReporter(new MemoryBlobImplDataOwnerMemoryReporter());
|
||||
|
||||
sMemoryReporterRegistered = true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,117 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_MemoryBlobImpl_h
|
||||
#define mozilla_dom_MemoryBlobImpl_h
|
||||
|
||||
#include "mozilla/dom/BaseBlobImpl.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class MemoryBlobImpl final : public BaseBlobImpl
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
MemoryBlobImpl(void* aMemoryBuffer, uint64_t aLength, const nsAString& aName,
|
||||
const nsAString& aContentType, int64_t aLastModifiedDate)
|
||||
: BaseBlobImpl(aName, aContentType, aLength, aLastModifiedDate)
|
||||
, mDataOwner(new DataOwner(aMemoryBuffer, aLength))
|
||||
{
|
||||
MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data");
|
||||
}
|
||||
|
||||
MemoryBlobImpl(void* aMemoryBuffer, uint64_t aLength,
|
||||
const nsAString& aContentType)
|
||||
: BaseBlobImpl(aContentType, aLength)
|
||||
, mDataOwner(new DataOwner(aMemoryBuffer, aLength))
|
||||
{
|
||||
MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data");
|
||||
}
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override;
|
||||
|
||||
virtual bool IsMemoryFile() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
class DataOwner final : public mozilla::LinkedListElement<DataOwner>
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataOwner)
|
||||
DataOwner(void* aMemoryBuffer, uint64_t aLength)
|
||||
: mData(aMemoryBuffer)
|
||||
, mLength(aLength)
|
||||
{
|
||||
mozilla::StaticMutexAutoLock lock(sDataOwnerMutex);
|
||||
|
||||
if (!sDataOwners) {
|
||||
sDataOwners = new mozilla::LinkedList<DataOwner>();
|
||||
EnsureMemoryReporterRegistered();
|
||||
}
|
||||
sDataOwners->insertBack(this);
|
||||
}
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
~DataOwner() {
|
||||
mozilla::StaticMutexAutoLock lock(sDataOwnerMutex);
|
||||
|
||||
remove();
|
||||
if (sDataOwners->isEmpty()) {
|
||||
// Free the linked list if it's empty.
|
||||
sDataOwners = nullptr;
|
||||
}
|
||||
|
||||
free(mData);
|
||||
}
|
||||
|
||||
public:
|
||||
static void EnsureMemoryReporterRegistered();
|
||||
|
||||
// sDataOwners and sMemoryReporterRegistered may only be accessed while
|
||||
// holding sDataOwnerMutex! You also must hold the mutex while touching
|
||||
// elements of the linked list that DataOwner inherits from.
|
||||
static mozilla::StaticMutex sDataOwnerMutex;
|
||||
static mozilla::StaticAutoPtr<mozilla::LinkedList<DataOwner> > sDataOwners;
|
||||
static bool sMemoryReporterRegistered;
|
||||
|
||||
void* mData;
|
||||
uint64_t mLength;
|
||||
};
|
||||
|
||||
private:
|
||||
// Create slice
|
||||
MemoryBlobImpl(const MemoryBlobImpl* aOther, uint64_t aStart,
|
||||
uint64_t aLength, const nsAString& aContentType)
|
||||
: BaseBlobImpl(aContentType, aOther->mStart + aStart, aLength)
|
||||
, mDataOwner(aOther->mDataOwner)
|
||||
{
|
||||
MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data");
|
||||
mImmutable = aOther->mImmutable;
|
||||
}
|
||||
|
||||
~MemoryBlobImpl() {}
|
||||
|
||||
// Used when backed by a memory store
|
||||
RefPtr<DataOwner> mDataOwner;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_MemoryBlobImpl_h
|
|
@ -280,13 +280,13 @@ MultipartBlobImpl::GetMozFullPathInternal(nsAString& aFilename,
|
|||
ErrorResult& aRv) const
|
||||
{
|
||||
if (!mIsFromNsIFile || mBlobImpls.Length() == 0) {
|
||||
BlobImplBase::GetMozFullPathInternal(aFilename, aRv);
|
||||
BaseBlobImpl::GetMozFullPathInternal(aFilename, aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
BlobImpl* blobImpl = mBlobImpls.ElementAt(0).get();
|
||||
if (!blobImpl) {
|
||||
BlobImplBase::GetMozFullPathInternal(aFilename, aRv);
|
||||
BaseBlobImpl::GetMozFullPathInternal(aFilename, aRv);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -313,7 +313,7 @@ MultipartBlobImpl::SetMutable(bool aMutable)
|
|||
}
|
||||
}
|
||||
|
||||
rv = BlobImplBase::SetMutable(aMutable);
|
||||
rv = BaseBlobImpl::SetMutable(aMutable);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -8,20 +8,14 @@
|
|||
#define mozilla_dom_MultipartBlobImpl_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/BlobBinding.h"
|
||||
#include "mozilla/dom/FileBinding.h"
|
||||
#include <algorithm>
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "mozilla/dom/BaseBlobImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class MultipartBlobImpl final : public BlobImplBase
|
||||
class MultipartBlobImpl final : public BaseBlobImpl
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
@ -41,14 +35,14 @@ public:
|
|||
|
||||
// Create as a file to be later initialized
|
||||
explicit MultipartBlobImpl(const nsAString& aName)
|
||||
: BlobImplBase(aName, EmptyString(), UINT64_MAX),
|
||||
: BaseBlobImpl(aName, EmptyString(), UINT64_MAX),
|
||||
mIsFromNsIFile(false)
|
||||
{
|
||||
}
|
||||
|
||||
// Create as a blob to be later initialized
|
||||
MultipartBlobImpl()
|
||||
: BlobImplBase(EmptyString(), UINT64_MAX),
|
||||
: BaseBlobImpl(EmptyString(), UINT64_MAX),
|
||||
mIsFromNsIFile(false)
|
||||
{
|
||||
}
|
||||
|
@ -103,7 +97,7 @@ protected:
|
|||
MultipartBlobImpl(nsTArray<RefPtr<BlobImpl>>&& aBlobImpls,
|
||||
const nsAString& aName,
|
||||
const nsAString& aContentType)
|
||||
: BlobImplBase(aName, aContentType, UINT64_MAX),
|
||||
: BaseBlobImpl(aName, aContentType, UINT64_MAX),
|
||||
mBlobImpls(Move(aBlobImpls)),
|
||||
mIsFromNsIFile(false)
|
||||
{
|
||||
|
@ -111,7 +105,7 @@ protected:
|
|||
|
||||
MultipartBlobImpl(nsTArray<RefPtr<BlobImpl>>&& aBlobImpls,
|
||||
const nsAString& aContentType)
|
||||
: BlobImplBase(aContentType, UINT64_MAX),
|
||||
: BaseBlobImpl(aContentType, UINT64_MAX),
|
||||
mBlobImpls(Move(aBlobImpls)),
|
||||
mIsFromNsIFile(false)
|
||||
{
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/MutableBlobStorage.h"
|
||||
#include "MutableBlobStorage.h"
|
||||
#include "MemoryBlobImpl.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "File.h"
|
||||
#include "nsAnonymousTemporaryFile.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
@ -406,10 +408,10 @@ MutableBlobStorage::GetBlobWhenReady(nsISupports* aParent,
|
|||
RefPtr<BlobImpl> blobImpl;
|
||||
|
||||
if (mData) {
|
||||
blobImpl = new BlobImplMemory(mData, mDataLen,
|
||||
blobImpl = new MemoryBlobImpl(mData, mDataLen,
|
||||
NS_ConvertUTF8toUTF16(aContentType));
|
||||
|
||||
mData = nullptr; // The BlobImplMemory takes ownership of the buffer
|
||||
mData = nullptr; // The MemoryBlobImpl takes ownership of the buffer
|
||||
mDataLen = 0;
|
||||
mDataBufferLen = 0;
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "StreamBlobImpl.h"
|
||||
#include "nsStringStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(StreamBlobImpl, BlobImpl, nsIMemoryReporter)
|
||||
|
||||
/* static */ already_AddRefed<StreamBlobImpl>
|
||||
StreamBlobImpl::Create(nsIInputStream* aInputStream,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength)
|
||||
{
|
||||
RefPtr<StreamBlobImpl> blobImplStream =
|
||||
new StreamBlobImpl(aInputStream, aContentType, aLength);
|
||||
blobImplStream->MaybeRegisterMemoryReporter();
|
||||
return blobImplStream.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<StreamBlobImpl>
|
||||
StreamBlobImpl::Create(nsIInputStream* aInputStream,
|
||||
const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
int64_t aLastModifiedDate,
|
||||
uint64_t aLength)
|
||||
{
|
||||
RefPtr<StreamBlobImpl> blobImplStream =
|
||||
new StreamBlobImpl(aInputStream, aName, aContentType, aLastModifiedDate,
|
||||
aLength);
|
||||
blobImplStream->MaybeRegisterMemoryReporter();
|
||||
return blobImplStream.forget();
|
||||
}
|
||||
|
||||
StreamBlobImpl::StreamBlobImpl(nsIInputStream* aInputStream,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength)
|
||||
: BaseBlobImpl(aContentType, aLength)
|
||||
, mInputStream(aInputStream)
|
||||
{
|
||||
mImmutable = true;
|
||||
}
|
||||
|
||||
StreamBlobImpl::StreamBlobImpl(StreamBlobImpl* aOther,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aStart, uint64_t aLength)
|
||||
: BaseBlobImpl(aContentType, aOther->mStart + aStart, aLength)
|
||||
, mInputStream(new SlicedInputStream(aOther->mInputStream, aStart, aLength))
|
||||
{
|
||||
mImmutable = true;
|
||||
}
|
||||
|
||||
StreamBlobImpl::StreamBlobImpl(nsIInputStream* aInputStream,
|
||||
const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
int64_t aLastModifiedDate,
|
||||
uint64_t aLength)
|
||||
: BaseBlobImpl(aName, aContentType, aLength, aLastModifiedDate)
|
||||
, mInputStream(aInputStream)
|
||||
{
|
||||
mImmutable = true;
|
||||
}
|
||||
|
||||
StreamBlobImpl::~StreamBlobImpl()
|
||||
{
|
||||
UnregisterWeakMemoryReporter(this);
|
||||
}
|
||||
|
||||
void
|
||||
StreamBlobImpl::GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> clonedStream;
|
||||
nsCOMPtr<nsIInputStream> replacementStream;
|
||||
|
||||
aRv = NS_CloneInputStream(mInputStream, getter_AddRefs(clonedStream),
|
||||
getter_AddRefs(replacementStream));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (replacementStream) {
|
||||
mInputStream = replacementStream.forget();
|
||||
}
|
||||
|
||||
clonedStream.forget(aStream);
|
||||
}
|
||||
|
||||
already_AddRefed<BlobImpl>
|
||||
StreamBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv)
|
||||
{
|
||||
if (!aLength) {
|
||||
RefPtr<BlobImpl> impl = new EmptyBlobImpl(aContentType);
|
||||
return impl.forget();
|
||||
}
|
||||
|
||||
RefPtr<BlobImpl> impl =
|
||||
new StreamBlobImpl(this, aContentType, aStart, aLength);
|
||||
return impl.forget();
|
||||
}
|
||||
|
||||
void
|
||||
StreamBlobImpl::MaybeRegisterMemoryReporter()
|
||||
{
|
||||
// We report only stringInputStream.
|
||||
nsCOMPtr<nsIStringInputStream> stringInputStream =
|
||||
do_QueryInterface(mInputStream);
|
||||
if (!stringInputStream) {
|
||||
return;
|
||||
}
|
||||
|
||||
RegisterWeakMemoryReporter(this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StreamBlobImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aData, bool aAnonymize)
|
||||
{
|
||||
nsCOMPtr<nsIStringInputStream> stringInputStream =
|
||||
do_QueryInterface(mInputStream);
|
||||
if (!stringInputStream) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_COLLECT_REPORT(
|
||||
"explicit/dom/memory-file-data/stream", KIND_HEAP, UNITS_BYTES,
|
||||
stringInputStream->SizeOfIncludingThis(MallocSizeOf),
|
||||
"Memory used to back a File/Blob based on an input stream.");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,75 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_StreamBlobImpl_h
|
||||
#define mozilla_dom_StreamBlobImpl_h
|
||||
|
||||
#include "BaseBlobImpl.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class StreamBlobImpl final : public BaseBlobImpl
|
||||
, public nsIMemoryReporter
|
||||
{
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIMEMORYREPORTER
|
||||
|
||||
static already_AddRefed<StreamBlobImpl>
|
||||
Create(nsIInputStream* aInputStream,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength);
|
||||
|
||||
static already_AddRefed<StreamBlobImpl>
|
||||
Create(nsIInputStream* aInputStream,
|
||||
const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
int64_t aLastModifiedDate,
|
||||
uint64_t aLength);
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override;
|
||||
|
||||
virtual bool IsMemoryFile() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
StreamBlobImpl(nsIInputStream* aInputStream,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aLength);
|
||||
|
||||
StreamBlobImpl(nsIInputStream* aInputStream,
|
||||
const nsAString& aName,
|
||||
const nsAString& aContentType,
|
||||
int64_t aLastModifiedDate,
|
||||
uint64_t aLength);
|
||||
|
||||
StreamBlobImpl(StreamBlobImpl* aOther,
|
||||
const nsAString& aContentType,
|
||||
uint64_t aStart,
|
||||
uint64_t aLength);
|
||||
|
||||
~StreamBlobImpl();
|
||||
|
||||
void MaybeRegisterMemoryReporter();
|
||||
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_StreamBlobImpl_h
|
|
@ -0,0 +1,64 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "StreamBlobImpl.h"
|
||||
#include "nsStringStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(StringBlobImpl, BlobImpl, nsIMemoryReporter)
|
||||
|
||||
/* static */ already_AddRefed<StringBlobImpl>
|
||||
StringBlobImpl::Create(const nsACString& aData, const nsAString& aContentType)
|
||||
{
|
||||
RefPtr<StringBlobImpl> blobImpl = new StringBlobImpl(aData, aContentType);
|
||||
RegisterWeakMemoryReporter(blobImpl);
|
||||
return blobImpl.forget();
|
||||
}
|
||||
|
||||
StringBlobImpl::StringBlobImpl(const nsACString& aData,
|
||||
const nsAString& aContentType)
|
||||
: BaseBlobImpl(aContentType, aData.Length())
|
||||
, mData(aData)
|
||||
{
|
||||
}
|
||||
|
||||
StringBlobImpl::~StringBlobImpl()
|
||||
{
|
||||
UnregisterWeakMemoryReporter(this);
|
||||
}
|
||||
|
||||
already_AddRefed<BlobImpl>
|
||||
StringBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<BlobImpl> impl =
|
||||
new StringBlobImpl(Substring(mData, aStart, aLength),
|
||||
aContentType);
|
||||
return impl.forget();
|
||||
}
|
||||
|
||||
void
|
||||
StringBlobImpl::GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv)
|
||||
{
|
||||
aRv = NS_NewCStringInputStream(aStream, mData);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StringBlobImpl::CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aData, bool aAnonymize)
|
||||
{
|
||||
MOZ_COLLECT_REPORT(
|
||||
"explicit/dom/memory-file-data/string", KIND_HEAP, UNITS_BYTES,
|
||||
mData.SizeOfExcludingThisIfUnshared(MallocSizeOf),
|
||||
"Memory used to back a File/Blob based on a string.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_StringBlobImpl_h
|
||||
#define mozilla_dom_StringBlobImpl_h
|
||||
|
||||
#include "BaseBlobImpl.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class StringBlobImpl final : public BaseBlobImpl
|
||||
, public nsIMemoryReporter
|
||||
{
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIMEMORYREPORTER
|
||||
|
||||
static already_AddRefed<StringBlobImpl>
|
||||
Create(const nsACString& aData, const nsAString& aContentType);
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override;
|
||||
|
||||
private:
|
||||
StringBlobImpl(const nsACString& aData, const nsAString& aContentType);
|
||||
|
||||
~StringBlobImpl();
|
||||
|
||||
nsCString mData;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_StringBlobImpl_h
|
|
@ -0,0 +1,58 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "TemporaryBlobImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(TemporaryBlobImpl, BlobImpl)
|
||||
|
||||
TemporaryBlobImpl::TemporaryBlobImpl(PRFileDesc* aFD, uint64_t aStartPos,
|
||||
uint64_t aLength,
|
||||
const nsAString& aContentType)
|
||||
: BaseBlobImpl(aContentType, aLength)
|
||||
, mStartPos(aStartPos)
|
||||
{
|
||||
mFileDescOwner = new nsTemporaryFileInputStream::FileDescOwner(aFD);
|
||||
}
|
||||
|
||||
TemporaryBlobImpl::TemporaryBlobImpl(const TemporaryBlobImpl* aOther,
|
||||
uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType)
|
||||
: BaseBlobImpl(aContentType, aLength)
|
||||
, mStartPos(aStart)
|
||||
, mFileDescOwner(aOther->mFileDescOwner)
|
||||
{}
|
||||
|
||||
already_AddRefed<BlobImpl>
|
||||
TemporaryBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (aStart + aLength > mLength) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<BlobImpl> impl =
|
||||
new TemporaryBlobImpl(this, aStart + mStartPos,
|
||||
aLength, aContentType);
|
||||
return impl.forget();
|
||||
}
|
||||
|
||||
void
|
||||
TemporaryBlobImpl::GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> stream =
|
||||
new nsTemporaryFileInputStream(mFileDescOwner, mStartPos,
|
||||
mStartPos + mLength);
|
||||
stream.forget(aStream);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,45 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_TemporaryBlobImpl_h
|
||||
#define mozilla_dom_TemporaryBlobImpl_h
|
||||
|
||||
#include "BaseBlobImpl.h"
|
||||
#include "nsTemporaryFileInputStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class TemporaryBlobImpl final : public BaseBlobImpl
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
TemporaryBlobImpl(PRFileDesc* aFD, uint64_t aStartPos,
|
||||
uint64_t aLength, const nsAString& aContentType);
|
||||
|
||||
virtual void GetInternalStream(nsIInputStream** aStream,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual already_AddRefed<BlobImpl>
|
||||
CreateSlice(uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType, ErrorResult& aRv) override;
|
||||
|
||||
private:
|
||||
TemporaryBlobImpl(const TemporaryBlobImpl* aOther,
|
||||
uint64_t aStart, uint64_t aLength,
|
||||
const nsAString& aContentType);
|
||||
|
||||
~TemporaryBlobImpl() = default;
|
||||
|
||||
uint64_t mStartPos;
|
||||
RefPtr<nsTemporaryFileInputStream::FileDescOwner> mFileDescOwner;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_TemporaryBlobImpl_h
|
|
@ -10,6 +10,7 @@
|
|||
#include "BackgroundParent.h"
|
||||
#include "ContentChild.h"
|
||||
#include "ContentParent.h"
|
||||
#include "EmptyBlobImpl.h"
|
||||
#include "FileDescriptorSetChild.h"
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
@ -18,7 +19,7 @@
|
|||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/BaseBlobImpl.h"
|
||||
#include "mozilla/dom/nsIContentParent.h"
|
||||
#include "mozilla/dom/nsIContentChild.h"
|
||||
#include "mozilla/dom/PBlobStreamChild.h"
|
||||
|
@ -46,6 +47,7 @@
|
|||
#include "nsStringStream.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "StreamBlobImpl.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
|
||||
|
@ -658,7 +660,7 @@ CreateBlobImpl(const BlobDataStream& aStream,
|
|||
if (!aMetadata.mHasRecursed && aMetadata.IsFile()) {
|
||||
if (length) {
|
||||
blobImpl =
|
||||
BlobImplStream::Create(inputStream,
|
||||
StreamBlobImpl::Create(inputStream,
|
||||
aMetadata.mName,
|
||||
aMetadata.mContentType,
|
||||
aMetadata.mLastModifiedDate,
|
||||
|
@ -671,7 +673,7 @@ CreateBlobImpl(const BlobDataStream& aStream,
|
|||
}
|
||||
} else if (length) {
|
||||
blobImpl =
|
||||
BlobImplStream::Create(inputStream, aMetadata.mContentType,
|
||||
StreamBlobImpl::Create(inputStream, aMetadata.mContentType,
|
||||
length);
|
||||
} else {
|
||||
blobImpl = new EmptyBlobImpl(aMetadata.mContentType);
|
||||
|
@ -1786,7 +1788,7 @@ NS_IMPL_ISUPPORTS_INHERITED0(BlobParent::OpenStreamRunnable, Runnable)
|
|||
******************************************************************************/
|
||||
|
||||
class BlobChild::RemoteBlobImpl
|
||||
: public BlobImplBase
|
||||
: public BaseBlobImpl
|
||||
, public nsIRemoteBlob
|
||||
{
|
||||
protected:
|
||||
|
@ -2180,7 +2182,7 @@ RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
|
|||
int64_t aModDate,
|
||||
BlobImplIsDirectory aIsDirectory,
|
||||
bool aIsSameProcessBlob)
|
||||
: BlobImplBase(aName, aContentType, aLength, aModDate)
|
||||
: BaseBlobImpl(aName, aContentType, aLength, aModDate)
|
||||
, mWorkerPrivate(nullptr)
|
||||
, mMutex("BlobChild::RemoteBlobImpl::mMutex")
|
||||
, mIsSlice(false), mIsDirectory(aIsDirectory == eDirectory)
|
||||
|
@ -2204,7 +2206,7 @@ RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
|
|||
const nsAString& aContentType,
|
||||
uint64_t aLength,
|
||||
bool aIsSameProcessBlob)
|
||||
: BlobImplBase(aContentType, aLength)
|
||||
: BaseBlobImpl(aContentType, aLength)
|
||||
, mWorkerPrivate(nullptr)
|
||||
, mMutex("BlobChild::RemoteBlobImpl::mMutex")
|
||||
, mIsSlice(false), mIsDirectory(false)
|
||||
|
@ -2222,7 +2224,7 @@ RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
|
|||
|
||||
BlobChild::
|
||||
RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor)
|
||||
: BlobImplBase(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
|
||||
: BaseBlobImpl(EmptyString(), EmptyString(), UINT64_MAX, INT64_MAX)
|
||||
, mWorkerPrivate(nullptr)
|
||||
, mMutex("BlobChild::RemoteBlobImpl::mMutex")
|
||||
, mIsSlice(false), mIsDirectory(false)
|
||||
|
@ -2232,7 +2234,7 @@ RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor)
|
|||
|
||||
BlobChild::
|
||||
RemoteBlobImpl::RemoteBlobImpl(const nsAString& aContentType, uint64_t aLength)
|
||||
: BlobImplBase(aContentType, aLength)
|
||||
: BaseBlobImpl(aContentType, aLength)
|
||||
, mActor(nullptr)
|
||||
, mWorkerPrivate(nullptr)
|
||||
, mMutex("BlobChild::RemoteBlobImpl::mMutex")
|
||||
|
@ -2478,7 +2480,7 @@ RemoteBlobImpl::SetMutable(bool aMutable)
|
|||
AsSlice()->EnsureActorWasCreated();
|
||||
}
|
||||
|
||||
nsresult rv = BlobImplBase::SetMutable(aMutable);
|
||||
nsresult rv = BaseBlobImpl::SetMutable(aMutable);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -19,27 +19,41 @@ EXPORTS += [
|
|||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'BaseBlobImpl.h',
|
||||
'Blob.h',
|
||||
'BlobImpl.h',
|
||||
'BlobSet.h',
|
||||
'File.h',
|
||||
'FileBlobImpl.h',
|
||||
'FileCreatorHelper.h',
|
||||
'FileList.h',
|
||||
'FileReader.h',
|
||||
'MemoryBlobImpl.h',
|
||||
'MultipartBlobImpl.h',
|
||||
'MutableBlobStorage.h',
|
||||
'MutableBlobStreamListener.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'BaseBlobImpl.cpp',
|
||||
'Blob.cpp',
|
||||
'BlobImpl.cpp',
|
||||
'BlobSet.cpp',
|
||||
'EmptyBlobImpl.cpp',
|
||||
'File.cpp',
|
||||
'FileBlobImpl.cpp',
|
||||
'FileCreatorHelper.cpp',
|
||||
'FileList.cpp',
|
||||
'FileReader.cpp',
|
||||
'MemoryBlobImpl.cpp',
|
||||
'MultipartBlobImpl.cpp',
|
||||
'MutableBlobStorage.cpp',
|
||||
'MutableBlobStreamListener.cpp',
|
||||
'nsHostObjectProtocolHandler.cpp',
|
||||
'nsHostObjectURI.cpp',
|
||||
'StreamBlobImpl.cpp',
|
||||
'StringBlobImpl.cpp',
|
||||
'TemporaryBlobImpl.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/Exceptions.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/BlobImpl.h"
|
||||
#include "mozilla/dom/ipc/BlobChild.h"
|
||||
#include "mozilla/dom/ipc/BlobParent.h"
|
||||
#include "mozilla/dom/MediaSource.h"
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileBlobImpl.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/PFileSystemParams.h"
|
||||
|
@ -20,6 +20,7 @@
|
|||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
|
@ -232,7 +233,7 @@ CreateFileTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
|||
{
|
||||
AssertIsOnBackgroundThread();
|
||||
|
||||
RefPtr<BlobImpl> blobImpl = new BlobImplFile(mTargetPath);
|
||||
RefPtr<BlobImpl> blobImpl = new FileBlobImpl(mTargetPath);
|
||||
BlobParent* blobParent =
|
||||
BlobParent::GetOrCreate(mRequestParent->Manager(), blobImpl);
|
||||
return FileSystemFileResponse(blobParent, nullptr);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include "HTMLSplitOnSpacesTokenizer.h"
|
||||
#include "js/Value.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileBlobImpl.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/PFileSystemParams.h"
|
||||
|
@ -239,7 +239,7 @@ GetDirectoryListingTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
|||
}
|
||||
|
||||
FileSystemDirectoryListingResponseFile fileData;
|
||||
RefPtr<BlobImpl> blobImpl = new BlobImplFile(path);
|
||||
RefPtr<BlobImpl> blobImpl = new FileBlobImpl(path);
|
||||
|
||||
nsAutoString filePath;
|
||||
filePath.Assign(mDOMPath);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "GetFileOrDirectoryTask.h"
|
||||
|
||||
#include "js/Value.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileBlobImpl.h"
|
||||
#include "mozilla/dom/FileSystemBase.h"
|
||||
#include "mozilla/dom/FileSystemUtils.h"
|
||||
#include "mozilla/dom/PFileSystemParams.h"
|
||||
|
@ -214,7 +214,7 @@ GetFileOrDirectoryTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
|
|||
return FileSystemDirectoryResponse(path);
|
||||
}
|
||||
|
||||
RefPtr<BlobImpl> blobImpl = new BlobImplFile(mTargetPath);
|
||||
RefPtr<BlobImpl> blobImpl = new FileBlobImpl(mTargetPath);
|
||||
BlobParent* blobParent =
|
||||
BlobParent::GetOrCreate(mRequestParent->Manager(), blobImpl);
|
||||
return FileSystemFileResponse(blobParent, nullptr);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "GetFilesHelper.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/FileBlobImpl.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -383,7 +384,7 @@ GetFilesHelperBase::ExploreDirectory(const nsAString& aDOMPath, nsIFile* aFile)
|
|||
domPath.Append(leafName);
|
||||
|
||||
if (isFile) {
|
||||
RefPtr<BlobImpl> blobImpl = new BlobImplFile(currFile);
|
||||
RefPtr<BlobImpl> blobImpl = new FileBlobImpl(currFile);
|
||||
blobImpl->SetDOMPath(domPath);
|
||||
|
||||
if (!mTargetBlobImplArray.AppendElement(blobImpl, fallible)) {
|
||||
|
|
|
@ -372,6 +372,17 @@ nsGenericHTMLFrameElement::MapScrollingAttribute(const nsAttrValue* aValue)
|
|||
return mappedValue;
|
||||
}
|
||||
|
||||
static bool
|
||||
PrincipalAllowsBrowserFrame(nsIPrincipal* aPrincipal)
|
||||
{
|
||||
nsCOMPtr<nsIPermissionManager> permMgr = mozilla::services::GetPermissionManager();
|
||||
NS_ENSURE_TRUE(permMgr, false);
|
||||
uint32_t permission = nsIPermissionManager::DENY_ACTION;
|
||||
nsresult rv = permMgr->TestPermissionFromPrincipal(aPrincipal, "browser", &permission);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
return permission == nsIPermissionManager::ALLOW_ACTION;
|
||||
}
|
||||
|
||||
/* virtual */ nsresult
|
||||
nsGenericHTMLFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
const nsAttrValue* aValue,
|
||||
|
@ -401,6 +412,11 @@ nsGenericHTMLFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|||
}
|
||||
}
|
||||
|
||||
if (aName == nsGkAtoms::mozbrowser && aNameSpaceID == kNameSpaceID_None) {
|
||||
mReallyIsBrowser = !!aValue && BrowserFramesEnabled() &&
|
||||
PrincipalAllowsBrowserFrame(NodePrincipal());
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
|
||||
aNotify);
|
||||
}
|
||||
|
@ -486,28 +502,7 @@ nsGenericHTMLFrameElement::BrowserFramesEnabled()
|
|||
/* [infallible] */ nsresult
|
||||
nsGenericHTMLFrameElement::GetReallyIsBrowser(bool *aOut)
|
||||
{
|
||||
*aOut = false;
|
||||
|
||||
// Fail if browser frames are globally disabled.
|
||||
if (!nsGenericHTMLFrameElement::BrowserFramesEnabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Fail if this frame doesn't have the mozbrowser attribute.
|
||||
if (!GetBoolAttr(nsGkAtoms::mozbrowser)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Fail if the node principal isn't trusted.
|
||||
nsIPrincipal *principal = NodePrincipal();
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
services::GetPermissionManager();
|
||||
NS_ENSURE_TRUE(permMgr, NS_OK);
|
||||
|
||||
uint32_t permission = nsIPermissionManager::DENY_ACTION;
|
||||
nsresult rv = permMgr->TestPermissionFromPrincipal(principal, "browser", &permission);
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
*aOut = permission == nsIPermissionManager::ALLOW_ACTION;
|
||||
*aOut = mReallyIsBrowser;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
, mIsPrerendered(false)
|
||||
, mBrowserFrameListenersRegistered(false)
|
||||
, mFrameLoaderCreationDisallowed(false)
|
||||
, mReallyIsBrowser(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -125,6 +126,7 @@ protected:
|
|||
bool mIsPrerendered;
|
||||
bool mBrowserFrameListenersRegistered;
|
||||
bool mFrameLoaderCreationDisallowed;
|
||||
bool mReallyIsBrowser;
|
||||
|
||||
// This flag is only used by <iframe>. See HTMLIFrameElement::
|
||||
// FullscreenFlag() for details. It is placed here so that we
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "mozilla/UniquePtrExtensions.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileBlobImpl.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/dom/filehandle/ActorsParent.h"
|
||||
|
@ -9086,14 +9087,14 @@ private:
|
|||
};
|
||||
|
||||
class BlobImplStoredFile final
|
||||
: public BlobImplFile
|
||||
: public FileBlobImpl
|
||||
{
|
||||
RefPtr<FileInfo> mFileInfo;
|
||||
const bool mSnapshot;
|
||||
|
||||
public:
|
||||
BlobImplStoredFile(nsIFile* aFile, FileInfo* aFileInfo, bool aSnapshot)
|
||||
: BlobImplFile(aFile)
|
||||
: FileBlobImpl(aFile)
|
||||
, mFileInfo(aFileInfo)
|
||||
, mSnapshot(aSnapshot)
|
||||
{
|
||||
|
@ -17633,7 +17634,7 @@ FileManager::GetUsage(nsIFile* aDirectory, uint64_t* aUsage)
|
|||
******************************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(BlobImplStoredFile,
|
||||
BlobImplFile,
|
||||
FileBlobImpl,
|
||||
BlobImplStoredFile)
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "mozilla/dom/IDBMutableFileBinding.h"
|
||||
#include "mozilla/dom/BlobBinding.h"
|
||||
#include "mozilla/dom/IDBObjectStoreBinding.h"
|
||||
#include "mozilla/dom/MemoryBlobImpl.h"
|
||||
#include "mozilla/dom/StructuredCloneHolder.h"
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
#include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
|
||||
|
@ -363,11 +364,11 @@ StructuredCloneWriteCallback(JSContext* aCx,
|
|||
compiledSize);
|
||||
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
new BlobImplMemory(bytecode.release(), bytecodeSize, EmptyString());
|
||||
new MemoryBlobImpl(bytecode.release(), bytecodeSize, EmptyString());
|
||||
RefPtr<Blob> bytecodeBlob = Blob::Create(nullptr, blobImpl);
|
||||
|
||||
blobImpl =
|
||||
new BlobImplMemory(compiled.release(), compiledSize, EmptyString());
|
||||
new MemoryBlobImpl(compiled.release(), compiledSize, EmptyString());
|
||||
RefPtr<Blob> compiledBlob = Blob::Create(nullptr, blobImpl);
|
||||
|
||||
if (cloneWriteInfo->mFiles.Length() + 1 > size_t(UINT32_MAX)) {
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include "ContentChild.h"
|
||||
|
||||
#include "CrashReporterChild.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "TabChild.h"
|
||||
#include "HandlerServiceChild.h"
|
||||
|
@ -33,7 +32,6 @@
|
|||
#include "mozilla/dom/FlyWebPublishedServerIPC.h"
|
||||
#include "mozilla/dom/GetFilesHelper.h"
|
||||
#include "mozilla/dom/MemoryReportRequest.h"
|
||||
#include "mozilla/dom/PCrashReporterChild.h"
|
||||
#include "mozilla/dom/ProcessGlobal.h"
|
||||
#include "mozilla/dom/PushNotifier.h"
|
||||
#include "mozilla/dom/StorageIPC.h"
|
||||
|
@ -205,6 +203,9 @@
|
|||
#ifdef MOZ_WIDGET_GTK
|
||||
#include "nsAppRunner.h"
|
||||
#endif
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "mozilla/ipc/CrashReporterClient.h"
|
||||
#endif
|
||||
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -587,8 +588,7 @@ ContentChild::Init(MessageLoop* aIOLoop,
|
|||
#endif
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
SendPCrashReporterConstructor(CrashReporter::CurrentThreadId(),
|
||||
XRE_GetProcessType());
|
||||
CrashReporterClient::InitSingleton(this);
|
||||
#endif
|
||||
|
||||
mID = aChildID;
|
||||
|
@ -1625,24 +1625,6 @@ ContentChild::RecvNotifyEmptyHTTPCache()
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PCrashReporterChild*
|
||||
ContentChild::AllocPCrashReporterChild(const mozilla::dom::NativeThreadId& id,
|
||||
const uint32_t& processType)
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
return new CrashReporterChild();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPCrashReporterChild(PCrashReporterChild* crashreporter)
|
||||
{
|
||||
delete crashreporter;
|
||||
return true;
|
||||
}
|
||||
|
||||
PHalChild*
|
||||
ContentChild::AllocPHalChild()
|
||||
{
|
||||
|
@ -2037,6 +2019,9 @@ ContentChild::ActorDestroy(ActorDestroyReason why)
|
|||
}
|
||||
mIsAlive = false;
|
||||
|
||||
# ifdef MOZ_CRASHREPORTER
|
||||
CrashReporterClient::DestroySingleton();
|
||||
# endif
|
||||
XRE_ShutdownChildProcess();
|
||||
#endif // NS_FREE_PERMANENT_DATA
|
||||
}
|
||||
|
@ -2062,14 +2047,8 @@ ContentChild::ProcessingError(Result aCode, const char* aReason)
|
|||
}
|
||||
|
||||
#if defined(MOZ_CRASHREPORTER) && !defined(MOZ_B2G)
|
||||
if (PCrashReporterChild* c = LoneManagedOrNullAsserts(ManagedPCrashReporterChild())) {
|
||||
CrashReporterChild* crashReporter =
|
||||
static_cast<CrashReporterChild*>(c);
|
||||
nsDependentCString reason(aReason);
|
||||
crashReporter->SendAnnotateCrashReport(
|
||||
NS_LITERAL_CSTRING("ipc_channel_error"),
|
||||
reason);
|
||||
}
|
||||
nsDependentCString reason(aReason);
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ipc_channel_error"), reason);
|
||||
#endif
|
||||
MOZ_CRASH("Content child abort due to IPC error");
|
||||
}
|
||||
|
|
|
@ -188,13 +188,6 @@ public:
|
|||
|
||||
virtual bool DeallocPBlobChild(PBlobChild* aActor) override;
|
||||
|
||||
virtual PCrashReporterChild*
|
||||
AllocPCrashReporterChild(const mozilla::dom::NativeThreadId& id,
|
||||
const uint32_t& processType) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPCrashReporterChild(PCrashReporterChild*) override;
|
||||
|
||||
virtual PHalChild* AllocPHalChild() override;
|
||||
virtual bool DeallocPHalChild(PHalChild*) override;
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
#include "mozilla/a11y/PDocAccessible.h"
|
||||
#include "AudioChannelService.h"
|
||||
#include "CrashReporterParent.h"
|
||||
#include "DeviceStorageStatics.h"
|
||||
#include "GMPServiceParent.h"
|
||||
#include "HandlerServiceParent.h"
|
||||
|
@ -95,6 +94,7 @@
|
|||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TelemetryIPC.h"
|
||||
#include "mozilla/WebBrowserPersistDocumentParent.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsAnonymousTemporaryFile.h"
|
||||
|
@ -247,6 +247,7 @@
|
|||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsThread.h"
|
||||
#include "mozilla/ipc/CrashReporterHost.h"
|
||||
#endif
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
|
@ -1592,17 +1593,17 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
|
|||
// There's a window in which child processes can crash
|
||||
// after IPC is established, but before a crash reporter
|
||||
// is created.
|
||||
if (PCrashReporterParent* p = LoneManagedOrNullAsserts(ManagedPCrashReporterParent())) {
|
||||
CrashReporterParent* crashReporter =
|
||||
static_cast<CrashReporterParent*>(p);
|
||||
|
||||
if (mCrashReporter) {
|
||||
// if mCreatedPairedMinidumps is true, we've already generated
|
||||
// parent/child dumps for dekstop crashes.
|
||||
// parent/child dumps for desktop crashes.
|
||||
if (!mCreatedPairedMinidumps) {
|
||||
crashReporter->GenerateCrashReport(this, nullptr);
|
||||
mCrashReporter->GenerateCrashReport(OtherPid());
|
||||
}
|
||||
|
||||
nsAutoString dumpID(crashReporter->ChildDumpID());
|
||||
nsAutoString dumpID;
|
||||
if (mCrashReporter->HasMinidump()) {
|
||||
dumpID = mCrashReporter->MinidumpID();
|
||||
}
|
||||
props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID);
|
||||
}
|
||||
#endif
|
||||
|
@ -2816,25 +2817,28 @@ ContentParent::KillHard(const char* aReason)
|
|||
// We're about to kill the child process associated with this content.
|
||||
// Something has gone wrong to get us here, so we generate a minidump
|
||||
// of the parent and child for submission to the crash server.
|
||||
if (PCrashReporterParent* p = LoneManagedOrNullAsserts(ManagedPCrashReporterParent())) {
|
||||
CrashReporterParent* crashReporter =
|
||||
static_cast<CrashReporterParent*>(p);
|
||||
if (mCrashReporter) {
|
||||
// GeneratePairedMinidump creates two minidumps for us - the main
|
||||
// one is for the content process we're about to kill, and the other
|
||||
// one is for the main browser process. That second one is the extra
|
||||
// minidump tagging along, so we have to tell the crash reporter that
|
||||
// it exists and is being appended.
|
||||
nsAutoCString additionalDumps("browser");
|
||||
crashReporter->AnnotateCrashReport(
|
||||
mCrashReporter->AddNote(
|
||||
NS_LITERAL_CSTRING("additional_minidumps"),
|
||||
additionalDumps);
|
||||
nsDependentCString reason(aReason);
|
||||
crashReporter->AnnotateCrashReport(
|
||||
mCrashReporter->AddNote(
|
||||
NS_LITERAL_CSTRING("ipc_channel_error"),
|
||||
reason);
|
||||
|
||||
// Generate the report and insert into the queue for submittal.
|
||||
mCreatedPairedMinidumps = crashReporter->GenerateCompleteMinidump(this);
|
||||
if (mCrashReporter->GenerateMinidumpAndPair(this,
|
||||
nullptr,
|
||||
NS_LITERAL_CSTRING("browser")))
|
||||
{
|
||||
mCreatedPairedMinidumps = mCrashReporter->FinalizeCrashReport();
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1);
|
||||
}
|
||||
|
@ -2873,33 +2877,18 @@ ContentParent::FriendlyName(nsAString& aName, bool aAnonymize)
|
|||
}
|
||||
}
|
||||
|
||||
PCrashReporterParent*
|
||||
ContentParent::AllocPCrashReporterParent(const NativeThreadId& tid,
|
||||
const uint32_t& processType)
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvInitCrashReporter(Shmem&& aShmem, const NativeThreadId& aThreadId)
|
||||
{
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
return new CrashReporterParent();
|
||||
#else
|
||||
return nullptr;
|
||||
mCrashReporter = MakeUnique<CrashReporterHost>(
|
||||
GeckoProcessType_Content,
|
||||
aShmem,
|
||||
aThreadId);
|
||||
#endif
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvPCrashReporterConstructor(PCrashReporterParent* actor,
|
||||
const NativeThreadId& tid,
|
||||
const uint32_t& processType)
|
||||
{
|
||||
static_cast<CrashReporterParent*>(actor)->SetChildData(tid, processType);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPCrashReporterParent(PCrashReporterParent* crashreporter)
|
||||
{
|
||||
delete crashreporter;
|
||||
return true;
|
||||
}
|
||||
|
||||
hal_sandbox::PHalParent*
|
||||
ContentParent::AllocPHalParent()
|
||||
{
|
||||
|
@ -4888,18 +4877,18 @@ ContentParent::ForceTabPaint(TabParent* aTabParent, uint64_t aLayerObserverEpoch
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvAccumulateChildHistogram(
|
||||
ContentParent::RecvAccumulateChildHistograms(
|
||||
InfallibleTArray<Accumulation>&& aAccumulations)
|
||||
{
|
||||
Telemetry::AccumulateChild(GeckoProcessType_Content, aAccumulations);
|
||||
TelemetryIPC::AccumulateChildHistograms(GeckoProcessType_Content, aAccumulations);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentParent::RecvAccumulateChildKeyedHistogram(
|
||||
ContentParent::RecvAccumulateChildKeyedHistograms(
|
||||
InfallibleTArray<KeyedAccumulation>&& aAccumulations)
|
||||
{
|
||||
Telemetry::AccumulateChildKeyed(GeckoProcessType_Content, aAccumulations);
|
||||
TelemetryIPC::AccumulateChildKeyedHistograms(GeckoProcessType_Content, aAccumulations);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -4907,7 +4896,7 @@ mozilla::ipc::IPCResult
|
|||
ContentParent::RecvUpdateChildScalars(
|
||||
InfallibleTArray<ScalarAction>&& aScalarActions)
|
||||
{
|
||||
Telemetry::UpdateChildScalars(GeckoProcessType_Content, aScalarActions);
|
||||
TelemetryIPC::UpdateChildScalars(GeckoProcessType_Content, aScalarActions);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -4915,7 +4904,7 @@ mozilla::ipc::IPCResult
|
|||
ContentParent::RecvUpdateChildKeyedScalars(
|
||||
InfallibleTArray<KeyedScalarAction>&& aScalarActions)
|
||||
{
|
||||
Telemetry::UpdateChildKeyedScalars(GeckoProcessType_Content, aScalarActions);
|
||||
TelemetryIPC::UpdateChildKeyedScalars(GeckoProcessType_Content, aScalarActions);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ class OptionalURIParams;
|
|||
class PFileDescriptorSetParent;
|
||||
class URIParams;
|
||||
class TestShellParent;
|
||||
class CrashReporterHost;
|
||||
} // namespace ipc
|
||||
|
||||
namespace jsipc {
|
||||
|
@ -402,14 +403,8 @@ public:
|
|||
|
||||
virtual void OnChannelError() override;
|
||||
|
||||
virtual PCrashReporterParent*
|
||||
AllocPCrashReporterParent(const NativeThreadId& tid,
|
||||
const uint32_t& processType) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvPCrashReporterConstructor(PCrashReporterParent* actor,
|
||||
const NativeThreadId& tid,
|
||||
const uint32_t& processType) override;
|
||||
RecvInitCrashReporter(Shmem&& aShmem, const NativeThreadId& aThreadId) override;
|
||||
|
||||
virtual PNeckoParent* AllocPNeckoParent() override;
|
||||
|
||||
|
@ -796,9 +791,6 @@ private:
|
|||
RecvPBlobConstructor(PBlobParent* aActor,
|
||||
const BlobConstructorParams& params) override;
|
||||
|
||||
virtual bool
|
||||
DeallocPCrashReporterParent(PCrashReporterParent* crashreporter) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvNSSU2FTokenIsCompatibleVersion(const nsString& aVersion,
|
||||
bool* aIsCompatible) override;
|
||||
|
||||
|
@ -1113,9 +1105,9 @@ private:
|
|||
const int64_t& aLastModified,
|
||||
const bool& aIsFromNsIFile) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvAccumulateChildHistogram(
|
||||
virtual mozilla::ipc::IPCResult RecvAccumulateChildHistograms(
|
||||
InfallibleTArray<Accumulation>&& aAccumulations) override;
|
||||
virtual mozilla::ipc::IPCResult RecvAccumulateChildKeyedHistogram(
|
||||
virtual mozilla::ipc::IPCResult RecvAccumulateChildKeyedHistograms(
|
||||
InfallibleTArray<KeyedAccumulation>&& aAccumulations) override;
|
||||
virtual mozilla::ipc::IPCResult RecvUpdateChildScalars(
|
||||
InfallibleTArray<ScalarAction>&& aScalarActions) override;
|
||||
|
@ -1175,8 +1167,6 @@ private:
|
|||
bool mShutdownPending;
|
||||
bool mIPCOpen;
|
||||
|
||||
friend class CrashReporterParent;
|
||||
|
||||
RefPtr<nsConsoleService> mConsoleService;
|
||||
nsConsoleService* GetConsoleService();
|
||||
|
||||
|
@ -1213,6 +1203,9 @@ private:
|
|||
nsRefPtrHashtable<nsIDHashKey, GetFilesHelper> mGetFilesPendingRequests;
|
||||
|
||||
nsTArray<nsCString> mBlobURLs;
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
UniquePtr<mozilla::ipc::CrashReporterHost> mCrashReporter;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -17,20 +17,7 @@ namespace dom {
|
|||
PCrashReporterChild*
|
||||
CrashReporterChild::GetCrashReporter()
|
||||
{
|
||||
const ManagedContainer<PCrashReporterChild>* reporters = nullptr;
|
||||
switch (XRE_GetProcessType()) {
|
||||
case GeckoProcessType_Content: {
|
||||
ContentChild* child = ContentChild::GetSingleton();
|
||||
reporters = &child->ManagedPCrashReporterChild();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!reporters) {
|
||||
return nullptr;
|
||||
}
|
||||
return LoneManagedOrNullAsserts(*reporters);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "nsIFile.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileBlobImpl.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
|
@ -105,7 +105,7 @@ FilePickerParent::IORunnable::Run()
|
|||
continue;
|
||||
}
|
||||
|
||||
RefPtr<BlobImpl> blobImpl = new BlobImplFile(mFiles[i]);
|
||||
RefPtr<BlobImpl> blobImpl = new FileBlobImpl(mFiles[i]);
|
||||
|
||||
ErrorResult error;
|
||||
blobImpl->GetSize(error);
|
||||
|
|
|
@ -11,7 +11,6 @@ include protocol PCompositorBridge;
|
|||
include protocol PContentBridge;
|
||||
include protocol PContentPermissionRequest;
|
||||
include protocol PCycleCollectWithLogs;
|
||||
include protocol PCrashReporter;
|
||||
include protocol PPSMContentDownloader;
|
||||
include protocol PExternalHelperApp;
|
||||
include protocol PHandlerService;
|
||||
|
@ -383,7 +382,6 @@ nested(upto inside_cpow) sync protocol PContent
|
|||
manages PBlob;
|
||||
manages PBrowser;
|
||||
manages PContentPermissionRequest;
|
||||
manages PCrashReporter;
|
||||
manages PCycleCollectWithLogs;
|
||||
manages PDeviceStorageRequest;
|
||||
manages PPSMContentDownloader;
|
||||
|
@ -746,7 +744,7 @@ parent:
|
|||
async PRemoteSpellcheckEngine();
|
||||
async PDeviceStorageRequest(DeviceStorageParams params);
|
||||
|
||||
sync PCrashReporter(NativeThreadId tid, uint32_t processType);
|
||||
async InitCrashReporter(Shmem shmem, NativeThreadId tid);
|
||||
|
||||
/**
|
||||
* Is this token compatible with the provided version?
|
||||
|
@ -1181,8 +1179,8 @@ parent:
|
|||
/**
|
||||
* Messages for communicating child Telemetry to the parent process
|
||||
*/
|
||||
async AccumulateChildHistogram(Accumulation[] accumulations);
|
||||
async AccumulateChildKeyedHistogram(KeyedAccumulation[] accumulations);
|
||||
async AccumulateChildHistograms(Accumulation[] accumulations);
|
||||
async AccumulateChildKeyedHistograms(KeyedAccumulation[] accumulations);
|
||||
async UpdateChildScalars(ScalarAction[] updates);
|
||||
async UpdateChildKeyedScalars(KeyedScalarAction[] updates);
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ struct Mapping {
|
|||
};
|
||||
|
||||
async protocol PCrashReporter {
|
||||
manager PContent;
|
||||
parent:
|
||||
async AnnotateCrashReport(nsCString key, nsCString data);
|
||||
async AppendAppNotes(nsCString data);
|
||||
|
|
|
@ -6,37 +6,202 @@
|
|||
* and to access the manifest data (including icons).
|
||||
*
|
||||
* TODO:
|
||||
* - Persist installed manifest data to disk and keep track of which
|
||||
* origins have installed applications
|
||||
* - Trigger appropriate app installed events
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const { ManifestObtainer } =
|
||||
Cu.import('resource://gre/modules/ManifestObtainer.jsm', {});
|
||||
Cu.import("resource://gre/modules/ManifestObtainer.jsm", {});
|
||||
const { ManifestIcons } =
|
||||
Cu.import('resource://gre/modules/ManifestIcons.jsm', {});
|
||||
Cu.import("resource://gre/modules/ManifestIcons.jsm", {});
|
||||
|
||||
function Manifest(browser) {
|
||||
this.browser = browser;
|
||||
this.data = null;
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "JSONFile",
|
||||
"resource://gre/modules/JSONFile.jsm");
|
||||
|
||||
/**
|
||||
* Generates an hash for the given string.
|
||||
*
|
||||
* @note The generated hash is returned in base64 form. Mind the fact base64
|
||||
* is case-sensitive if you are going to reuse this code.
|
||||
*/
|
||||
function generateHash(aString) {
|
||||
const cryptoHash = Cc["@mozilla.org/security/hash;1"]
|
||||
.createInstance(Ci.nsICryptoHash);
|
||||
cryptoHash.init(Ci.nsICryptoHash.MD5);
|
||||
const stringStream = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
stringStream.data = aString;
|
||||
cryptoHash.updateFromStream(stringStream, -1);
|
||||
// base64 allows the '/' char, but we can't use it for filenames.
|
||||
return cryptoHash.finish(true).replace(/\//g, "-");
|
||||
}
|
||||
|
||||
Manifest.prototype.install = Task.async(function* () {
|
||||
this.data = yield ManifestObtainer.browserObtainManifest(this.browser);
|
||||
});
|
||||
|
||||
Manifest.prototype.icon = Task.async(function* (expectedSize) {
|
||||
return yield ManifestIcons.browserFetchIcon(this.browser, this.data, expectedSize);
|
||||
});
|
||||
|
||||
Manifest.prototype.name = function () {
|
||||
return this.data.short_name || this.data.short_url;
|
||||
/**
|
||||
* Trims the query paramters from a url
|
||||
*/
|
||||
function stripQuery(url) {
|
||||
return url.split("?")[0];
|
||||
}
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["Manifest"]; // jshint ignore:line
|
||||
// Folder in which we store the manifest files
|
||||
const MANIFESTS_DIR = OS.Path.join(OS.Constants.Path.profileDir, "manifests");
|
||||
|
||||
// We maintain a list of scopes for installed webmanifests so we can determine
|
||||
// whether a given url is within the scope of a previously installed manifest
|
||||
const MANIFESTS_FILE = "manifest-scopes.json";
|
||||
|
||||
/**
|
||||
* Manifest object
|
||||
*/
|
||||
|
||||
class Manifest {
|
||||
|
||||
constructor(browser, manifestUrl) {
|
||||
this._manifestUrl = manifestUrl;
|
||||
// The key for this is the manifests URL that is required to be unique.
|
||||
// However arbitrary urls are not safe file paths so lets hash it.
|
||||
const fileName = generateHash(manifestUrl) + ".json";
|
||||
this._path = OS.Path.join(MANIFESTS_DIR, fileName);
|
||||
this._browser = browser;
|
||||
}
|
||||
|
||||
async initialise() {
|
||||
this._store = new JSONFile({path: this._path});
|
||||
await this._store.load();
|
||||
}
|
||||
|
||||
async install() {
|
||||
const manifestData = await ManifestObtainer.browserObtainManifest(this._browser);
|
||||
this._store.data = {
|
||||
installed: true,
|
||||
manifest: manifestData
|
||||
};
|
||||
Manifests.manifestInstalled(this);
|
||||
this._store.saveSoon();
|
||||
}
|
||||
|
||||
async icon(expectedSize) {
|
||||
return await ManifestIcons
|
||||
.browserFetchIcon(this._browser, this._store.data.manifest, expectedSize);
|
||||
}
|
||||
|
||||
get scope() {
|
||||
const scope = this._store.data.manifest.scope ||
|
||||
this._store.data.manifest.start_url;
|
||||
return stripQuery(scope);
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this._store.data.manifest.short_name ||
|
||||
this._store.data.manifest.short_url;
|
||||
}
|
||||
|
||||
get url() {
|
||||
return this._manifestUrl;
|
||||
}
|
||||
|
||||
get installed() {
|
||||
return this._store.data && this._store.data.installed || false;
|
||||
}
|
||||
|
||||
get start_url() {
|
||||
return this._store.data.manifest.start_url;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Manifests maintains the list of installed manifests
|
||||
*/
|
||||
var Manifests = {
|
||||
|
||||
async initialise () {
|
||||
|
||||
if (this.started) {
|
||||
return this.started;
|
||||
}
|
||||
|
||||
this.started = (async function() {
|
||||
|
||||
// Make sure the manifests have the folder needed to save into
|
||||
await OS.File.makeDir(MANIFESTS_DIR, {ignoreExisting: true});
|
||||
|
||||
// Ensure any existing scope data we have about manifests is loaded
|
||||
this._path = OS.Path.join(OS.Constants.Path.profileDir, MANIFESTS_FILE);
|
||||
this._store = new JSONFile({path: this._path});
|
||||
await this._store.load();
|
||||
|
||||
// If we dont have any existing data, initialise empty
|
||||
if (!this._store.data.hasOwnProperty("scopes")) {
|
||||
this._store.data.scopes = new Map();
|
||||
}
|
||||
|
||||
// Cache the Manifest objects creates as they are references to files
|
||||
// and we do not want multiple file handles
|
||||
this.manifestObjs = {};
|
||||
|
||||
}).bind(this)();
|
||||
|
||||
return this.started;
|
||||
},
|
||||
|
||||
// When a manifest is installed, we save its scope so we can determine if
|
||||
// fiture visits fall within this manifests scope
|
||||
manifestInstalled(manifest) {
|
||||
this._store.data.scopes[manifest.scope] = manifest.url;
|
||||
this._store.saveSoon();
|
||||
},
|
||||
|
||||
// Given a url, find if it is within an installed manifests scope and if so
|
||||
// return that manifests url
|
||||
findManifestUrl(url) {
|
||||
for (let scope in this._store.data.scopes) {
|
||||
if (url.startsWith(scope)) {
|
||||
return this._store.data.scopes[scope];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
// Get the manifest given a url, or if not look for a manifest that is
|
||||
// tied to the current page
|
||||
async getManifest(browser, manifestUrl) {
|
||||
|
||||
// Ensure we have all started up
|
||||
await this.initialise();
|
||||
|
||||
// If the client does not already know its manifestUrl, we take the
|
||||
// url of the client and see if it matches the scope of any installed
|
||||
// manifests
|
||||
if (!manifestUrl) {
|
||||
const url = stripQuery(browser.currentURI.spec);
|
||||
manifestUrl = this.findManifestUrl(url);
|
||||
}
|
||||
|
||||
// No matches so no manifest
|
||||
if (manifestUrl === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If we have already created this manifest return cached
|
||||
if (manifestUrl in this.manifestObjs) {
|
||||
return this.manifestObjs[manifestUrl];
|
||||
}
|
||||
|
||||
// Otherwise create a new manifest object
|
||||
this.manifestObjs[manifestUrl] = new Manifest(browser, manifestUrl);
|
||||
await this.manifestObjs[manifestUrl].initialise();
|
||||
return this.manifestObjs[manifestUrl];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["Manifests"]; // jshint ignore:line
|
||||
|
|
|
@ -6,6 +6,7 @@ support-files =
|
|||
resource.sjs
|
||||
red-50.png
|
||||
blue-150.png
|
||||
[browser_Manifest_install.js]
|
||||
[browser_ManifestFinder_browserHasManifestLink.js]
|
||||
[browser_ManifestIcons_browserFetchIcon.js]
|
||||
[browser_ManifestObtainer_obtain.js]
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
//Used by JSHint:
|
||||
/*global Cu, BrowserTestUtils, ok, add_task, gBrowser */
|
||||
"use strict";
|
||||
|
||||
const { Manifests } = Cu.import("resource://gre/modules/Manifest.jsm", {});
|
||||
|
||||
const defaultURL = new URL("http://example.org/browser/dom/manifest/test/resource.sjs");
|
||||
defaultURL.searchParams.set("Content-Type", "application/manifest+json");
|
||||
|
||||
const manifest = JSON.stringify({short_name: "hello World", scope: "/browser/"});
|
||||
const manifestUrl = `${defaultURL}&body=${manifest}`;
|
||||
|
||||
function makeTestURL(manifest) {
|
||||
const url = new URL(defaultURL);
|
||||
const body = `<link rel="manifest" href='${manifestUrl}'>`;
|
||||
url.searchParams.set("Content-Type", "text/html; charset=utf-8");
|
||||
url.searchParams.set("body", encodeURIComponent(body));
|
||||
return url.href;
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
|
||||
const tabOptions = {gBrowser, url: makeTestURL(manifest)};
|
||||
|
||||
yield BrowserTestUtils.withNewTab(tabOptions, function*(browser) {
|
||||
|
||||
let manifest = yield Manifests.getManifest(browser, manifestUrl);
|
||||
is(manifest.installed, false, "We havent installed this manifest yet");
|
||||
|
||||
yield manifest.install(browser);
|
||||
is(manifest.name, "hello World", "Manifest has correct name");
|
||||
is(manifest.installed, true, "Manifest is installed");
|
||||
is(manifest.url, manifestUrl, "has correct url");
|
||||
|
||||
manifest = yield Manifests.getManifest(browser, manifestUrl);
|
||||
is(manifest.installed, true, "New instances are installed");
|
||||
|
||||
manifest = yield Manifests.getManifest(browser);
|
||||
is(manifest.installed, true, "Will find manifest without being given url");
|
||||
|
||||
let foundManifest = Manifests.findManifestUrl("http://example.org/browser/dom/");
|
||||
is(foundManifest, manifestUrl, "Finds manifests within scope");
|
||||
|
||||
foundManifest = Manifests.findManifestUrl("http://example.org/");
|
||||
is(foundManifest, null, "Does not find manifests outside scope");
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -73,8 +73,9 @@ transferSimulcastProperties: function(offer_sdp, answer_sdp) {
|
|||
o_rids.forEach((o_rid) => {
|
||||
new_answer_sdp = new_answer_sdp + o_rid.replace(/send/, "recv") + "\r\n";
|
||||
});
|
||||
ok(offer_sdp.includes("a=extmap:1/sendonly urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id"), "Offer contains RID RTP header extension");
|
||||
new_answer_sdp = new_answer_sdp + "a=extmap:1/recvonly urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\n";
|
||||
var extmap_id = offer_sdp.match("a=extmap:([0-9+])/sendonly urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id");
|
||||
ok(extmap_id != null, "Offer contains RID RTP header extension");
|
||||
new_answer_sdp = new_answer_sdp + "a=extmap:" + extmap_id[1] + "/recvonly urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\n";
|
||||
return new_answer_sdp;
|
||||
},
|
||||
|
||||
|
|
|
@ -26,7 +26,10 @@
|
|||
|
||||
runNetworkTest(() =>
|
||||
pushPrefs(['media.peerconnection.simulcast', true],
|
||||
['media.peerconnection.video.min_bitrate_estimate', 100*1000]).then(() => {
|
||||
// 180Kbps was determined empirically, set well-higher than
|
||||
// the 80Kbps+overhead needed for the two simulcast streams.
|
||||
// 100Kbps was apparently too low.
|
||||
['media.peerconnection.video.min_bitrate_estimate', 180*1000]).then(() => {
|
||||
SimpleTest.requestCompleteLog();
|
||||
var helper;
|
||||
|
||||
|
|
|
@ -12,10 +12,12 @@
|
|||
#endif
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/dom/BlobBinding.h"
|
||||
#include "mozilla/dom/BlobSet.h"
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
#include "mozilla/dom/DOMString.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/FileBinding.h"
|
||||
#include "mozilla/dom/FileCreatorHelper.h"
|
||||
#include "mozilla/dom/FetchUtil.h"
|
||||
#include "mozilla/dom/FormData.h"
|
||||
|
|
|
@ -31461,7 +31461,7 @@ inventiveness/M
|
|||
inventor/MS
|
||||
inventory/DSMG
|
||||
inverse/SMY
|
||||
invert/SMDG
|
||||
invert/SMDGR
|
||||
invest/ASDGL
|
||||
investigate/GNVDSX
|
||||
investigation/M
|
||||
|
|
10
gfx/2d/2D.h
10
gfx/2d/2D.h
|
@ -32,8 +32,6 @@
|
|||
#include <string>
|
||||
#endif
|
||||
|
||||
#include "gfxPrefs.h"
|
||||
|
||||
struct _cairo_surface;
|
||||
typedef _cairo_surface cairo_surface_t;
|
||||
|
||||
|
@ -720,13 +718,7 @@ public:
|
|||
typedef void (*FontDescriptorOutput)(const uint8_t* aData, uint32_t aLength, Float aFontSize, void* aBaton);
|
||||
|
||||
virtual FontType GetType() const = 0;
|
||||
virtual AntialiasMode GetDefaultAAMode() {
|
||||
if (gfxPrefs::DisableAllTextAA()) {
|
||||
return AntialiasMode::NONE;
|
||||
}
|
||||
|
||||
return AntialiasMode::DEFAULT;
|
||||
}
|
||||
virtual AntialiasMode GetDefaultAAMode();
|
||||
|
||||
/** This allows getting a path that describes the outline of a set of glyphs.
|
||||
* A target is passed in so that the guarantee is made the returned path
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "ScaledFontBase.h"
|
||||
|
||||
#include "gfxPrefs.h"
|
||||
|
||||
#ifdef USE_SKIA
|
||||
#include "PathSkia.h"
|
||||
#include "skia/include/core/SkPaint.h"
|
||||
|
@ -24,6 +26,16 @@ using namespace std;
|
|||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
AntialiasMode
|
||||
ScaledFont::GetDefaultAAMode()
|
||||
{
|
||||
if (gfxPrefs::DisableAllTextAA()) {
|
||||
return AntialiasMode::NONE;
|
||||
}
|
||||
|
||||
return AntialiasMode::DEFAULT;
|
||||
}
|
||||
|
||||
ScaledFontBase::~ScaledFontBase()
|
||||
{
|
||||
#ifdef USE_SKIA
|
||||
|
@ -253,7 +265,7 @@ ScaledFontBase::SetCairoScaledFont(cairo_scaled_font_t* font)
|
|||
|
||||
if (font == mScaledFont)
|
||||
return;
|
||||
|
||||
|
||||
if (mScaledFont)
|
||||
cairo_scaled_font_destroy(mScaledFont);
|
||||
|
||||
|
|
|
@ -73,9 +73,6 @@ LOCAL_INCLUDES += [
|
|||
if CONFIG['MOZ_USE_PTHREADS']:
|
||||
DEFINES['HAVE_PTHREAD_SETSPECIFIC'] = True
|
||||
|
||||
if CONFIG['_MSC_VER']:
|
||||
DEFINES['PIXMAN_USE_XP_DLL_TLS_WORKAROUND'] = True
|
||||
|
||||
DEFINES['PACKAGE'] = 'mozpixman'
|
||||
|
||||
DEFINES['_USE_MATH_DEFINES'] = True
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "GPUProcessHost.h"
|
||||
#include "GPUProcessManager.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TelemetryIPC.h"
|
||||
#include "mozilla/dom/CheckerboardReportService.h"
|
||||
#include "mozilla/dom/MemoryReportRequest.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
|
@ -144,30 +145,30 @@ GPUChild::RecvNotifyUiObservers(const nsCString& aTopic)
|
|||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GPUChild::RecvAccumulateChildHistogram(InfallibleTArray<Accumulation>&& aAccumulations)
|
||||
GPUChild::RecvAccumulateChildHistograms(InfallibleTArray<Accumulation>&& aAccumulations)
|
||||
{
|
||||
Telemetry::AccumulateChild(GeckoProcessType_GPU, aAccumulations);
|
||||
TelemetryIPC::AccumulateChildHistograms(GeckoProcessType_GPU, aAccumulations);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GPUChild::RecvAccumulateChildKeyedHistogram(InfallibleTArray<KeyedAccumulation>&& aAccumulations)
|
||||
GPUChild::RecvAccumulateChildKeyedHistograms(InfallibleTArray<KeyedAccumulation>&& aAccumulations)
|
||||
{
|
||||
Telemetry::AccumulateChildKeyed(GeckoProcessType_GPU, aAccumulations);
|
||||
TelemetryIPC::AccumulateChildKeyedHistograms(GeckoProcessType_GPU, aAccumulations);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GPUChild::RecvUpdateChildScalars(InfallibleTArray<ScalarAction>&& aScalarActions)
|
||||
{
|
||||
Telemetry::UpdateChildScalars(GeckoProcessType_GPU, aScalarActions);
|
||||
TelemetryIPC::UpdateChildScalars(GeckoProcessType_GPU, aScalarActions);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GPUChild::RecvUpdateChildKeyedScalars(InfallibleTArray<KeyedScalarAction>&& aScalarActions)
|
||||
{
|
||||
Telemetry::UpdateChildKeyedScalars(GeckoProcessType_GPU, aScalarActions);
|
||||
TelemetryIPC::UpdateChildKeyedScalars(GeckoProcessType_GPU, aScalarActions);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
|
|
@ -43,8 +43,8 @@ public:
|
|||
mozilla::ipc::IPCResult RecvInitComplete(const GPUDeviceData& aData) override;
|
||||
mozilla::ipc::IPCResult RecvReportCheckerboard(const uint32_t& aSeverity, const nsCString& aLog) override;
|
||||
mozilla::ipc::IPCResult RecvInitCrashReporter(Shmem&& shmem, const NativeThreadId& aThreadId) override;
|
||||
mozilla::ipc::IPCResult RecvAccumulateChildHistogram(InfallibleTArray<Accumulation>&& aAccumulations) override;
|
||||
mozilla::ipc::IPCResult RecvAccumulateChildKeyedHistogram(InfallibleTArray<KeyedAccumulation>&& aAccumulations) override;
|
||||
mozilla::ipc::IPCResult RecvAccumulateChildHistograms(InfallibleTArray<Accumulation>&& aAccumulations) override;
|
||||
mozilla::ipc::IPCResult RecvAccumulateChildKeyedHistograms(InfallibleTArray<KeyedAccumulation>&& aAccumulations) override;
|
||||
mozilla::ipc::IPCResult RecvUpdateChildScalars(InfallibleTArray<ScalarAction>&& aScalarActions) override;
|
||||
mozilla::ipc::IPCResult RecvUpdateChildKeyedScalars(InfallibleTArray<KeyedScalarAction>&& aScalarActions) override;
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
|
|
@ -110,8 +110,8 @@ child:
|
|||
async NotifyUiObservers(nsCString aTopic);
|
||||
|
||||
// Messages for reporting telemetry to the UI process.
|
||||
async AccumulateChildHistogram(Accumulation[] accumulations);
|
||||
async AccumulateChildKeyedHistogram(KeyedAccumulation[] accumulations);
|
||||
async AccumulateChildHistograms(Accumulation[] accumulations);
|
||||
async AccumulateChildKeyedHistograms(KeyedAccumulation[] accumulations);
|
||||
async UpdateChildScalars(ScalarAction[] actions);
|
||||
async UpdateChildKeyedScalars(KeyedScalarAction[] actions);
|
||||
|
||||
|
|
|
@ -383,6 +383,7 @@ private:
|
|||
DECL_GFX_PREF(Once, "gfx.direct2d.force-enabled", Direct2DForceEnabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "gfx.direct3d11.reuse-decoder-device", Direct3D11ReuseDecoderDevice, int32_t, -1);
|
||||
DECL_GFX_PREF(Live, "gfx.direct3d11.allow-intel-mutex", Direct3D11AllowIntelMutex, bool, true);
|
||||
DECL_GFX_PREF(Live, "gfx.downloadable_fonts.otl_validation", ValidateOTLTables, bool, true);
|
||||
DECL_GFX_PREF(Live, "gfx.draw-color-bars", CompositorDrawColorBars, bool, false);
|
||||
DECL_GFX_PREF(Once, "gfx.e10s.hide-plugins-for-scroll", HidePluginsForScroll, bool, true);
|
||||
DECL_GFX_PREF(Live, "gfx.layerscope.enabled", LayerScopeEnabled, bool, false);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "gfxUserFontSet.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
@ -176,17 +177,19 @@ gfxUserFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle, bool aNeeds
|
|||
class gfxOTSContext : public ots::OTSContext {
|
||||
public:
|
||||
explicit gfxOTSContext(gfxUserFontEntry* aUserFontEntry)
|
||||
: mUserFontEntry(aUserFontEntry) {}
|
||||
: mUserFontEntry(aUserFontEntry)
|
||||
{
|
||||
// Whether to apply OTS validation to OpenType Layout tables
|
||||
mCheckOTLTables = gfxPrefs::ValidateOTLTables();
|
||||
}
|
||||
|
||||
virtual ots::TableAction GetTableAction(uint32_t aTag) override {
|
||||
// Preserve Graphite, color glyph and SVG tables
|
||||
if (
|
||||
#ifdef RELEASE_OR_BETA // For Beta/Release, also allow OT Layout tables through
|
||||
// unchecked, and rely on harfbuzz to handle them safely.
|
||||
aTag == TRUETYPE_TAG('G', 'D', 'E', 'F') ||
|
||||
aTag == TRUETYPE_TAG('G', 'P', 'O', 'S') ||
|
||||
aTag == TRUETYPE_TAG('G', 'S', 'U', 'B') ||
|
||||
#endif
|
||||
// Preserve Graphite, color glyph and SVG tables,
|
||||
// and possibly OTL tables (depending on pref)
|
||||
if ((!mCheckOTLTables &&
|
||||
(aTag == TRUETYPE_TAG('G', 'D', 'E', 'F') ||
|
||||
aTag == TRUETYPE_TAG('G', 'P', 'O', 'S') ||
|
||||
aTag == TRUETYPE_TAG('G', 'S', 'U', 'B'))) ||
|
||||
aTag == TRUETYPE_TAG('S', 'i', 'l', 'f') ||
|
||||
aTag == TRUETYPE_TAG('S', 'i', 'l', 'l') ||
|
||||
aTag == TRUETYPE_TAG('G', 'l', 'o', 'c') ||
|
||||
|
@ -225,6 +228,7 @@ public:
|
|||
private:
|
||||
gfxUserFontEntry* mUserFontEntry;
|
||||
nsTHashtable<nsCStringHashKey> mWarningsIssued;
|
||||
bool mCheckOTLTables;
|
||||
};
|
||||
|
||||
// Call the OTS library to sanitize an sfnt before attempting to use it.
|
||||
|
|
|
@ -507,7 +507,7 @@ bool Pickle::WriteBytes(const void* data, uint32_t data_len, uint32_t alignment)
|
|||
}
|
||||
|
||||
bool Pickle::WriteString(const std::string& value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
std::string v(value);
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzString(v);
|
||||
if (!WriteInt(static_cast<int>(v.size())))
|
||||
|
@ -523,7 +523,7 @@ bool Pickle::WriteString(const std::string& value) {
|
|||
}
|
||||
|
||||
bool Pickle::WriteWString(const std::wstring& value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
std::wstring v(value);
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzWString(v);
|
||||
if (!WriteInt(static_cast<int>(v.size())))
|
||||
|
@ -541,7 +541,7 @@ bool Pickle::WriteWString(const std::wstring& value) {
|
|||
}
|
||||
|
||||
bool Pickle::WriteData(const char* data, uint32_t length) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
std::string v(data, length);
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzData(v, v.size());
|
||||
return WriteInt(v.size()) && WriteBytes(v.data(), v.size());
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "mozilla/BufferList.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
#include "base/singleton.h"
|
||||
#include "mozilla/ipc/Faulty.h"
|
||||
#endif
|
||||
|
@ -134,25 +134,25 @@ class Pickle {
|
|||
// Pickle, it is important to read them in the order in which they were added
|
||||
// to the Pickle.
|
||||
bool WriteBool(bool value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzBool(&value);
|
||||
#endif
|
||||
return WriteInt(value ? 1 : 0);
|
||||
}
|
||||
bool WriteInt16(int16_t value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzInt16(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteUInt16(uint16_t value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt16(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteInt(int value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzInt(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
|
@ -160,7 +160,7 @@ class Pickle {
|
|||
bool WriteLong(long value) {
|
||||
// Always written as a 64-bit value since the size for this type can
|
||||
// differ between architectures.
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzLong(&value);
|
||||
#endif
|
||||
return WriteInt64(int64_t(value));
|
||||
|
@ -168,7 +168,7 @@ class Pickle {
|
|||
bool WriteULong(unsigned long value) {
|
||||
// Always written as a 64-bit value since the size for this type can
|
||||
// differ between architectures.
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzULong(&value);
|
||||
#endif
|
||||
return WriteUInt64(uint64_t(value));
|
||||
|
@ -176,37 +176,37 @@ class Pickle {
|
|||
bool WriteSize(size_t value) {
|
||||
// Always written as a 64-bit value since the size for this type can
|
||||
// differ between architectures.
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzSize(&value);
|
||||
#endif
|
||||
return WriteUInt64(uint64_t(value));
|
||||
}
|
||||
bool WriteInt32(int32_t value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzInt(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteUInt32(uint32_t value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt32(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteInt64(int64_t value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzInt64(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteUInt64(uint64_t value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt64(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteDouble(double value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzDouble(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
|
@ -217,7 +217,7 @@ class Pickle {
|
|||
return WriteInt64(int64_t(value));
|
||||
}
|
||||
bool WriteUnsignedChar(unsigned char value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzUChar(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
#include "mozilla/ipc/Faulty.h"
|
||||
#endif
|
||||
|
||||
|
@ -583,7 +583,7 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
|||
// Write out all the messages we can till the write blocks or there are no
|
||||
// more outgoing messages.
|
||||
while (!output_queue_.empty()) {
|
||||
#ifdef MOZ_FAULTY
|
||||
#ifdef FUZZING
|
||||
Singleton<mozilla::ipc::Faulty>::get()->MaybeCollectAndClosePipe(pipe_);
|
||||
#endif
|
||||
Message* msg = output_queue_.front();
|
||||
|
|
|
@ -3,17 +3,19 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "mozilla/ipc/Faulty.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <prinrval.h>
|
||||
#include "nsXULAppAPI.h"
|
||||
#include <unistd.h>
|
||||
#include "base/string_util.h"
|
||||
#include "chrome/common/ipc_message.h"
|
||||
#include "chrome/common/ipc_channel.h"
|
||||
#include "prenv.h"
|
||||
#include "mozilla/ipc/Faulty.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include <cmath>
|
||||
#include <climits>
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "prenv.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "nsMultiplexInputStream.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsTemporaryFileInputStream.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
|
|
@ -421,7 +421,7 @@ LoggingEnabled()
|
|||
inline bool
|
||||
LoggingEnabledFor(const char *aTopLevelProtocol)
|
||||
{
|
||||
#if defined(DEBUG)
|
||||
#if defined(DEBUG) || defined(FUZZING)
|
||||
const char *filter = PR_GetEnv("MOZ_IPC_MESSAGE_LOG");
|
||||
if (!filter) {
|
||||
return false;
|
||||
|
|
|
@ -45,7 +45,7 @@ EXPORTS.mozilla.ipc += [
|
|||
'WindowsMessageLoop.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_FAULTY'] == '1':
|
||||
if CONFIG['FUZZING'] == '1':
|
||||
EXPORTS.mozilla.ipc += ['Faulty.h']
|
||||
SOURCES += ['Faulty.cpp']
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_mscom_Aggregation_h
|
||||
#define mozilla_mscom_Aggregation_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace mscom {
|
||||
|
||||
/**
|
||||
* This is used for stabilizing a COM object's reference count during
|
||||
* construction when that object aggregates other objects. Since the aggregated
|
||||
* object(s) may AddRef() or Release(), we need to artifically boost the
|
||||
* refcount to prevent premature destruction. Note that we increment/decrement
|
||||
* instead of AddRef()/Release() in this class because we want to adjust the
|
||||
* refcount without causing any other side effects (like object destruction).
|
||||
*/
|
||||
template <typename RefCntT>
|
||||
class MOZ_RAII StabilizedRefCount
|
||||
{
|
||||
public:
|
||||
explicit StabilizedRefCount(RefCntT& aRefCnt)
|
||||
: mRefCnt(aRefCnt)
|
||||
{
|
||||
++aRefCnt;
|
||||
}
|
||||
|
||||
~StabilizedRefCount()
|
||||
{
|
||||
--mRefCnt;
|
||||
}
|
||||
|
||||
StabilizedRefCount(const StabilizedRefCount&) = delete;
|
||||
StabilizedRefCount(StabilizedRefCount&&) = delete;
|
||||
StabilizedRefCount& operator=(const StabilizedRefCount&) = delete;
|
||||
StabilizedRefCount& operator=(StabilizedRefCount&&) = delete;
|
||||
|
||||
private:
|
||||
RefCntT& mRefCnt;
|
||||
};
|
||||
|
||||
} // namespace mscom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_mscom_Aggregation_h
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_mscom_AsyncInvoker_h
|
||||
#define mozilla_mscom_AsyncInvoker_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/mscom/Aggregation.h"
|
||||
#include "mozilla/mscom/Utils.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
#include <objidl.h>
|
||||
#include <windows.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace mscom {
|
||||
namespace detail {
|
||||
|
||||
template <typename AsyncInterface>
|
||||
class ForgettableAsyncCall : public ISynchronize
|
||||
{
|
||||
public:
|
||||
explicit ForgettableAsyncCall(ICallFactory* aCallFactory)
|
||||
: mRefCnt(0)
|
||||
, mAsyncCall(nullptr)
|
||||
{
|
||||
StabilizedRefCount<Atomic<ULONG>> stabilizer(mRefCnt);
|
||||
|
||||
HRESULT hr =
|
||||
aCallFactory->CreateCall(__uuidof(AsyncInterface), this,
|
||||
IID_IUnknown, getter_AddRefs(mInnerUnk));
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
hr = mInnerUnk->QueryInterface(__uuidof(AsyncInterface),
|
||||
reinterpret_cast<void**>(&mAsyncCall));
|
||||
if (SUCCEEDED(hr)) {
|
||||
// Don't hang onto a ref. Because mAsyncCall is aggregated, its refcount
|
||||
// is this->mRefCnt, so we'd create a cycle!
|
||||
mAsyncCall->Release();
|
||||
}
|
||||
}
|
||||
|
||||
AsyncInterface* GetInterface() const
|
||||
{
|
||||
return mAsyncCall;
|
||||
}
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID aIid, void** aOutInterface) override
|
||||
{
|
||||
if (aIid == IID_IUnknown || aIid == IID_ISynchronize) {
|
||||
RefPtr<ISynchronize> ptr(this);
|
||||
ptr.forget(aOutInterface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return mInnerUnk->QueryInterface(aIid, aOutInterface);
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) AddRef() override
|
||||
{
|
||||
ULONG result = ++mRefCnt;
|
||||
NS_LOG_ADDREF(this, result, "ForgettableAsyncCall", sizeof(*this));
|
||||
return result;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) Release() override
|
||||
{
|
||||
ULONG result = --mRefCnt;
|
||||
NS_LOG_RELEASE(this, result, "ForgettableAsyncCall");
|
||||
if (!result) {
|
||||
delete this;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ISynchronize
|
||||
STDMETHODIMP Wait(DWORD aFlags, DWORD aTimeoutMilliseconds) override
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
STDMETHODIMP Signal() override
|
||||
{
|
||||
// Even though this function is a no-op, we must return S_OK as opposed to
|
||||
// E_NOTIMPL or else COM will consider the async call to have failed.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP Reset() override
|
||||
{
|
||||
// Even though this function is a no-op, we must return S_OK as opposed to
|
||||
// E_NOTIMPL or else COM will consider the async call to have failed.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~ForgettableAsyncCall() {}
|
||||
|
||||
private:
|
||||
Atomic<ULONG> mRefCnt;
|
||||
RefPtr<IUnknown> mInnerUnk;
|
||||
AsyncInterface* mAsyncCall; // weak reference
|
||||
};
|
||||
|
||||
template <typename AsyncInterface>
|
||||
class WaitableAsyncCall : public ForgettableAsyncCall<AsyncInterface>
|
||||
{
|
||||
public:
|
||||
explicit WaitableAsyncCall(ICallFactory* aCallFactory)
|
||||
: ForgettableAsyncCall(aCallFactory)
|
||||
, mEvent(::CreateEventW(nullptr, FALSE, FALSE, nullptr))
|
||||
{
|
||||
}
|
||||
|
||||
STDMETHODIMP Wait(DWORD aFlags, DWORD aTimeoutMilliseconds) override
|
||||
{
|
||||
const DWORD waitStart = aTimeoutMilliseconds == INFINITE ? 0 :
|
||||
::GetTickCount();
|
||||
DWORD flags = aFlags;
|
||||
if (XRE_IsContentProcess() && NS_IsMainThread()) {
|
||||
flags |= COWAIT_ALERTABLE;
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
DWORD signaledIdx;
|
||||
|
||||
DWORD elapsed = 0;
|
||||
|
||||
while (true) {
|
||||
if (aTimeoutMilliseconds != INFINITE) {
|
||||
elapsed = ::GetTickCount() - waitStart;
|
||||
}
|
||||
if (elapsed >= aTimeoutMilliseconds) {
|
||||
return RPC_S_CALLPENDING;
|
||||
}
|
||||
|
||||
::SetLastError(ERROR_SUCCESS);
|
||||
|
||||
hr = ::CoWaitForMultipleHandles(flags, aTimeoutMilliseconds - elapsed, 1,
|
||||
&mEvent, &signaledIdx);
|
||||
if (hr == RPC_S_CALLPENDING || FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (hr == S_OK && signaledIdx == 0) {
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP Signal() override
|
||||
{
|
||||
if (!::SetEvent(mEvent)) {
|
||||
return HRESULT_FROM_WIN32(::GetLastError());
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
~WaitableAsyncCall()
|
||||
{
|
||||
if (mEvent) {
|
||||
::CloseHandle(mEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE mEvent;
|
||||
};
|
||||
|
||||
template <typename AsyncInterface>
|
||||
class FireAndForgetInvoker
|
||||
{
|
||||
protected:
|
||||
typedef ForgettableAsyncCall<AsyncInterface> AsyncCallType;
|
||||
|
||||
RefPtr<ForgettableAsyncCall<AsyncInterface>> mAsyncCall;
|
||||
};
|
||||
|
||||
template <typename AsyncInterface>
|
||||
class WaitableInvoker
|
||||
{
|
||||
public:
|
||||
HRESULT Wait(DWORD aTimeout = INFINITE) const
|
||||
{
|
||||
if (!mAsyncCall) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
return mAsyncCall->Wait(0, aTimeout);
|
||||
}
|
||||
|
||||
protected:
|
||||
typedef WaitableAsyncCall<AsyncInterface> AsyncCallType;
|
||||
|
||||
RefPtr<WaitableAsyncCall<AsyncInterface>> mAsyncCall;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* This class is intended for "fire-and-forget" asynchronous invocations of COM
|
||||
* interfaces. This requires that an interface be annotated with the
|
||||
* |async_uuid| attribute in midl.
|
||||
*
|
||||
* For example, let us suppose we have some IDL as such:
|
||||
* [object, uuid(...), async_uuid(...)]
|
||||
* interface IFoo : IUnknown
|
||||
* {
|
||||
* HRESULT Bar(long baz);
|
||||
* }
|
||||
*
|
||||
* Then, given an IFoo, we may construct an AsyncInvoker<AsyncIFoo>:
|
||||
*
|
||||
* IFoo* foo = ...;
|
||||
* AsyncInvoker<AsyncIFoo> myInvoker(foo);
|
||||
* HRESULT hr = myInvoker->Begin_Bar(7);
|
||||
*
|
||||
* Alternatively you may use the ASYNC_INVOKER_FOR macro, which automatically
|
||||
* derives the name of the asynchronous interface from the name of the
|
||||
* synchronous interface:
|
||||
*
|
||||
* ASYNC_INVOKER_FOR(IFoo) myInvoker(foo);
|
||||
*
|
||||
* This class may also be used when a synchronous COM call must be made that
|
||||
* might reenter the content process. In this case, use the WaitableAsyncInvoker
|
||||
* variant, or the WAITABLE_ASYNC_INVOKER_FOR macro:
|
||||
*
|
||||
* WAITABLE_ASYNC_INVOKER_FOR(Ifoo) myInvoker(foo);
|
||||
* myInvoker->Begin_Bar(7);
|
||||
* myInvoker.Wait(); // <-- Wait for the COM call to complete.
|
||||
*
|
||||
* In general you should avoid using the waitable version, but in some corner
|
||||
* cases it is absolutely necessary in order to preserve correctness while
|
||||
* avoiding deadlock.
|
||||
*/
|
||||
template <typename AsyncInterface,
|
||||
template <typename Iface> class WaitPolicy = detail::FireAndForgetInvoker>
|
||||
class MOZ_RAII AsyncInvoker final : public WaitPolicy<AsyncInterface>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @param aSyncProxy The COM object on which to invoke the asynchronous event.
|
||||
* This object must be a proxy to the synchronous variant of
|
||||
* AsyncInterface.
|
||||
*/
|
||||
explicit AsyncInvoker(IUnknown* aSyncProxy)
|
||||
{
|
||||
MOZ_ASSERT(aSyncProxy);
|
||||
MOZ_ASSERT(IsProxy(aSyncProxy));
|
||||
|
||||
RefPtr<ICallFactory> callFactory;
|
||||
if (FAILED(aSyncProxy->QueryInterface(IID_ICallFactory,
|
||||
getter_AddRefs(callFactory)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
mAsyncCall = new AsyncCallType(callFactory);
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return mAsyncCall && mAsyncCall->GetInterface();
|
||||
}
|
||||
|
||||
AsyncInterface* operator->() const
|
||||
{
|
||||
return mAsyncCall->GetInterface();
|
||||
}
|
||||
|
||||
AsyncInvoker(const AsyncInvoker& aOther) = delete;
|
||||
AsyncInvoker(AsyncInvoker&& aOther) = delete;
|
||||
AsyncInvoker& operator=(const AsyncInvoker& aOther) = delete;
|
||||
AsyncInvoker& operator=(AsyncInvoker&& aOther) = delete;
|
||||
};
|
||||
|
||||
template <typename AsyncInterface>
|
||||
using WaitableAsyncInvoker = AsyncInvoker<AsyncInterface, detail::WaitableInvoker>;
|
||||
|
||||
} // namespace mscom
|
||||
} // namespace mozilla
|
||||
|
||||
#define ASYNC_INVOKER_FOR(SyncIface) \
|
||||
mozilla::mscom::AsyncInvoker<Async##SyncIface>
|
||||
|
||||
#define WAITABLE_ASYNC_INVOKER_FOR(SyncIface) \
|
||||
mozilla::mscom::WaitableAsyncInvoker<Async##SyncIface>
|
||||
|
||||
#endif // mozilla_mscom_AsyncInvoker_h
|
|
@ -5,6 +5,8 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS.mozilla.mscom += [
|
||||
'Aggregation.h',
|
||||
'AsyncInvoker.h',
|
||||
'COMApartmentRegion.h',
|
||||
'COMPtrHolder.h',
|
||||
'EnsureMTA.h',
|
||||
|
|
|
@ -36,9 +36,7 @@
|
|||
# include "jit/PerfSpewer.h"
|
||||
#endif
|
||||
#include "vm/MatchPairs.h"
|
||||
#ifdef MOZ_VTUNE
|
||||
# include "vtune/VTuneWrapper.h"
|
||||
#endif
|
||||
#include "vtune/VTuneWrapper.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
|
||||
|
|
|
@ -1003,9 +1003,7 @@ BaselineCacheIRCompiler::emitStoreTypedObjectScalarProperty()
|
|||
masm.addPtr(offsetAddr, scratch1);
|
||||
Address dest(scratch1, 0);
|
||||
|
||||
BaselineStoreToTypedArray(cx_, masm, type, val, dest, scratch2,
|
||||
failure->label(), failure->label());
|
||||
|
||||
BaselineStoreToTypedArray(cx_, masm, type, val, dest, scratch2, failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1198,6 +1196,52 @@ BaselineCacheIRCompiler::emitStoreDenseElementHole()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitStoreTypedElement()
|
||||
{
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
Register index = allocator.useRegister(masm, reader.int32OperandId());
|
||||
ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
|
||||
|
||||
TypedThingLayout layout = reader.typedThingLayout();
|
||||
Scalar::Type type = reader.scalarType();
|
||||
bool handleOOB = reader.readBool();
|
||||
|
||||
AutoScratchRegister scratch1(allocator, masm);
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
// Bounds check.
|
||||
Label done;
|
||||
LoadTypedThingLength(masm, layout, obj, scratch1);
|
||||
masm.branch32(Assembler::BelowOrEqual, scratch1, index, handleOOB ? &done : failure->label());
|
||||
|
||||
// Load the elements vector.
|
||||
LoadTypedThingData(masm, layout, obj, scratch1);
|
||||
|
||||
BaseIndex dest(scratch1, index, ScaleFromElemWidth(Scalar::byteSize(type)));
|
||||
|
||||
// Use ICStubReg as second scratch register. TODO: consider doing the RHS
|
||||
// type check/conversion as a separate IR instruction so we can simplify
|
||||
// this.
|
||||
Register scratch2 = ICStubReg;
|
||||
masm.push(scratch2);
|
||||
|
||||
Label fail;
|
||||
BaselineStoreToTypedArray(cx_, masm, type, val, dest, scratch2, &fail);
|
||||
masm.pop(scratch2);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&fail);
|
||||
masm.pop(scratch2);
|
||||
masm.jump(failure->label());
|
||||
|
||||
masm.bind(&done);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitStoreUnboxedArrayElement()
|
||||
{
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "vm/EnvironmentObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
#include "vtune/VTuneWrapper.h"
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
|
@ -35,9 +36,6 @@
|
|||
#include "jit/MacroAssembler-inl.h"
|
||||
#include "vm/Interpreter-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
#ifdef MOZ_VTUNE
|
||||
# include "vtune/VTuneWrapper.h"
|
||||
#endif
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
|
|
@ -903,38 +903,6 @@ LoadTypedThingLength(MacroAssembler& masm, TypedThingLayout layout, Register obj
|
|||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
TypedArraySetElemStubExists(ICSetElem_Fallback* stub, HandleObject obj, bool expectOOB)
|
||||
{
|
||||
for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) {
|
||||
if (!iter->isSetElem_TypedArray())
|
||||
continue;
|
||||
ICSetElem_TypedArray* taStub = iter->toSetElem_TypedArray();
|
||||
if (obj->maybeShape() == taStub->shape() && taStub->expectOutOfBounds() == expectOOB)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
RemoveExistingTypedArraySetElemStub(JSContext* cx, ICSetElem_Fallback* stub, HandleObject obj)
|
||||
{
|
||||
for (ICStubIterator iter = stub->beginChain(); !iter.atEnd(); iter++) {
|
||||
if (!iter->isSetElem_TypedArray())
|
||||
continue;
|
||||
|
||||
if (obj->maybeShape() != iter->toSetElem_TypedArray()->shape())
|
||||
continue;
|
||||
|
||||
// TypedArraySetElem stubs are only removed using this procedure if
|
||||
// being replaced with one that expects out of bounds index.
|
||||
MOZ_ASSERT(!iter->toSetElem_TypedArray()->expectOutOfBounds());
|
||||
iter.unlink(cx);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_, Value* stack,
|
||||
HandleValue objv, HandleValue index, HandleValue rhs)
|
||||
|
@ -994,6 +962,9 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
|
|||
newStub->toCacheIR_Updated()->notePreliminaryObject();
|
||||
else if (gen.shouldUnlinkPreliminaryObjectStubs())
|
||||
StripPreliminaryObjectStubs(cx, stub);
|
||||
|
||||
if (gen.attachedTypedArrayOOBStub())
|
||||
stub->noteHasTypedArrayOOB();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1057,55 +1028,6 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
|
|||
}
|
||||
}
|
||||
|
||||
if ((obj->is<TypedArrayObject>() || IsPrimitiveArrayTypedObject(obj)) &&
|
||||
index.isNumber() &&
|
||||
rhs.isNumber())
|
||||
{
|
||||
if (!cx->runtime()->jitSupportsFloatingPoint &&
|
||||
(TypedThingRequiresFloatingPoint(obj) || index.isDouble()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool expectOutOfBounds;
|
||||
double idx = index.toNumber();
|
||||
if (obj->is<TypedArrayObject>()) {
|
||||
expectOutOfBounds = (idx < 0 || idx >= double(obj->as<TypedArrayObject>().length()));
|
||||
} else {
|
||||
// Typed objects throw on out of bounds accesses. Don't attach
|
||||
// a stub in this case.
|
||||
if (idx < 0 || idx >= double(obj->as<TypedObject>().length()))
|
||||
return true;
|
||||
expectOutOfBounds = false;
|
||||
|
||||
// Don't attach stubs if the underlying storage for typed objects
|
||||
// in the compartment could be detached, as the stub will always
|
||||
// bail out.
|
||||
if (cx->compartment()->detachedTypedObjects)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!TypedArraySetElemStubExists(stub, obj, expectOutOfBounds)) {
|
||||
// Remove any existing TypedArraySetElemStub that doesn't handle out-of-bounds
|
||||
if (expectOutOfBounds)
|
||||
RemoveExistingTypedArraySetElemStub(cx, stub, obj);
|
||||
|
||||
Shape* shape = obj->maybeShape();
|
||||
Scalar::Type type = TypedThingElementType(obj);
|
||||
|
||||
JitSpew(JitSpew_BaselineIC,
|
||||
" Generating SetElem_TypedArray stub (shape=%p, type=%u, oob=%s)",
|
||||
shape, type, expectOutOfBounds ? "yes" : "no");
|
||||
ICSetElem_TypedArray::Compiler compiler(cx, shape, type, expectOutOfBounds);
|
||||
ICStub* typedArrayStub = compiler.getStub(compiler.getStubSpace(outerScript));
|
||||
if (!typedArrayStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(typedArrayStub);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1153,13 +1075,13 @@ ICSetElem_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
}
|
||||
|
||||
void
|
||||
BaselineScript::noteArrayWriteHole(uint32_t pcOffset)
|
||||
BaselineScript::noteHasDenseAdd(uint32_t pcOffset)
|
||||
{
|
||||
ICEntry& entry = icEntryFromPCOffset(pcOffset);
|
||||
ICFallbackStub* stub = entry.fallbackStub();
|
||||
|
||||
if (stub->isSetElem_Fallback())
|
||||
stub->toSetElem_Fallback()->noteArrayWriteHole();
|
||||
stub->toSetElem_Fallback()->noteHasDenseAdd();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1173,15 +1095,11 @@ EmitUnboxedPreBarrierForBaseline(MacroAssembler &masm, const BaseIndex& address,
|
|||
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(type));
|
||||
}
|
||||
|
||||
//
|
||||
// SetElem_TypedArray
|
||||
//
|
||||
|
||||
template <typename S, typename T>
|
||||
template <typename T>
|
||||
void
|
||||
BaselineStoreToTypedArray(JSContext* cx, MacroAssembler& masm, Scalar::Type type, const S& value,
|
||||
const T& dest, Register scratch, Label* failure,
|
||||
Label* failureModifiedScratch)
|
||||
BaselineStoreToTypedArray(JSContext* cx, MacroAssembler& masm, Scalar::Type type,
|
||||
const ValueOperand& value, const T& dest, Register scratch,
|
||||
Label* failure)
|
||||
{
|
||||
Label done;
|
||||
|
||||
|
@ -1231,7 +1149,7 @@ BaselineStoreToTypedArray(JSContext* cx, MacroAssembler& masm, Scalar::Type type
|
|||
if (cx->runtime()->jitSupportsFloatingPoint) {
|
||||
masm.branchTestDouble(Assembler::NotEqual, value, failure);
|
||||
masm.unboxDouble(value, FloatReg0);
|
||||
masm.branchTruncateDoubleMaybeModUint32(FloatReg0, scratch, failureModifiedScratch);
|
||||
masm.branchTruncateDoubleMaybeModUint32(FloatReg0, scratch, failure);
|
||||
masm.jump(&isInt32);
|
||||
} else {
|
||||
masm.jump(failure);
|
||||
|
@ -1244,98 +1162,12 @@ BaselineStoreToTypedArray(JSContext* cx, MacroAssembler& masm, Scalar::Type type
|
|||
template void
|
||||
BaselineStoreToTypedArray(JSContext* cx, MacroAssembler& masm, Scalar::Type type,
|
||||
const ValueOperand& value, const Address& dest, Register scratch,
|
||||
Label* failure, Label* failureModifiedScratch);
|
||||
Label* failure);
|
||||
|
||||
template void
|
||||
BaselineStoreToTypedArray(JSContext* cx, MacroAssembler& masm, Scalar::Type type,
|
||||
const Address& value, const BaseIndex& dest, Register scratch,
|
||||
Label* failure, Label* failureModifiedScratch);
|
||||
|
||||
bool
|
||||
ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
{
|
||||
MOZ_ASSERT(engine_ == Engine::Baseline);
|
||||
|
||||
Label failure;
|
||||
|
||||
if (layout_ != Layout_TypedArray)
|
||||
CheckForTypedObjectWithDetachedStorage(cx, masm, &failure);
|
||||
|
||||
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
||||
|
||||
AllocatableGeneralRegisterSet regs(availableGeneralRegs(2));
|
||||
Register scratchReg = regs.takeAny();
|
||||
|
||||
// Unbox R0 and shape guard.
|
||||
Register obj = masm.extractObject(R0, ExtractTemp0);
|
||||
masm.loadPtr(Address(ICStubReg, ICSetElem_TypedArray::offsetOfShape()), scratchReg);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
|
||||
|
||||
// Ensure the index is an integer.
|
||||
if (cx->runtime()->jitSupportsFloatingPoint) {
|
||||
Label isInt32;
|
||||
masm.branchTestInt32(Assembler::Equal, R1, &isInt32);
|
||||
{
|
||||
// If the index is a double, try to convert it to int32. It's okay
|
||||
// to convert -0 to 0: the shape check ensures the object is a typed
|
||||
// array so the difference is not observable.
|
||||
masm.branchTestDouble(Assembler::NotEqual, R1, &failure);
|
||||
masm.unboxDouble(R1, FloatReg0);
|
||||
masm.convertDoubleToInt32(FloatReg0, scratchReg, &failure, /* negZeroCheck = */false);
|
||||
masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R1);
|
||||
}
|
||||
masm.bind(&isInt32);
|
||||
} else {
|
||||
masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
|
||||
}
|
||||
|
||||
// Unbox key.
|
||||
Register key = masm.extractInt32(R1, ExtractTemp1);
|
||||
|
||||
// Bounds check.
|
||||
Label oobWrite;
|
||||
LoadTypedThingLength(masm, layout_, obj, scratchReg);
|
||||
masm.branch32(Assembler::BelowOrEqual, scratchReg, key,
|
||||
expectOutOfBounds_ ? &oobWrite : &failure);
|
||||
|
||||
// Load the elements vector.
|
||||
LoadTypedThingData(masm, layout_, obj, scratchReg);
|
||||
|
||||
BaseIndex dest(scratchReg, key, ScaleFromElemWidth(Scalar::byteSize(type_)));
|
||||
Address value(masm.getStackPointer(), ICStackValueOffset);
|
||||
|
||||
// We need a second scratch register. It's okay to clobber the type tag of
|
||||
// R0 or R1, as long as it's restored before jumping to the next stub.
|
||||
regs = availableGeneralRegs(0);
|
||||
regs.takeUnchecked(obj);
|
||||
regs.takeUnchecked(key);
|
||||
regs.take(scratchReg);
|
||||
Register secondScratch = regs.takeAny();
|
||||
|
||||
Label failureModifiedSecondScratch;
|
||||
BaselineStoreToTypedArray(cx, masm, type_, value, dest,
|
||||
secondScratch, &failure, &failureModifiedSecondScratch);
|
||||
EmitReturnFromIC(masm);
|
||||
|
||||
if (failureModifiedSecondScratch.used()) {
|
||||
// Writing to secondScratch may have clobbered R0 or R1, restore them
|
||||
// first.
|
||||
masm.bind(&failureModifiedSecondScratch);
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, obj, R0);
|
||||
masm.tagValue(JSVAL_TYPE_INT32, key, R1);
|
||||
}
|
||||
|
||||
// Failure case - jump to next stub
|
||||
masm.bind(&failure);
|
||||
EmitStubGuardFailure(masm);
|
||||
|
||||
if (expectOutOfBounds_) {
|
||||
MOZ_ASSERT(layout_ == Layout_TypedArray);
|
||||
masm.bind(&oobWrite);
|
||||
EmitReturnFromIC(masm);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const ValueOperand& value, const BaseIndex& dest, Register scratch,
|
||||
Label* failure);
|
||||
|
||||
//
|
||||
// In_Fallback
|
||||
|
@ -4674,17 +4506,6 @@ ICTypeUpdate_ObjectGroup::ICTypeUpdate_ObjectGroup(JitCode* stubCode, ObjectGrou
|
|||
group_(group)
|
||||
{ }
|
||||
|
||||
ICSetElem_TypedArray::ICSetElem_TypedArray(JitCode* stubCode, Shape* shape, Scalar::Type type,
|
||||
bool expectOutOfBounds)
|
||||
: ICStub(SetElem_TypedArray, stubCode),
|
||||
shape_(shape)
|
||||
{
|
||||
extra_ = uint8_t(type);
|
||||
MOZ_ASSERT(extra_ == type);
|
||||
extra_ |= (static_cast<uint16_t>(expectOutOfBounds) << 8);
|
||||
}
|
||||
|
||||
|
||||
ICGetIntrinsic_Constant::ICGetIntrinsic_Constant(JitCode* stubCode, const Value& value)
|
||||
: ICStub(GetIntrinsic_Constant, stubCode),
|
||||
value_(value)
|
||||
|
|
|
@ -431,15 +431,17 @@ class ICSetElem_Fallback : public ICFallbackStub
|
|||
: ICFallbackStub(ICStub::SetElem_Fallback, stubCode)
|
||||
{ }
|
||||
|
||||
static const size_t HasDenseAddFlag = 0x1;
|
||||
static const size_t HasTypedArrayOOBFlag = 0x2;
|
||||
|
||||
public:
|
||||
static const uint32_t MAX_OPTIMIZED_STUBS = 8;
|
||||
|
||||
void noteArrayWriteHole() {
|
||||
extra_ = 1;
|
||||
}
|
||||
bool hasArrayWriteHole() const {
|
||||
return extra_;
|
||||
}
|
||||
void noteHasDenseAdd() { extra_ |= HasDenseAddFlag; }
|
||||
bool hasDenseAdd() const { return extra_ & HasDenseAddFlag; }
|
||||
|
||||
void noteHasTypedArrayOOB() { extra_ |= HasTypedArrayOOBFlag; }
|
||||
bool hasTypedArrayOOB() const { return extra_ & HasTypedArrayOOBFlag; }
|
||||
|
||||
// Compiler for this stub kind.
|
||||
class Compiler : public ICStubCompiler {
|
||||
|
@ -457,67 +459,6 @@ class ICSetElem_Fallback : public ICFallbackStub
|
|||
};
|
||||
};
|
||||
|
||||
// Accesses scalar elements of a typed array or typed object.
|
||||
class ICSetElem_TypedArray : public ICStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
protected: // Protected to silence Clang warning.
|
||||
GCPtrShape shape_;
|
||||
|
||||
ICSetElem_TypedArray(JitCode* stubCode, Shape* shape, Scalar::Type type,
|
||||
bool expectOutOfBounds);
|
||||
|
||||
public:
|
||||
Scalar::Type type() const {
|
||||
return (Scalar::Type) (extra_ & 0xff);
|
||||
}
|
||||
|
||||
bool expectOutOfBounds() const {
|
||||
return (extra_ >> 8) & 1;
|
||||
}
|
||||
|
||||
static size_t offsetOfShape() {
|
||||
return offsetof(ICSetElem_TypedArray, shape_);
|
||||
}
|
||||
|
||||
GCPtrShape& shape() {
|
||||
return shape_;
|
||||
}
|
||||
|
||||
class Compiler : public ICStubCompiler {
|
||||
RootedShape shape_;
|
||||
Scalar::Type type_;
|
||||
TypedThingLayout layout_;
|
||||
bool expectOutOfBounds_;
|
||||
|
||||
protected:
|
||||
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
|
||||
|
||||
virtual int32_t getKey() const {
|
||||
return static_cast<int32_t>(engine_) |
|
||||
(static_cast<int32_t>(kind) << 1) |
|
||||
(static_cast<int32_t>(type_) << 17) |
|
||||
(static_cast<int32_t>(layout_) << 25) |
|
||||
(static_cast<int32_t>(expectOutOfBounds_) << 29);
|
||||
}
|
||||
|
||||
public:
|
||||
Compiler(JSContext* cx, Shape* shape, Scalar::Type type, bool expectOutOfBounds)
|
||||
: ICStubCompiler(cx, ICStub::SetElem_TypedArray, Engine::Baseline),
|
||||
shape_(cx, shape),
|
||||
type_(type),
|
||||
layout_(GetTypedThingLayout(shape->getObjectClass())),
|
||||
expectOutOfBounds_(expectOutOfBounds)
|
||||
{}
|
||||
|
||||
ICStub* getStub(ICStubSpace* space) {
|
||||
return newStub<ICSetElem_TypedArray>(space, getStubCode(), shape_, type_,
|
||||
expectOutOfBounds_);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// In
|
||||
// JSOP_IN
|
||||
class ICIn_Fallback : public ICFallbackStub
|
||||
|
@ -1775,12 +1716,11 @@ void EmitUnboxedPreBarrierForBaseline(MacroAssembler &masm, const BaseIndex& add
|
|||
|
||||
// Write an arbitrary value to a typed array or typed object address at dest.
|
||||
// If the value could not be converted to the appropriate format, jump to
|
||||
// failure or failureModifiedScratch.
|
||||
template <typename S, typename T>
|
||||
void
|
||||
BaselineStoreToTypedArray(JSContext* cx, MacroAssembler& masm, Scalar::Type type, const S& value,
|
||||
const T& dest, Register scratch, Label* failure,
|
||||
Label* failureModifiedScratch);
|
||||
// failure.
|
||||
template <typename T>
|
||||
void BaselineStoreToTypedArray(JSContext* cx, MacroAssembler& masm, Scalar::Type type,
|
||||
const ValueOperand& value, const T& dest, Register scratch,
|
||||
Label* failure);
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
|
|
@ -49,9 +49,7 @@ namespace jit {
|
|||
_(Call_IsSuspendedStarGenerator) \
|
||||
\
|
||||
_(GetElem_Fallback) \
|
||||
\
|
||||
_(SetElem_Fallback) \
|
||||
_(SetElem_TypedArray) \
|
||||
\
|
||||
_(In_Fallback) \
|
||||
\
|
||||
|
|
|
@ -30,7 +30,7 @@ SetElemICInspector::sawOOBDenseWrite() const
|
|||
// Check for a write hole bit on the SetElem_Fallback stub.
|
||||
ICStub* stub = icEntry_->fallbackStub();
|
||||
if (stub->isSetElem_Fallback())
|
||||
return stub->toSetElem_Fallback()->hasArrayWriteHole();
|
||||
return stub->toSetElem_Fallback()->hasDenseAdd();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -41,27 +41,10 @@ SetElemICInspector::sawOOBTypedArrayWrite() const
|
|||
if (!icEntry_)
|
||||
return false;
|
||||
|
||||
// Check for SetElem_TypedArray stubs with expectOutOfBounds set.
|
||||
for (ICStub* stub = icEntry_->firstStub(); stub; stub = stub->next()) {
|
||||
if (!stub->isSetElem_TypedArray())
|
||||
continue;
|
||||
if (stub->toSetElem_TypedArray()->expectOutOfBounds())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ICStub* stub = icEntry_->fallbackStub();
|
||||
if (stub->isSetElem_Fallback())
|
||||
return stub->toSetElem_Fallback()->hasTypedArrayOOB();
|
||||
|
||||
bool
|
||||
SetElemICInspector::sawTypedArrayWrite() const
|
||||
{
|
||||
if (!icEntry_)
|
||||
return false;
|
||||
|
||||
// Check for a SetElem_TypedArray stub.
|
||||
for (ICStub* stub = icEntry_->firstStub(); stub; stub = stub->next()) {
|
||||
if (stub->isSetElem_TypedArray())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче