Merge m-c to inbound.

This commit is contained in:
Ryan VanderMeulen 2012-10-18 21:44:09 -04:00
commit 0744ad5c35
15 changed files with 209 additions and 42 deletions

View File

@ -208,3 +208,14 @@
fun:_ZN2js3ion5Range6updateEPKS1_ fun:_ZN2js3ion5Range6updateEPKS1_
... ...
} }
{
Bug 803386
Memcheck:Free
fun:_ZdlPv
fun:_ZN16SkMallocPixelRefD0Ev
fun:_ZNK8SkRefCnt16internal_disposeEv
fun:_ZN8SkBitmap10freePixelsEv
fun:_ZN8SkBitmapD1Ev
fun:_ZN7mozilla3gfx5ScaleEPhiiiS1_iiiNS0_13SurfaceFormatE
...
}

View File

@ -54,14 +54,14 @@ public:
void void
SetLazyData(const nsAString& aName, const nsAString& aContentType, SetLazyData(const nsAString& aName, const nsAString& aContentType,
uint64_t aLength) uint64_t aLength, uint64_t aLastModifiedDate)
{ {
NS_ASSERTION(aLength, "must have length"); NS_ASSERTION(aLength, "must have length");
mName = aName; mName = aName;
mContentType = aContentType; mContentType = aContentType;
mLength = aLength; mLength = aLength;
mLastModificationDate = aLastModifiedDate;
mIsFile = !aName.IsVoid(); mIsFile = !aName.IsVoid();
} }
@ -70,11 +70,25 @@ public:
return mLength == UINT64_MAX; return mLength == UINT64_MAX;
} }
bool IsDateUnknown() const
{
return mIsFile && mLastModificationDate == UINT64_MAX;
}
protected: protected:
nsDOMFileBase(const nsAString& aName, const nsAString& aContentType,
uint64_t aLength, uint64_t aLastModifiedDate)
: mIsFile(true), mImmutable(false), mContentType(aContentType),
mName(aName), mStart(0), mLength(aLength), mLastModificationDate(aLastModifiedDate)
{
// Ensure non-null mContentType by default
mContentType.SetIsVoid(false);
}
nsDOMFileBase(const nsAString& aName, const nsAString& aContentType, nsDOMFileBase(const nsAString& aName, const nsAString& aContentType,
uint64_t aLength) uint64_t aLength)
: mIsFile(true), mImmutable(false), mContentType(aContentType), : mIsFile(true), mImmutable(false), mContentType(aContentType),
mName(aName), mStart(0), mLength(aLength) mName(aName), mStart(0), mLength(aLength), mLastModificationDate(UINT64_MAX)
{ {
// Ensure non-null mContentType by default // Ensure non-null mContentType by default
mContentType.SetIsVoid(false); mContentType.SetIsVoid(false);
@ -82,7 +96,7 @@ protected:
nsDOMFileBase(const nsAString& aContentType, uint64_t aLength) nsDOMFileBase(const nsAString& aContentType, uint64_t aLength)
: mIsFile(false), mImmutable(false), mContentType(aContentType), : mIsFile(false), mImmutable(false), mContentType(aContentType),
mStart(0), mLength(aLength) mStart(0), mLength(aLength), mLastModificationDate(UINT64_MAX)
{ {
// Ensure non-null mContentType by default // Ensure non-null mContentType by default
mContentType.SetIsVoid(false); mContentType.SetIsVoid(false);
@ -91,7 +105,7 @@ protected:
nsDOMFileBase(const nsAString& aContentType, uint64_t aStart, nsDOMFileBase(const nsAString& aContentType, uint64_t aStart,
uint64_t aLength) uint64_t aLength)
: mIsFile(false), mImmutable(false), mContentType(aContentType), : mIsFile(false), mImmutable(false), mContentType(aContentType),
mStart(aStart), mLength(aLength) mStart(aStart), mLength(aLength), mLastModificationDate(UINT64_MAX)
{ {
NS_ASSERTION(aLength != UINT64_MAX, NS_ASSERTION(aLength != UINT64_MAX,
"Must know length when creating slice"); "Must know length when creating slice");
@ -127,12 +141,15 @@ protected:
bool mIsFile; bool mIsFile;
bool mImmutable; bool mImmutable;
nsString mContentType; nsString mContentType;
nsString mName; nsString mName;
uint64_t mStart; uint64_t mStart;
uint64_t mLength; uint64_t mLength;
uint64_t mLastModificationDate;
// Protected by IndexedDatabaseManager::FileMutex() // Protected by IndexedDatabaseManager::FileMutex()
nsTArray<nsRefPtr<FileInfo> > mFileInfos; nsTArray<nsRefPtr<FileInfo> > mFileInfos;
}; };
@ -140,6 +157,11 @@ protected:
class nsDOMFile : public nsDOMFileBase class nsDOMFile : public nsDOMFileBase
{ {
public: public:
nsDOMFile(const nsAString& aName, const nsAString& aContentType,
uint64_t aLength, uint64_t aLastModifiedDate)
: nsDOMFileBase(aName, aContentType, aLength, aLastModifiedDate)
{ }
nsDOMFile(const nsAString& aName, const nsAString& aContentType, nsDOMFile(const nsAString& aName, const nsAString& aContentType,
uint64_t aLength) uint64_t aLength)
: nsDOMFileBase(aName, aContentType, aLength) : nsDOMFileBase(aName, aContentType, aLength)
@ -183,7 +205,7 @@ class nsDOMFileFile : public nsDOMFile,
public: public:
// Create as a file // Create as a file
nsDOMFileFile(nsIFile *aFile) nsDOMFileFile(nsIFile *aFile)
: nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX), : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX),
mFile(aFile), mWholeFile(true), mStoredFile(false) mFile(aFile), mWholeFile(true), mStoredFile(false)
{ {
NS_ASSERTION(mFile, "must have file"); NS_ASSERTION(mFile, "must have file");
@ -195,7 +217,15 @@ public:
// Create as a file // Create as a file
nsDOMFileFile(const nsAString& aName, const nsAString& aContentType, nsDOMFileFile(const nsAString& aName, const nsAString& aContentType,
uint64_t aLength, nsIFile *aFile) uint64_t aLength, nsIFile *aFile)
: nsDOMFile(aName, aContentType, aLength), : nsDOMFile(aName, aContentType, aLength, UINT64_MAX),
mFile(aFile), mWholeFile(true), mStoredFile(false)
{
NS_ASSERTION(mFile, "must have file");
}
nsDOMFileFile(const nsAString& aName, const nsAString& aContentType,
uint64_t aLength, nsIFile *aFile, uint64_t aLastModificationDate)
: nsDOMFile(aName, aContentType, aLength, aLastModificationDate),
mFile(aFile), mWholeFile(true), mStoredFile(false) mFile(aFile), mWholeFile(true), mStoredFile(false)
{ {
NS_ASSERTION(mFile, "must have file"); NS_ASSERTION(mFile, "must have file");
@ -213,7 +243,7 @@ public:
// Create as a file with custom name // Create as a file with custom name
nsDOMFileFile(nsIFile *aFile, const nsAString& aName) nsDOMFileFile(nsIFile *aFile, const nsAString& aName)
: nsDOMFile(aName, EmptyString(), UINT64_MAX), : nsDOMFile(aName, EmptyString(), UINT64_MAX, UINT64_MAX),
mFile(aFile), mWholeFile(true), mStoredFile(false) mFile(aFile), mWholeFile(true), mStoredFile(false)
{ {
NS_ASSERTION(mFile, "must have file"); NS_ASSERTION(mFile, "must have file");
@ -225,7 +255,7 @@ public:
nsDOMFileFile(const nsAString& aName, const nsAString& aContentType, nsDOMFileFile(const nsAString& aName, const nsAString& aContentType,
uint64_t aLength, nsIFile* aFile, uint64_t aLength, nsIFile* aFile,
FileInfo* aFileInfo) FileInfo* aFileInfo)
: nsDOMFile(aName, aContentType, aLength), : nsDOMFile(aName, aContentType, aLength, UINT64_MAX),
mFile(aFile), mWholeFile(true), mStoredFile(true) mFile(aFile), mWholeFile(true), mStoredFile(true)
{ {
NS_ASSERTION(mFile, "must have file"); NS_ASSERTION(mFile, "must have file");
@ -244,7 +274,7 @@ public:
// Create as a file to be later initialized // Create as a file to be later initialized
nsDOMFileFile() nsDOMFileFile()
: nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX), : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX),
mWholeFile(true), mStoredFile(false) mWholeFile(true), mStoredFile(false)
{ {
// Lazily get the content type and size // Lazily get the content type and size
@ -264,7 +294,8 @@ public:
// Overrides // Overrides
NS_IMETHOD GetSize(uint64_t* aSize); NS_IMETHOD GetSize(uint64_t* aSize);
NS_IMETHOD GetType(nsAString& aType); NS_IMETHOD GetType(nsAString& aType);
NS_IMETHOD GetLastModifiedDate(JSContext* cx, JS::Value *aLastModifiedDate); NS_IMETHOD GetLastModifiedDate(JSContext* cx, JS::Value* aLastModifiedDate);
NS_IMETHOD GetMozLastModifiedDate(uint64_t* aLastModifiedDate);
NS_IMETHOD GetMozFullPathInternal(nsAString& aFullPath); NS_IMETHOD GetMozFullPathInternal(nsAString& aFullPath);
NS_IMETHOD GetInternalStream(nsIInputStream**); NS_IMETHOD GetInternalStream(nsIInputStream**);
@ -328,7 +359,7 @@ public:
uint64_t aLength, uint64_t aLength,
const nsAString& aName, const nsAString& aName,
const nsAString& aContentType) const nsAString& aContentType)
: nsDOMFile(aName, aContentType, aLength), : nsDOMFile(aName, aContentType, aLength, UINT64_MAX),
mDataOwner(new DataOwner(aMemoryBuffer)) mDataOwner(new DataOwner(aMemoryBuffer))
{ {
NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data"); NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");

View File

@ -28,7 +28,7 @@ interface nsIURI;
interface nsIPrincipal; interface nsIPrincipal;
interface nsIDOMBlob; interface nsIDOMBlob;
[scriptable, builtinclass, uuid(16e3f8d1-7f31-48cc-93f5-9c931a977cf6)] [scriptable, builtinclass, uuid(52d22585-7737-460e-9731-c658df03304a)]
interface nsIDOMBlob : nsISupports interface nsIDOMBlob : nsISupports
{ {
readonly attribute unsigned long long size; readonly attribute unsigned long long size;
@ -73,4 +73,6 @@ interface nsIDOMFile : nsIDOMBlob
// This performs no security checks! // This performs no security checks!
[noscript] readonly attribute DOMString mozFullPathInternal; [noscript] readonly attribute DOMString mozFullPathInternal;
[noscript] readonly attribute uint64_t mozLastModifiedDate;
}; };

View File

@ -888,11 +888,15 @@ nsIContent::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
// Event may need to be retargeted if this is the root of a native // Event may need to be retargeted if this is the root of a native
// anonymous content subtree or event is dispatched somewhere inside XBL. // anonymous content subtree or event is dispatched somewhere inside XBL.
if (isAnonForEvents) { if (isAnonForEvents) {
#ifdef DEBUG
// If a DOM event is explicitly dispatched using node.dispatchEvent(), then // If a DOM event is explicitly dispatched using node.dispatchEvent(), then
// all the events are allowed even in the native anonymous content.. // all the events are allowed even in the native anonymous content..
NS_ASSERTION(aVisitor.mEvent->eventStructType != NS_MUTATION_EVENT || nsCOMPtr<nsIContent> t = do_QueryInterface(aVisitor.mEvent->originalTarget);
NS_ASSERTION(!t || !t->ChromeOnlyAccess() ||
aVisitor.mEvent->eventStructType != NS_MUTATION_EVENT ||
aVisitor.mDOMEvent, aVisitor.mDOMEvent,
"Mutation event dispatched in native anonymous content!?!"); "Mutation event dispatched in native anonymous content!?!");
#endif
aVisitor.mEventTargetAtParent = parent; aVisitor.mEventTargetAtParent = parent;
} else if (parent && aVisitor.mOriginalTargetIsInAnon) { } else if (parent && aVisitor.mOriginalTargetIsInAnon) {
nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->target)); nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mEvent->target));

View File

@ -174,6 +174,14 @@ nsDOMFileBase::GetType(nsAString &aType)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsDOMFileBase::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
{
NS_ASSERTION(mIsFile, "Should only be called on files");
*aLastModifiedDate = mLastModificationDate;
return NS_OK;
}
// Makes sure that aStart and aEnd is less then or equal to aSize and greater // Makes sure that aStart and aEnd is less then or equal to aSize and greater
// than 0 // than 0
static void static void
@ -498,10 +506,20 @@ nsDOMFileFile::GetMozFullPathInternal(nsAString &aFilename)
} }
NS_IMETHODIMP NS_IMETHODIMP
nsDOMFileFile::GetLastModifiedDate(JSContext* cx, JS::Value *aLastModifiedDate) nsDOMFileFile::GetLastModifiedDate(JSContext* cx, JS::Value* aLastModifiedDate)
{ {
NS_ASSERTION(mIsFile, "Should only be called on files");
PRTime msecs; PRTime msecs;
mFile->GetLastModifiedTime(&msecs); mFile->GetLastModifiedTime(&msecs);
if (IsDateUnknown()) {
nsresult rv = mFile->GetLastModifiedTime(&msecs);
NS_ENSURE_SUCCESS(rv, rv);
mLastModificationDate = msecs;
} else {
msecs = mLastModificationDate;
}
JSObject* date = JS_NewDateObjectMsec(cx, msecs); JSObject* date = JS_NewDateObjectMsec(cx, msecs);
if (date) { if (date) {
aLastModifiedDate->setObject(*date); aLastModifiedDate->setObject(*date);
@ -562,6 +580,14 @@ nsDOMFileFile::GetType(nsAString &aType)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsDOMFileFile::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
{
NS_ASSERTION(mIsFile, "Should only be called on files");
*aLastModifiedDate = mLastModificationDate;
return NS_OK;
}
const uint32_t sFileStreamFlags = const uint32_t sFileStreamFlags =
nsIFileInputStream::CLOSE_ON_EOF | nsIFileInputStream::CLOSE_ON_EOF |
nsIFileInputStream::REOPEN_ON_REWIND | nsIFileInputStream::REOPEN_ON_REWIND |

View File

@ -10,14 +10,21 @@
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
// CHANGING THE ORDER/PLACEMENT OF EXISTING ENUM VALUES MAY BREAK INDEXEDDB.
// PROCEED WITH EXTREME CAUTION.
enum StructuredCloneTags { enum StructuredCloneTags {
SCTAG_BASE = JS_SCTAG_USER_MIN, SCTAG_BASE = JS_SCTAG_USER_MIN,
// These tags are used only for main thread structured clone. // These tags are used only for main thread structured clone.
SCTAG_DOM_BLOB, SCTAG_DOM_BLOB,
SCTAG_DOM_FILE,
// This tag is obsolete and exists only for backwards compatibility with
// existing IndexedDB databases.
SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE,
SCTAG_DOM_FILELIST, SCTAG_DOM_FILELIST,
SCTAG_DOM_FILEHANDLE, SCTAG_DOM_FILEHANDLE,
SCTAG_DOM_FILE,
// These tags are used for both main thread and workers. // These tags are used for both main thread and workers.
SCTAG_DOM_IMAGEDATA, SCTAG_DOM_IMAGEDATA,

View File

@ -175,9 +175,11 @@ DeviceStorageRequestParent::PostSuccessEvent::CancelableRun() {
DeviceStorageRequestParent::PostBlobSuccessEvent::PostBlobSuccessEvent(DeviceStorageRequestParent* aParent, DeviceStorageRequestParent::PostBlobSuccessEvent::PostBlobSuccessEvent(DeviceStorageRequestParent* aParent,
DeviceStorageFile* aFile, DeviceStorageFile* aFile,
uint32_t aLength, uint32_t aLength,
nsACString& aMimeType) nsACString& aMimeType,
uint64_t aLastModifiedDate)
: CancelableRunnable(aParent) : CancelableRunnable(aParent)
, mLength(aLength) , mLength(aLength)
, mLastModificationDate(aLastModifiedDate)
, mFile(aFile) , mFile(aFile)
, mMimeType(aMimeType) , mMimeType(aMimeType)
{ {
@ -192,7 +194,7 @@ DeviceStorageRequestParent::PostBlobSuccessEvent::CancelableRun() {
nsString mime; nsString mime;
CopyASCIItoUTF16(mMimeType, mime); CopyASCIItoUTF16(mMimeType, mime);
nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(mFile->mPath, mime, mLength, mFile->mFile); nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(mFile->mPath, mime, mLength, mFile->mFile, mLastModificationDate);
ContentParent* cp = static_cast<ContentParent*>(mParent->Manager()); ContentParent* cp = static_cast<ContentParent*>(mParent->Manager());
BlobParent* actor = cp->GetOrCreateActorForBlob(blob); BlobParent* actor = cp->GetOrCreateActorForBlob(blob);
@ -374,7 +376,15 @@ DeviceStorageRequestParent::ReadFileEvent::CancelableRun()
return NS_OK; return NS_OK;
} }
r = new PostBlobSuccessEvent(mParent, mFile, fileSize, mMimeType); PRTime modDate;
rv = mFile->mFile->GetLastModifiedTime(&modDate);
if (NS_FAILED(rv)) {
r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
NS_DispatchToMainThread(r);
return NS_OK;
}
r = new PostBlobSuccessEvent(mParent, mFile, fileSize, mMimeType, modDate);
NS_DispatchToMainThread(r); NS_DispatchToMainThread(r);
return NS_OK; return NS_OK;
} }

View File

@ -86,11 +86,12 @@ private:
class PostBlobSuccessEvent : public CancelableRunnable class PostBlobSuccessEvent : public CancelableRunnable
{ {
public: public:
PostBlobSuccessEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, uint32_t aLength, nsACString& aMimeType); PostBlobSuccessEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, uint32_t aLength, nsACString& aMimeType, uint64_t aLastModifiedDate);
virtual ~PostBlobSuccessEvent(); virtual ~PostBlobSuccessEvent();
virtual nsresult CancelableRun(); virtual nsresult CancelableRun();
private: private:
uint32_t mLength; uint32_t mLength;
uint64_t mLastModificationDate;
nsRefPtr<DeviceStorageFile> mFile; nsRefPtr<DeviceStorageFile> mFile;
nsCString mMimeType; nsCString mMimeType;
}; };

View File

@ -61,6 +61,9 @@ function getSuccess(e) {
ok(navigator.getDeviceStorage, "Should have getDeviceStorage"); ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
ok(e.target.result.name == gFileName, "File name should match"); ok(e.target.result.name == gFileName, "File name should match");
ok(e.target.result.size > 0, "File size be greater than zero");
ok(e.target.result.type, "File should have a mime type");
ok(e.target.result.lastModifiedDate, "File should have a last modified date");
var name = e.target.result.name; var name = e.target.result.name;

View File

@ -604,12 +604,14 @@ ActorFromRemoteBlob(nsIDOMBlob* aBlob)
inline inline
bool bool
ResolveMysteryBlob(nsIDOMBlob* aBlob, const nsString& aName, ResolveMysteryFile(nsIDOMBlob* aBlob, const nsString& aName,
const nsString& aContentType, uint64_t aSize) const nsString& aContentType, uint64_t aSize,
uint64_t aLastModifiedDate)
{ {
BlobChild* actor = ActorFromRemoteBlob(aBlob); BlobChild* actor = ActorFromRemoteBlob(aBlob);
if (actor) { if (actor) {
return actor->SetMysteryBlobInfo(aName, aContentType, aSize); return actor->SetMysteryBlobInfo(aName, aContentType,
aSize, aLastModifiedDate);
} }
return true; return true;
} }
@ -1095,7 +1097,18 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
uint32_t aData, uint32_t aData,
void* aClosure) void* aClosure)
{ {
if (aTag == SCTAG_DOM_FILEHANDLE || aTag == SCTAG_DOM_BLOB || // We need to statically assert that our tag values are what we expect
// so that if people accidentally change them they notice.
MOZ_STATIC_ASSERT(SCTAG_DOM_BLOB == 0xFFFF8001 &&
SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xFFFF8002 &&
SCTAG_DOM_FILEHANDLE == 0xFFFF8004 &&
SCTAG_DOM_FILE == 0xFFFF8005,
"You changed our structured clone tag values and just ate "
"everyone's IndexedDB data. I hope you are happy.");
if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
aTag == SCTAG_DOM_FILEHANDLE ||
aTag == SCTAG_DOM_BLOB ||
aTag == SCTAG_DOM_FILE) { aTag == SCTAG_DOM_FILE) {
StructuredCloneReadInfo* cloneReadInfo = StructuredCloneReadInfo* cloneReadInfo =
reinterpret_cast<StructuredCloneReadInfo*>(aClosure); reinterpret_cast<StructuredCloneReadInfo*>(aClosure);
@ -1141,6 +1154,7 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
return JSVAL_TO_OBJECT(wrappedFileHandle); return JSVAL_TO_OBJECT(wrappedFileHandle);
} }
// If it's not a FileHandle, it's a Blob or a File.
uint64_t size; uint64_t size;
if (!JS_ReadBytes(aReader, &size, sizeof(uint64_t))) { if (!JS_ReadBytes(aReader, &size, sizeof(uint64_t))) {
NS_WARNING("Failed to read size!"); NS_WARNING("Failed to read size!");
@ -1196,7 +1210,15 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
return JSVAL_TO_OBJECT(wrappedBlob); return JSVAL_TO_OBJECT(wrappedBlob);
} }
NS_ASSERTION(aTag == SCTAG_DOM_FILE, "Huh?!"); NS_ASSERTION(aTag == SCTAG_DOM_FILE ||
aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE, "Huh?!");
uint64_t lastModifiedDate = UINT64_MAX;
if (aTag != SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE &&
!JS_ReadBytes(aReader, &lastModifiedDate, sizeof(lastModifiedDate))) {
NS_WARNING("Failed to read lastModifiedDate");
return nullptr;
}
nsCString name; nsCString name;
if (!StructuredCloneReadString(aReader, name)) { if (!StructuredCloneReadString(aReader, name)) {
@ -1206,7 +1228,7 @@ IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
nsCOMPtr<nsIDOMFile> domFile; nsCOMPtr<nsIDOMFile> domFile;
if (file.mFile) { if (file.mFile) {
if (!ResolveMysteryBlob(file.mFile, convName, convType, size)) { if (!ResolveMysteryFile(file.mFile, convName, convType, size, lastModifiedDate)) {
return nullptr; return nullptr;
} }
domFile = do_QueryInterface(file.mFile); domFile = do_QueryInterface(file.mFile);
@ -1320,6 +1342,14 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
} }
if (file) { if (file) {
uint64_t lastModifiedDate = 0;
if (NS_FAILED(file->GetMozLastModifiedDate(&lastModifiedDate))) {
NS_WARNING("Failed to get last modified date!");
return false;
}
lastModifiedDate = SwapBytes(lastModifiedDate);
nsString name; nsString name;
if (NS_FAILED(file->GetName(name))) { if (NS_FAILED(file->GetName(name))) {
NS_WARNING("Failed to get name!"); NS_WARNING("Failed to get name!");
@ -1328,7 +1358,8 @@ IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
NS_ConvertUTF16toUTF8 convName(name); NS_ConvertUTF16toUTF8 convName(name);
uint32_t convNameLength = SwapBytes(convName.Length()); uint32_t convNameLength = SwapBytes(convName.Length());
if (!JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) || if (!JS_WriteBytes(aWriter, &lastModifiedDate, sizeof(lastModifiedDate)) ||
!JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) ||
!JS_WriteBytes(aWriter, convName.get(), convName.Length())) { !JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
return false; return false;
} }

View File

@ -584,6 +584,13 @@ private:
public: public:
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
RemoteBlob(const nsAString& aName, const nsAString& aContentType,
uint64_t aLength, uint64_t aModDate)
: nsDOMFile(aName, aContentType, aLength, aModDate), mActor(nullptr)
{
mImmutable = true;
}
RemoteBlob(const nsAString& aName, const nsAString& aContentType, RemoteBlob(const nsAString& aName, const nsAString& aContentType,
uint64_t aLength) uint64_t aLength)
: nsDOMFile(aName, aContentType, aLength), mActor(nullptr) : nsDOMFile(aName, aContentType, aLength), mActor(nullptr)
@ -598,7 +605,8 @@ public:
} }
RemoteBlob() RemoteBlob()
: nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX), mActor(nullptr) : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
, mActor(nullptr)
{ {
mImmutable = true; mImmutable = true;
} }
@ -651,6 +659,21 @@ public:
{ {
return static_cast<typename ActorType::ProtocolType*>(mActor); return static_cast<typename ActorType::ProtocolType*>(mActor);
} }
NS_IMETHOD
GetLastModifiedDate(JSContext* cx, JS::Value* aLastModifiedDate)
{
if (IsDateUnknown()) {
aLastModifiedDate->setNull();
} else {
JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate);
if (!date) {
return NS_ERROR_OUT_OF_MEMORY;
}
aLastModifiedDate->setObject(*date);
}
return NS_OK;
}
}; };
template <ActorFlavorEnum ActorFlavor> template <ActorFlavorEnum ActorFlavor>
@ -686,7 +709,7 @@ Blob<ActorFlavor>::Blob(const BlobConstructorParams& aParams)
aParams.get_FileBlobConstructorParams(); aParams.get_FileBlobConstructorParams();
remoteBlob = remoteBlob =
new RemoteBlobType(params.name(), params.contentType(), new RemoteBlobType(params.name(), params.contentType(),
params.length()); params.length(), params.modDate());
mBlobIsFile = true; mBlobIsFile = true;
break; break;
} }
@ -770,16 +793,20 @@ template <ActorFlavorEnum ActorFlavor>
bool bool
Blob<ActorFlavor>::SetMysteryBlobInfo(const nsString& aName, Blob<ActorFlavor>::SetMysteryBlobInfo(const nsString& aName,
const nsString& aContentType, const nsString& aContentType,
uint64_t aLength) uint64_t aLength,
uint64_t aLastModifiedDate)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mBlob); MOZ_ASSERT(mBlob);
MOZ_ASSERT(mRemoteBlob); MOZ_ASSERT(mRemoteBlob);
MOZ_ASSERT(aLength); MOZ_ASSERT(aLength);
MOZ_ASSERT(aLastModifiedDate != UINT64_MAX);
ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength); ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType,
aLength, aLastModifiedDate);
FileBlobConstructorParams params(aName, aContentType, aLength); FileBlobConstructorParams params(aName, aContentType,
aLength, aLastModifiedDate);
return ProtocolType::SendResolveMystery(params); return ProtocolType::SendResolveMystery(params);
} }
@ -796,7 +823,8 @@ Blob<ActorFlavor>::SetMysteryBlobInfo(const nsString& aContentType,
nsString voidString; nsString voidString;
voidString.SetIsVoid(true); voidString.SetIsVoid(true);
ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength); ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType,
aLength, UINT64_MAX);
NormalBlobConstructorParams params(aContentType, aLength); NormalBlobConstructorParams params(aContentType, aLength);
return ProtocolType::SendResolveMystery(params); return ProtocolType::SendResolveMystery(params);
@ -890,14 +918,16 @@ Blob<ActorFlavor>::RecvResolveMystery(const ResolveMysteryParams& aParams)
aParams.get_NormalBlobConstructorParams(); aParams.get_NormalBlobConstructorParams();
nsString voidString; nsString voidString;
voidString.SetIsVoid(true); voidString.SetIsVoid(true);
blob->SetLazyData(voidString, params.contentType(), params.length()); blob->SetLazyData(voidString, params.contentType(),
params.length(), UINT64_MAX);
break; break;
} }
case ResolveMysteryParams::TFileBlobConstructorParams: { case ResolveMysteryParams::TFileBlobConstructorParams: {
const FileBlobConstructorParams& params = const FileBlobConstructorParams& params =
aParams.get_FileBlobConstructorParams(); aParams.get_FileBlobConstructorParams();
blob->SetLazyData(params.name(), params.contentType(), params.length()); blob->SetLazyData(params.name(), params.contentType(),
params.length(), params.modDate());
break; break;
} }

View File

@ -173,7 +173,7 @@ public:
// Use this for files. // Use this for files.
bool bool
SetMysteryBlobInfo(const nsString& aName, const nsString& aContentType, SetMysteryBlobInfo(const nsString& aName, const nsString& aContentType,
uint64_t aLength); uint64_t aLength, uint64_t aLastModifiedDate);
// Use this for non-file blobs. // Use this for non-file blobs.
bool bool

View File

@ -540,9 +540,11 @@ ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
BlobConstructorParams params; BlobConstructorParams params;
if (blob->IsSizeUnknown()) { if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
// We don't want to call GetSize yet since that may stat a file on the main // We don't want to call GetSize or GetLastModifiedDate
// thread here. Instead we'll learn the size lazily from the other process. // yet since that may stat a file on the main thread
// here. Instead we'll learn the size lazily from the
// other process.
params = MysteryBlobConstructorParams(); params = MysteryBlobConstructorParams();
} }
else { else {
@ -561,6 +563,9 @@ ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
rv = file->GetName(fileParams.name()); rv = file->GetName(fileParams.name());
NS_ENSURE_SUCCESS(rv, nullptr); NS_ENSURE_SUCCESS(rv, nullptr);
rv = file->GetMozLastModifiedDate(&fileParams.modDate());
NS_ENSURE_SUCCESS(rv, nullptr);
fileParams.contentType() = contentType; fileParams.contentType() = contentType;
fileParams.length() = length; fileParams.length() = length;

View File

@ -1238,9 +1238,11 @@ ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
BlobConstructorParams params; BlobConstructorParams params;
if (blob->IsSizeUnknown()) { if (blob->IsSizeUnknown() || /*blob->IsDateUnknown()*/ 0) {
// We don't want to call GetSize yet since that may stat a file on the main // We don't want to call GetSize or GetLastModifiedDate
// thread here. Instead we'll learn the size lazily from the other process. // yet since that may stat a file on the main thread
// here. Instead we'll learn the size lazily from the
// other process.
params = MysteryBlobConstructorParams(); params = MysteryBlobConstructorParams();
} }
else { else {
@ -1256,6 +1258,9 @@ ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
if (file) { if (file) {
FileBlobConstructorParams fileParams; FileBlobConstructorParams fileParams;
rv = file->GetMozLastModifiedDate(&fileParams.modDate());
NS_ENSURE_SUCCESS(rv, nullptr);
rv = file->GetName(fileParams.name()); rv = file->GetName(fileParams.name());
NS_ENSURE_SUCCESS(rv, nullptr); NS_ENSURE_SUCCESS(rv, nullptr);

View File

@ -28,6 +28,7 @@ struct FileBlobConstructorParams
nsString name; nsString name;
nsString contentType; nsString contentType;
uint64_t length; uint64_t length;
uint64_t modDate;
}; };
} // namespace dom } // namespace dom