Bug 1138886 - Structured Clone for MozNDEFRecord. r=smaug

From 9b1bdef0b25b41d0448662ec689a961ae4e8fcd2 Mon Sep 17 00:00:00 2001
---
 dom/base/StructuredCloneTags.h     |   2 +
 dom/base/nsJSEnvironment.cpp       |  29 +++++++++
 dom/nfc/MozNDEFRecord.cpp          | 122 ++++++++++++++++++++++++++++++++++---
 dom/nfc/MozNDEFRecord.h            |  20 ++++--
 js/xpconnect/src/ExportHelpers.cpp |  36 ++++++++++-
 5 files changed, 193 insertions(+), 16 deletions(-)
This commit is contained in:
Yoshi Huang 2015-01-30 15:36:42 +08:00
Родитель e4ffc04ba5
Коммит 38c3210ae5
5 изменённых файлов: 193 добавлений и 16 удалений

Просмотреть файл

@ -39,6 +39,8 @@ enum StructuredCloneTags {
SCTAG_DOM_SYSTEM_PRINCIPAL,
SCTAG_DOM_CONTENT_PRINCIPAL,
SCTAG_DOM_NFC_NDEF,
SCTAG_DOM_MAX
};

Просмотреть файл

@ -59,6 +59,9 @@
#include "mozilla/dom/ErrorEvent.h"
#include "mozilla/dom/ImageDataBinding.h"
#include "mozilla/dom/ImageData.h"
#ifdef MOZ_NFC
#include "mozilla/dom/MozNDEFRecord.h"
#endif // MOZ_NFC
#include "mozilla/dom/StructuredClone.h"
#include "mozilla/dom/SubtleCryptoBinding.h"
#include "mozilla/ipc/BackgroundUtils.h"
@ -2514,6 +2517,24 @@ NS_DOMReadStructuredClone(JSContext* cx,
}
return result.toObjectOrNull();
} else if (tag == SCTAG_DOM_NFC_NDEF) {
#ifdef MOZ_NFC
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(cx));
if (!global) {
return nullptr;
}
// Prevent the return value from being trashed by a GC during ~nsRefPtr.
JS::Rooted<JSObject*> result(cx);
{
nsRefPtr<MozNDEFRecord> ndefRecord = new MozNDEFRecord(global);
result = ndefRecord->ReadStructuredClone(cx, reader) ?
ndefRecord->WrapObject(cx) : nullptr;
}
return result;
#else
return nullptr;
#endif
}
// Don't know what this is. Bail.
@ -2565,6 +2586,14 @@ NS_DOMWriteStructuredClone(JSContext* cx,
}
}
#ifdef MOZ_NFC
MozNDEFRecord* ndefRecord;
if (NS_SUCCEEDED(UNWRAP_OBJECT(MozNDEFRecord, obj, ndefRecord))) {
return JS_WriteUint32Pair(writer, SCTAG_DOM_NFC_NDEF, 0) &&
ndefRecord->WriteStructuredClone(cx, writer);
}
#endif // MOZ_NFC
// Don't know what this is
xpc::Throw(cx, NS_ERROR_DOM_DATA_CLONE_ERR);
return false;

Просмотреть файл

@ -7,9 +7,11 @@
/* Copyright © 2013 Deutsche Telekom, Inc. */
#include "MozNDEFRecord.h"
#include "js/StructuredClone.h"
#include "mozilla/dom/MozNDEFRecordBinding.h"
#include "mozilla/HoldDropJSObjects.h"
#include "nsContentUtils.h"
#include "nsIGlobalObject.h"
#include "nsString.h"
namespace mozilla {
@ -18,13 +20,13 @@ namespace dom {
NS_IMPL_CYCLE_COLLECTION_CLASS(MozNDEFRecord)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MozNDEFRecord)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
tmp->DropData();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MozNDEFRecord)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -107,14 +109,14 @@ MozNDEFRecord::Constructor(const GlobalObject& aGlobal,
return nullptr;
}
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
if (!win) {
nsCOMPtr<nsISupports> parent = do_QueryInterface(aGlobal.GetAsSupports());
if (!parent) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
JSContext* context = aGlobal.Context();
nsRefPtr<MozNDEFRecord> ndefRecord = new MozNDEFRecord(win, aOptions.mTnf);
nsRefPtr<MozNDEFRecord> ndefRecord = new MozNDEFRecord(parent, aOptions.mTnf);
ndefRecord->InitType(context, aOptions.mType);
ndefRecord->InitId(context, aOptions.mId);
ndefRecord->InitPayload(context, aOptions.mPayload);
@ -132,20 +134,20 @@ MozNDEFRecord::Constructor(const GlobalObject& aGlobal,
return nullptr;
}
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
if (!win) {
nsCOMPtr<nsISupports> parent = do_QueryInterface(aGlobal.GetAsSupports());
if (!parent) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<MozNDEFRecord> ndefRecord = new MozNDEFRecord(win, TNF::Well_known);
nsRefPtr<MozNDEFRecord> ndefRecord = new MozNDEFRecord(parent, TNF::Well_known);
ndefRecord->InitType(aGlobal.Context(), RTD::U);
ndefRecord->InitPayload(aGlobal.Context(), aUri);
return ndefRecord.forget();
}
MozNDEFRecord::MozNDEFRecord(nsPIDOMWindow* aWindow, TNF aTnf)
: mWindow(aWindow) // For GetParentObject()
MozNDEFRecord::MozNDEFRecord(nsISupports* aParent, TNF aTnf)
: mParent(aParent) // For GetParentObject()
, mTnf(aTnf)
, mSize(3) // 1(flags) + 1(type_length) + 1(payload_length)
{
@ -181,6 +183,72 @@ MozNDEFRecord::GetAsURI(nsAString& aRetVal)
nsDependentCSubstring(reinterpret_cast<char*>(&payloadData[1]), payloadLen - 1)));
}
bool
MozNDEFRecord::WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter) const
{
uint8_t* dummy;
uint32_t typeLen = 0, idLen = 0, payloadLen = 0;
if (mType) {
js::GetUint8ArrayLengthAndData(mType, &typeLen, &dummy);
}
if (mId) {
js::GetUint8ArrayLengthAndData(mId, &idLen, &dummy);
}
if (mPayload) {
js::GetUint8ArrayLengthAndData(mPayload, &payloadLen, &dummy);
}
return JS_WriteUint32Pair(aWriter, static_cast<uint32_t>(mTnf), typeLen) &&
JS_WriteUint32Pair(aWriter, idLen, payloadLen) &&
WriteUint8Array(aCx, aWriter, mType, typeLen) &&
WriteUint8Array(aCx, aWriter, mId, idLen) &&
WriteUint8Array(aCx, aWriter, mPayload, payloadLen);
}
bool
MozNDEFRecord::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader)
{
uint32_t tnf, typeLen, idLen, payloadLen;
if (!JS_ReadUint32Pair(aReader, &tnf, &typeLen) ||
!JS_ReadUint32Pair(aReader, &idLen, &payloadLen)) {
return false;
}
mTnf = static_cast<TNF>(tnf);
if (typeLen) {
JS::Rooted<JS::Value> value(aCx);
if (!JS_ReadTypedArray(aReader, &value)) {
return false;
}
MOZ_ASSERT(value.isObject());
InitType(aCx, value.toObject(), typeLen);
}
if (idLen) {
JS::Rooted<JS::Value> value(aCx);
if (!JS_ReadTypedArray(aReader, &value)) {
return false;
}
MOZ_ASSERT(value.isObject());
InitId(aCx, value.toObject(), idLen);
}
if (payloadLen) {
JS::Rooted<JS::Value> value(aCx);
if (!JS_ReadTypedArray(aReader, &value)) {
return false;
}
MOZ_ASSERT(value.isObject());
InitPayload(aCx, value.toObject(), payloadLen);
}
return true;
}
void
MozNDEFRecord::InitType(JSContext* aCx, const Optional<Uint8Array>& aType)
{
@ -203,6 +271,13 @@ MozNDEFRecord::InitType(JSContext* aCx, RTD rtd)
IncSize(rtdType.length);
}
void
MozNDEFRecord::InitType(JSContext* aCx, JSObject& aType, uint32_t aLen)
{
mType = &aType;
IncSize(aLen);
}
void
MozNDEFRecord::InitId(JSContext* aCx, const Optional<Uint8Array>& aId)
{
@ -216,6 +291,13 @@ MozNDEFRecord::InitId(JSContext* aCx, const Optional<Uint8Array>& aId)
IncSize(1 /* id_length */ + id.Length());
}
void
MozNDEFRecord::InitId(JSContext* aCx, JSObject& aId, uint32_t aLen)
{
mId = &aId;
IncSize(1 /* id_length */ + aLen);
}
void
MozNDEFRecord::InitPayload(JSContext* aCx, const Optional<Uint8Array>& aPayload)
{
@ -246,6 +328,13 @@ MozNDEFRecord::InitPayload(JSContext* aCx, const nsAString& aUri)
IncSizeForPayload(uri.Length() + 1);
}
void
MozNDEFRecord::InitPayload(JSContext* aCx, JSObject& aPayload, uint32_t aLen)
{
mPayload = &aPayload;
IncSizeForPayload(aLen);
}
void
MozNDEFRecord::IncSize(uint32_t aCount)
{
@ -262,6 +351,19 @@ MozNDEFRecord::IncSizeForPayload(uint32_t aLen)
IncSize(aLen);
}
bool
MozNDEFRecord::WriteUint8Array(JSContext* aCx, JSStructuredCloneWriter* aWriter, JSObject* aObj, uint32_t aLen) const
{
if (!aLen) {
return true;
}
JS::Rooted<JSObject*> obj(aCx, aObj);
JSAutoCompartment ac(aCx, obj);
JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*obj));
return JS_WriteTypedArray(aWriter, value);
}
/* static */ uint32_t
MozNDEFRecord::GetURIIdentifier(const nsCString& aUri)
{

Просмотреть файл

@ -19,9 +19,11 @@
#include "mozilla/dom/TypedArray.h"
#include "jsfriendapi.h"
#include "js/GCAPI.h"
#include "nsPIDOMWindow.h"
#include "nsISupports.h"
class nsIGlobalObject;
struct JSContext;
struct JSStructuredCloneWriter;
namespace mozilla {
namespace dom {
@ -36,13 +38,13 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MozNDEFRecord)
public:
MozNDEFRecord(nsPIDOMWindow* aWindow, TNF aTnf);
MozNDEFRecord(nsISupports* aParent, TNF aTnf = TNF::Empty);
~MozNDEFRecord();
nsIDOMWindow* GetParentObject() const
nsISupports* GetParentObject() const
{
return mWindow;
return mParent;
}
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
@ -92,18 +94,26 @@ public:
}
void GetAsURI(nsAString& aRetVal);
// Structured clone methods use these to clone MozNDEFRecord.
bool WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter) const;
bool ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader);
private:
MozNDEFRecord() = delete;
nsRefPtr<nsPIDOMWindow> mWindow;
nsRefPtr<nsISupports> mParent;
void HoldData();
void DropData();
void InitType(JSContext* aCx, const Optional<Uint8Array>& aType);
void InitType(JSContext* aCx, const RTD rtd);
void InitType(JSContext* aCx, JSObject& aType, uint32_t aLen);
void InitId(JSContext* aCx, const Optional<Uint8Array>& aId);
void InitId(JSContext* aCx, JSObject& aId, uint32_t aLen);
void InitPayload(JSContext* aCx, const Optional<Uint8Array>& aPayload);
void InitPayload(JSContext* aCx, const nsAString& aUri);
void InitPayload(JSContext* aCx, JSObject& aPayload, uint32_t aLen);
void IncSize(uint32_t aCount);
void IncSizeForPayload(uint32_t aLen);
bool WriteUint8Array(JSContext* aCx, JSStructuredCloneWriter* aWriter, JSObject* aObj, uint32_t aLen) const;
static bool
ValidateTNF(const MozNDEFRecordOptions& aOptions, ErrorResult& aRv);

Просмотреть файл

@ -14,6 +14,9 @@
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/File.h"
#ifdef MOZ_NFC
#include "mozilla/dom/MozNDEFRecord.h"
#endif
#include "nsGlobalWindow.h"
#include "nsJSUtils.h"
#include "nsIDOMFileList.h"
@ -38,7 +41,8 @@ enum StackScopedCloneTags {
SCTAG_BASE = JS_SCTAG_USER_MIN,
SCTAG_REFLECTOR,
SCTAG_BLOB,
SCTAG_FUNCTION
SCTAG_FUNCTION,
SCTAG_DOM_NFC_NDEF
};
class MOZ_STACK_CLASS StackScopedCloneData {
@ -121,6 +125,26 @@ StackScopedCloneRead(JSContext *cx, JSStructuredCloneReader *reader, uint32_t ta
return val.toObjectOrNull();
}
if (tag == SCTAG_DOM_NFC_NDEF) {
#ifdef MOZ_NFC
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(cx));
if (!global) {
return nullptr;
}
// Prevent the return value from being trashed by a GC during ~nsRefPtr.
JS::Rooted<JSObject*> result(cx);
{
nsRefPtr<MozNDEFRecord> ndefRecord = new MozNDEFRecord(global);
result = ndefRecord->ReadStructuredClone(cx, reader) ?
ndefRecord->WrapObject(cx) : nullptr;
}
return result;
#else
return nullptr;
#endif
}
MOZ_ASSERT_UNREACHABLE("Encountered garbage in the clone stream!");
return nullptr;
}
@ -192,6 +216,16 @@ StackScopedCloneWrite(JSContext *cx, JSStructuredCloneWriter *writer,
}
}
#ifdef MOZ_NFC
{
MozNDEFRecord* ndefRecord;
if (NS_SUCCEEDED(UNWRAP_OBJECT(MozNDEFRecord, obj, ndefRecord))) {
return JS_WriteUint32Pair(writer, SCTAG_DOM_NFC_NDEF, 0) &&
ndefRecord->WriteStructuredClone(cx, writer);
}
}
#endif
JS_ReportError(cx, "Encountered unsupported value type writing stack-scoped structured clone");
return false;
}