Bug 664783 - Implement FileReaderSync for Workers. r=bent+sicking.

This commit is contained in:
William Chen 2011-08-15 20:40:38 -07:00
Родитель c35631abba
Коммит a5a375d3a6
36 изменённых файлов: 3042 добавлений и 37 удалений

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

@ -148,8 +148,9 @@ NS_INTERFACE_MAP_BEGIN(nsDOMFileBase)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFile)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsDOMFileBase)
NS_IMPL_RELEASE(nsDOMFileBase)
// Threadsafe when GetMutable() == PR_FALSE
NS_IMPL_THREADSAFE_ADDREF(nsDOMFileBase)
NS_IMPL_THREADSAFE_RELEASE(nsDOMFileBase)
NS_IMETHODIMP
nsDOMFileBase::GetName(nsAString &aFileName)
@ -163,6 +164,12 @@ NS_IMETHODIMP
nsDOMFileBase::GetMozFullPath(nsAString &aFileName)
{
NS_ASSERTION(mIsFile, "Should only be called on files");
// It is unsafe to call IsCallerTrustedForCapability on a non-main thread. If
// you hit the following assertion you need to figure out some other way to
// determine privileges and call GetMozFullPathInternal.
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (nsContentUtils::IsCallerTrustedForCapability("UniversalFileRead")) {
return GetMozFullPathInternal(aFileName);
}

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

@ -1,4 +1,5 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -45,6 +46,7 @@
#include "nsTraceRefcnt.h"
#include "WorkerInlines.h"
#include "WorkerPrivate.h"
#define PROPERTY_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED
@ -415,6 +417,8 @@ class MessageEvent : public Event
protected:
uint64* mData;
size_t mDataByteCount;
nsTArray<nsCOMPtr<nsISupports> > mClonedObjects;
bool mMainRuntime;
public:
static bool
@ -435,7 +439,7 @@ public:
static JSObject*
Create(JSContext* aCx, JSObject* aParent, JSAutoStructuredCloneBuffer& aData,
bool aMainRuntime)
nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects, bool aMainRuntime)
{
JSString* type = JS_InternString(aCx, "message");
if (!type) {
@ -449,7 +453,7 @@ public:
return NULL;
}
MessageEvent* priv = new MessageEvent();
MessageEvent* priv = new MessageEvent(aMainRuntime);
if (!SetJSPrivateSafeish(aCx, obj, priv) ||
!InitMessageEventCommon(aCx, obj, priv, type, false, false, NULL, NULL,
NULL, true)) {
@ -459,12 +463,14 @@ public:
}
aData.steal(&priv->mData, &priv->mDataByteCount);
priv->mClonedObjects.SwapElements(aClonedObjects);
return obj;
}
protected:
MessageEvent()
: mData(NULL), mDataByteCount(0)
MessageEvent(bool aMainRuntime)
: mData(NULL), mDataByteCount(0), mMainRuntime(aMainRuntime)
{
MOZ_COUNT_CTOR(mozilla::dom::workers::MessageEvent);
}
@ -570,8 +576,14 @@ private:
event->mData = NULL;
event->mDataByteCount = 0;
// Release reference to objects that were AddRef'd for
// cloning into worker when array goes out of scope.
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
clonedObjects.SwapElements(event->mClonedObjects);
jsval data;
if (!buffer.read(aCx, &data) ||
if (!buffer.read(aCx, &data,
WorkerStructuredCloneCallbacks(event->mMainRuntime)) ||
!JS_SetReservedSlot(aCx, aObj, slot, data)) {
return false;
}
@ -1057,10 +1069,11 @@ CreateGenericEvent(JSContext* aCx, JSString* aType, bool aBubbles,
JSObject*
CreateMessageEvent(JSContext* aCx, JSAutoStructuredCloneBuffer& aData,
nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects,
bool aMainRuntime)
{
JSObject* global = JS_GetGlobalForScopeChain(aCx);
return MessageEvent::Create(aCx, global, aData, aMainRuntime);
return MessageEvent::Create(aCx, global, aData, aClonedObjects, aMainRuntime);
}
JSObject*

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

@ -42,6 +42,8 @@
#include "Workers.h"
#include "jspubtd.h"
#include "nsTArray.h"
#include "nsCOMPtr.h"
class JSAutoStructuredCloneBuffer;
@ -58,6 +60,7 @@ CreateGenericEvent(JSContext* aCx, JSString* aType, bool aBubbles,
JSObject*
CreateMessageEvent(JSContext* aCx, JSAutoStructuredCloneBuffer& aData,
nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects,
bool aMainRuntime);
JSObject*

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

@ -1,4 +1,5 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -189,7 +190,6 @@ JSClass DOMException::sClass = {
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSPropertySpec DOMException::sProperties[] = {
{ "code", SLOT_code, PROPERTY_FLAGS, GetProperty, js_GetterOnlyPropertyStub },
{ "name", SLOT_name, PROPERTY_FLAGS, GetProperty, js_GetterOnlyPropertyStub },
@ -277,6 +277,156 @@ DOMException::Create(JSContext* aCx, intN aCode)
return obj;
}
class FileException : public PrivatizableBase
{
static JSClass sClass;
static JSPropertySpec sProperties[];
static JSPropertySpec sStaticProperties[];
enum SLOT {
SLOT_code = 0,
SLOT_name,
SLOT_COUNT
};
public:
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj)
{
return JS_InitClass(aCx, aObj, NULL, &sClass, Construct, 0, sProperties,
NULL, sStaticProperties, NULL);
}
static JSObject*
Create(JSContext* aCx, intN aCode);
private:
FileException()
{
MOZ_COUNT_CTOR(mozilla::dom::workers::exceptions::FileException);
}
~FileException()
{
MOZ_COUNT_DTOR(mozilla::dom::workers::exceptions::FileException);
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
sClass.name);
return false;
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
delete GetJSPrivateSafeish<FileException>(aCx, aObj);
}
static JSBool
GetProperty(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
int32 slot = JSID_TO_INT(aIdval);
JSClass* classPtr = JS_GET_CLASS(aCx, aObj);
if (classPtr != &sClass ||
!GetJSPrivateSafeish<FileException>(aCx, aObj)) {
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name,
sProperties[slot].name,
classPtr ? classPtr->name : "object");
return false;
}
return JS_GetReservedSlot(aCx, aObj, slot, aVp);
}
static JSBool
GetConstant(JSContext* aCx, JSObject* aObj, jsid idval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(idval));
*aVp = INT_TO_JSVAL(JSID_TO_INT(idval));
return true;
}
};
JSClass FileException::sClass = {
"FileException",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSPropertySpec FileException::sProperties[] = {
{ "code", SLOT_code, PROPERTY_FLAGS, GetProperty, js_GetterOnlyPropertyStub },
{ "name", SLOT_name, PROPERTY_FLAGS, GetProperty, js_GetterOnlyPropertyStub },
{ 0, 0, 0, NULL, NULL }
};
JSPropertySpec FileException::sStaticProperties[] = {
#define EXCEPTION_ENTRY(_name) \
{ #_name, FILE_##_name, CONSTANT_FLAGS, GetConstant, NULL },
EXCEPTION_ENTRY(NOT_FOUND_ERR)
EXCEPTION_ENTRY(SECURITY_ERR)
EXCEPTION_ENTRY(ABORT_ERR)
EXCEPTION_ENTRY(NOT_READABLE_ERR)
EXCEPTION_ENTRY(ENCODING_ERR)
#undef EXCEPTION_ENTRY
{ 0, 0, 0, NULL, NULL }
};
// static
JSObject*
FileException::Create(JSContext* aCx, intN aCode)
{
JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
if (!obj) {
return NULL;
}
size_t foundIndex = size_t(-1);
for (size_t index = 0;
index < JS_ARRAY_LENGTH(sStaticProperties) - 1;
index++) {
if (sStaticProperties[index].tinyid == aCode) {
foundIndex = index;
break;
}
}
JS_ASSERT(foundIndex != size_t(-1));
JSString* name = JS_NewStringCopyZ(aCx, sStaticProperties[foundIndex].name);
if (!name) {
return NULL;
}
if (!JS_SetReservedSlot(aCx, obj, SLOT_code, INT_TO_JSVAL(aCode)) ||
!JS_SetReservedSlot(aCx, obj, SLOT_name, STRING_TO_JSVAL(name))) {
return NULL;
}
FileException* priv = new FileException();
if (!SetJSPrivateSafeish(aCx, obj, priv)) {
delete priv;
return NULL;
}
return obj;
}
} // anonymous namespace
BEGIN_WORKERS_NAMESPACE
@ -286,7 +436,8 @@ namespace exceptions {
bool
InitClasses(JSContext* aCx, JSObject* aGlobal)
{
return !!DOMException::InitClass(aCx, aGlobal);
return DOMException::InitClass(aCx, aGlobal) &&
FileException::InitClass(aCx, aGlobal);
}
void
@ -298,6 +449,15 @@ ThrowDOMExceptionForCode(JSContext* aCx, intN aCode)
JS_SetPendingException(aCx, OBJECT_TO_JSVAL(exception));
}
void
ThrowFileExceptionForCode(JSContext* aCx, intN aCode)
{
JSObject* exception = FileException::Create(aCx, aCode);
JS_ASSERT(exception);
JS_SetPendingException(aCx, OBJECT_TO_JSVAL(exception));
}
} // namespace exceptions
END_WORKERS_NAMESPACE

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

@ -1,4 +1,5 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -43,6 +44,7 @@
#include "jspubtd.h"
// DOMException Codes.
#define INDEX_SIZE_ERR 1
#define DOMSTRING_SIZE_ERR 2
#define HIERARCHY_REQUEST_ERR 3
@ -69,6 +71,13 @@
#define INVALID_NODE_TYPE_ERR 24
#define DATA_CLONE_ERR 25
// FileException Codes
#define FILE_NOT_FOUND_ERR 1
#define FILE_SECURITY_ERR 2
#define FILE_ABORT_ERR 3
#define FILE_NOT_READABLE_ERR 4
#define FILE_ENCODING_ERR 5
BEGIN_WORKERS_NAMESPACE
namespace exceptions {
@ -79,6 +88,9 @@ InitClasses(JSContext* aCx, JSObject* aGlobal);
void
ThrowDOMExceptionForCode(JSContext* aCx, intN aCode);
void
ThrowFileExceptionForCode(JSContext* aCx, intN aCode);
} // namespace exceptions
END_WORKERS_NAMESPACE

452
dom/workers/File.cpp Normal file
Просмотреть файл

@ -0,0 +1,452 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* William Chen <wchen@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "File.h"
#include "nsIDOMFile.h"
#include "jsapi.h"
#include "jsatom.h"
#include "jscntxt.h"
#include "nsCOMPtr.h"
#include "nsJSUtils.h"
#include "nsStringGlue.h"
#include "xpcprivate.h"
#include "xpcquickstubs.h"
#include "Exceptions.h"
#include "WorkerInlines.h"
#include "WorkerPrivate.h"
#define PROPERTY_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED
USING_WORKERS_NAMESPACE
using mozilla::dom::workers::exceptions::ThrowFileExceptionForCode;
namespace {
class Blob
{
// Blob should never be instantiated.
Blob();
~Blob();
static JSClass sClass;
static JSPropertySpec sProperties[];
static JSFunctionSpec sFunctions[];
public:
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj)
{
return JS_InitClass(aCx, aObj, NULL, &sClass, Construct, 0, sProperties,
sFunctions, NULL, NULL);
}
static JSObject*
Create(JSContext* aCx, nsIDOMBlob* aBlob)
{
JS_ASSERT(SameCOMIdentity(static_cast<nsISupports*>(aBlob), aBlob));
JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
if (obj) {
if (!JS_SetPrivate(aCx, obj, aBlob)) {
return NULL;
}
NS_ADDREF(aBlob);
}
return obj;
}
static nsIDOMBlob*
GetPrivate(JSContext* aCx, JSObject* aObj);
private:
static nsIDOMBlob*
GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
{
JSClass* classPtr = NULL;
if (aObj) {
nsIDOMBlob* blob = GetPrivate(aCx, aObj);
if (blob) {
return blob;
}
classPtr = JS_GET_CLASS(aCx, aObj);
}
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
classPtr ? classPtr->name : "Object");
return NULL;
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
sClass.name);
return false;
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
nsIDOMBlob* blob = GetPrivate(aCx, aObj);
NS_IF_RELEASE(blob);
}
static JSBool
GetSize(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
nsIDOMBlob* blob = GetInstancePrivate(aCx, aObj, "size");
if (!blob) {
return false;
}
PRUint64 size;
if (NS_FAILED(blob->GetSize(&size))) {
ThrowFileExceptionForCode(aCx, FILE_NOT_READABLE_ERR);
}
if (!JS_NewNumberValue(aCx, jsdouble(size), aVp)) {
return false;
}
return true;
}
static JSBool
GetType(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
nsIDOMBlob* blob = GetInstancePrivate(aCx, aObj, "type");
if (!blob) {
return false;
}
nsString type;
if (NS_FAILED(blob->GetType(type))) {
ThrowFileExceptionForCode(aCx, FILE_NOT_READABLE_ERR);
}
JSString* jsType = JS_NewUCStringCopyN(aCx, type.get(), type.Length());
if (!jsType) {
return false;
}
*aVp = STRING_TO_JSVAL(jsType);
return true;
}
static JSBool
MozSlice(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "mozSlice");
if (!blob) {
return false;
}
jsdouble start = 0, end = 0;
JSString* jsContentType = JS_GetEmptyString(JS_GetRuntime(aCx));
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "/IIS", &start,
&end, &jsContentType)) {
return false;
}
nsDependentJSString contentType;
if (!contentType.init(aCx, jsContentType)) {
return false;
}
PRUint8 optionalArgc = aArgc;
nsCOMPtr<nsIDOMBlob> rtnBlob;
if (NS_FAILED(blob->MozSlice(xpc_qsDoubleToUint64(start),
xpc_qsDoubleToUint64(end),
contentType, optionalArgc,
getter_AddRefs(rtnBlob)))) {
ThrowFileExceptionForCode(aCx, FILE_NOT_READABLE_ERR);
return false;
}
JSObject* rtnObj = file::CreateBlob(aCx, rtnBlob);
if (!rtnObj) {
return false;
}
JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(rtnObj));
return true;
}
};
JSClass Blob::sClass = {
"Blob",
JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSPropertySpec Blob::sProperties[] = {
{ "size", 0, PROPERTY_FLAGS, GetSize, js_GetterOnlyPropertyStub },
{ "type", 0, PROPERTY_FLAGS, GetType, js_GetterOnlyPropertyStub },
{ 0, 0, 0, NULL, NULL }
};
JSFunctionSpec Blob::sFunctions[] = {
JS_FN("mozSlice", MozSlice, 1, JSPROP_ENUMERATE),
JS_FS_END
};
class File : public Blob
{
// File should never be instantiated.
File();
~File();
static JSClass sClass;
static JSPropertySpec sProperties[];
public:
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto)
{
return JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct, 0,
sProperties, NULL, NULL, NULL);
}
static JSObject*
Create(JSContext* aCx, nsIDOMFile* aFile)
{
JS_ASSERT(SameCOMIdentity(static_cast<nsISupports*>(aFile), aFile));
JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
if (obj) {
if (!JS_SetPrivate(aCx, obj, aFile)) {
return NULL;
}
NS_ADDREF(aFile);
}
return obj;
}
static nsIDOMFile*
GetPrivate(JSContext* aCx, JSObject* aObj)
{
if (aObj) {
JSClass* classPtr = JS_GET_CLASS(aCx, aObj);
if (classPtr == &sClass) {
nsISupports* priv = static_cast<nsISupports*>(JS_GetPrivate(aCx, aObj));
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(priv);
JS_ASSERT_IF(priv, file);
return file;
}
}
return NULL;
}
static JSClass*
Class()
{
return &sClass;
}
private:
static nsIDOMFile*
GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
{
JSClass* classPtr = NULL;
if (aObj) {
nsIDOMFile* file = GetPrivate(aCx, aObj);
if (file) {
return file;
}
classPtr = JS_GET_CLASS(aCx, aObj);
}
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
classPtr ? classPtr->name : "Object");
return NULL;
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
sClass.name);
return false;
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
nsIDOMFile* file = GetPrivate(aCx, aObj);
NS_IF_RELEASE(file);
}
static JSBool
GetMozFullPath(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
nsIDOMFile* file = GetInstancePrivate(aCx, aObj, "mozFullPath");
if (!file) {
return false;
}
nsString fullPath;
if (GetWorkerPrivateFromContext(aCx)->UsesSystemPrincipal() &&
NS_FAILED(file->GetMozFullPathInternal(fullPath))) {
ThrowFileExceptionForCode(aCx, FILE_NOT_READABLE_ERR);
return false;
}
JSString* jsFullPath = JS_NewUCStringCopyN(aCx, fullPath.get(),
fullPath.Length());
if (!jsFullPath) {
return false;
}
*aVp = STRING_TO_JSVAL(jsFullPath);
return true;
}
static JSBool
GetName(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
nsIDOMFile* file = GetInstancePrivate(aCx, aObj, "name");
if (!file) {
return false;
}
nsString name;
if (NS_FAILED(file->GetName(name))) {
name.Truncate();
}
JSString* jsName = JS_NewUCStringCopyN(aCx, name.get(), name.Length());
if (!jsName) {
return false;
}
*aVp = STRING_TO_JSVAL(jsName);
return true;
}
};
JSClass File::sClass = {
"File",
JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSPropertySpec File::sProperties[] = {
{ "name", 0, PROPERTY_FLAGS, GetName, js_GetterOnlyPropertyStub },
{ "mozFullPath", 0, PROPERTY_FLAGS, GetMozFullPath,
js_GetterOnlyPropertyStub },
{ 0, 0, 0, NULL, NULL }
};
nsIDOMBlob*
Blob::GetPrivate(JSContext* aCx, JSObject* aObj)
{
if (aObj) {
JSClass* classPtr = JS_GET_CLASS(aCx, aObj);
if (classPtr == &sClass || classPtr == File::Class()) {
nsISupports* priv = static_cast<nsISupports*>(JS_GetPrivate(aCx, aObj));
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(priv);
JS_ASSERT_IF(priv, blob);
return blob;
}
}
return NULL;
}
} // anonymous namespace
BEGIN_WORKERS_NAMESPACE
namespace file {
JSObject*
CreateBlob(JSContext* aCx, nsIDOMBlob* aBlob)
{
return Blob::Create(aCx, aBlob);
}
bool
InitClasses(JSContext* aCx, JSObject* aGlobal)
{
JSObject* blobProto = Blob::InitClass(aCx, aGlobal);
return blobProto && File::InitClass(aCx, aGlobal, blobProto);
}
nsIDOMBlob*
GetDOMBlobFromJSObject(JSContext* aCx, JSObject* aObj)
{
return Blob::GetPrivate(aCx, aObj);
}
JSObject*
CreateFile(JSContext* aCx, nsIDOMFile* aFile)
{
return File::Create(aCx, aFile);
}
nsIDOMFile*
GetDOMFileFromJSObject(JSContext* aCx, JSObject* aObj)
{
return File::GetPrivate(aCx, aObj);
}
} // namespace file
END_WORKERS_NAMESPACE

73
dom/workers/File.h Normal file
Просмотреть файл

@ -0,0 +1,73 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* William Chen <wchen@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_workers_file_h__
#define mozilla_dom_workers_file_h__
#include "Workers.h"
#include "jspubtd.h"
class nsIDOMFile;
class nsIDOMBlob;
BEGIN_WORKERS_NAMESPACE
namespace file {
bool
InitClasses(JSContext* aCx, JSObject* aGlobal);
JSObject*
CreateBlob(JSContext* aCx, nsIDOMBlob* aBlob);
nsIDOMBlob*
GetDOMBlobFromJSObject(JSContext* aCx, JSObject* aObj);
JSObject*
CreateFile(JSContext* aCx, nsIDOMFile* aFile);
nsIDOMFile*
GetDOMFileFromJSObject(JSContext* aCx, JSObject* aObj);
} // namespace file
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_file_h__ */

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

@ -0,0 +1,372 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* William Chen <wchen@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "FileReaderSync.h"
#include "nsIDOMFile.h"
#include "jsapi.h"
#include "jsatom.h"
#include "jscntxt.h"
#include "jstypedarray.h"
#include "nsJSUtils.h"
#include "xpcprivate.h"
#include "Exceptions.h"
#include "File.h"
#include "FileReaderSyncPrivate.h"
#include "WorkerInlines.h"
#define FUNCTION_FLAGS \
JSPROP_ENUMERATE
USING_WORKERS_NAMESPACE
using mozilla::dom::workers::exceptions::ThrowFileExceptionForCode;
using js::ArrayBuffer;
namespace {
inline bool
EnsureSucceededOrThrow(JSContext* aCx, nsresult rv)
{
if (NS_SUCCEEDED(rv)) {
return true;
}
intN code = rv == NS_ERROR_FILE_NOT_FOUND ?
FILE_NOT_FOUND_ERR :
FILE_NOT_READABLE_ERR;
ThrowFileExceptionForCode(aCx, code);
return false;
}
inline nsIDOMBlob*
GetDOMBlobFromJSObject(JSContext* aCx, JSObject* aObj) {
JSClass* classPtr = NULL;
if (aObj) {
nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aCx, aObj);
if (blob) {
return blob;
}
classPtr = JS_GET_CLASS(aCx, aObj);
}
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
classPtr ? classPtr->name : "Object", "not a Blob.");
return NULL;
}
class FileReaderSync
{
// FileReaderSync should not be instantiated.
FileReaderSync();
~FileReaderSync();
static JSClass sClass;
static JSFunctionSpec sFunctions[];
public:
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj)
{
return JS_InitClass(aCx, aObj, NULL, &sClass, Construct, 0,
NULL, sFunctions, NULL, NULL);
}
static FileReaderSyncPrivate*
GetPrivate(JSContext* aCx, JSObject* aObj)
{
if (aObj) {
JSClass* classPtr = JS_GET_CLASS(aCx, aObj);
if (classPtr == &sClass) {
FileReaderSyncPrivate* fileReader =
GetJSPrivateSafeish<FileReaderSyncPrivate>(aCx, aObj);
return fileReader;
}
}
return NULL;
}
private:
static FileReaderSyncPrivate*
GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
{
JSClass* classPtr = NULL;
if (aObj) {
FileReaderSyncPrivate* fileReader = GetPrivate(aCx, aObj);
if (fileReader) {
return fileReader;
}
classPtr = JS_GET_CLASS(aCx, aObj);
}
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
classPtr ? classPtr->name : "Object");
return NULL;
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
if (!obj) {
return false;
}
FileReaderSyncPrivate* fileReader = new FileReaderSyncPrivate();
NS_ADDREF(fileReader);
if (!SetJSPrivateSafeish(aCx, obj, fileReader)) {
NS_RELEASE(fileReader);
return false;
}
JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(obj));
return true;
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
FileReaderSyncPrivate* fileReader =
GetJSPrivateSafeish<FileReaderSyncPrivate>(aCx, aObj);
NS_IF_RELEASE(fileReader);
}
static JSBool
ReadAsArrayBuffer(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
FileReaderSyncPrivate* fileReader =
GetInstancePrivate(aCx, obj, "readAsArrayBuffer");
if (!fileReader) {
return false;
}
JSObject* jsBlob;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "o", &jsBlob)) {
return false;
}
nsIDOMBlob* blob = GetDOMBlobFromJSObject(aCx, jsBlob);
if (!blob) {
return false;
}
PRUint64 blobSize;
nsresult rv = blob->GetSize(&blobSize);
if (!EnsureSucceededOrThrow(aCx, rv)) {
return false;
}
JSObject* jsArrayBuffer = js_CreateArrayBuffer(aCx, blobSize);
if (!jsArrayBuffer) {
return false;
}
JSUint32 bufferLength = JS_GetArrayBufferByteLength(jsArrayBuffer);
uint8* arrayBuffer = JS_GetArrayBufferData(jsArrayBuffer);
rv = fileReader->ReadAsArrayBuffer(blob, bufferLength, arrayBuffer);
if (!EnsureSucceededOrThrow(aCx, rv)) {
return false;
}
JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(jsArrayBuffer));
return true;
}
static JSBool
ReadAsDataURL(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
FileReaderSyncPrivate* fileReader =
GetInstancePrivate(aCx, obj, "readAsDataURL");
if (!fileReader) {
return false;
}
JSObject* jsBlob;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "o", &jsBlob)) {
return false;
}
nsIDOMBlob* blob = GetDOMBlobFromJSObject(aCx, jsBlob);
if (!blob) {
return false;
}
nsString blobText;
nsresult rv = fileReader->ReadAsDataURL(blob, blobText);
if (!EnsureSucceededOrThrow(aCx, rv)) {
return false;
}
JSString* jsBlobText = JS_NewUCStringCopyN(aCx, blobText.get(),
blobText.Length());
if (!jsBlobText) {
return false;
}
JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(jsBlobText));
return true;
}
static JSBool
ReadAsBinaryString(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
FileReaderSyncPrivate* fileReader =
GetInstancePrivate(aCx, obj, "readAsBinaryString");
if (!fileReader) {
return false;
}
JSObject* jsBlob;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "o", &jsBlob)) {
return false;
}
nsIDOMBlob* blob = GetDOMBlobFromJSObject(aCx, jsBlob);
if (!blob) {
return false;
}
nsString blobText;
nsresult rv = fileReader->ReadAsBinaryString(blob, blobText);
if (!EnsureSucceededOrThrow(aCx, rv)) {
return false;
}
JSString* jsBlobText = JS_NewUCStringCopyN(aCx, blobText.get(),
blobText.Length());
if (!jsBlobText) {
return false;
}
JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(jsBlobText));
return true;
}
static JSBool
ReadAsText(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
FileReaderSyncPrivate* fileReader =
GetInstancePrivate(aCx, obj, "readAsText");
if (!fileReader) {
return false;
}
JSObject* jsBlob;
JSString* jsEncoding = JS_GetEmptyString(JS_GetRuntime(aCx));
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "o/S", &jsBlob,
&jsEncoding)) {
return false;
}
nsDependentJSString encoding;
if (!encoding.init(aCx, jsEncoding)) {
return false;
}
nsIDOMBlob* blob = GetDOMBlobFromJSObject(aCx, jsBlob);
if (!blob) {
return false;
}
nsString blobText;
nsresult rv = fileReader->ReadAsText(blob, encoding, blobText);
if (!EnsureSucceededOrThrow(aCx, rv)) {
return false;
}
JSString* jsBlobText = JS_NewUCStringCopyN(aCx, blobText.get(),
blobText.Length());
if (!jsBlobText) {
return false;
}
JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(jsBlobText));
return true;
}
};
JSClass FileReaderSync::sClass = {
"FileReaderSync",
JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSFunctionSpec FileReaderSync::sFunctions[] = {
JS_FN("readAsArrayBuffer", ReadAsArrayBuffer, 1, FUNCTION_FLAGS),
JS_FN("readAsBinaryString", ReadAsBinaryString, 1, FUNCTION_FLAGS),
JS_FN("readAsText", ReadAsText, 1, FUNCTION_FLAGS),
JS_FN("readAsDataURL", ReadAsDataURL, 1, FUNCTION_FLAGS),
JS_FS_END
};
} // anonymous namespace
BEGIN_WORKERS_NAMESPACE
namespace filereadersync {
bool
InitClass(JSContext* aCx, JSObject* aGlobal)
{
return !!FileReaderSync::InitClass(aCx, aGlobal);
}
} // namespace filereadersync
END_WORKERS_NAMESPACE

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

@ -0,0 +1,58 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* William Chen <wchen@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_workers_filereadersync_h__
#define mozilla_dom_workers_filereadersync_h__
#include "Workers.h"
#include "jspubtd.h"
BEGIN_WORKERS_NAMESPACE
namespace filereadersync {
bool
InitClass(JSContext* aCx, JSObject* aGlobal);
} // namespace filereadersync
END_WORKERS_NAMESPACE
#endif // mozilla_dom_workers_filereadersync_h__

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

@ -0,0 +1,318 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* William Chen <wchen@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "FileReaderSyncPrivate.h"
#include "nsCExternalHandlerService.h"
#include "nsComponentManagerUtils.h"
#include "nsCOMPtr.h"
#include "nsDOMClassInfo.h"
#include "nsDOMError.h"
#include "nsIDOMFile.h"
#include "nsICharsetAlias.h"
#include "nsICharsetDetector.h"
#include "nsIConverterInputStream.h"
#include "nsIInputStream.h"
#include "nsIPlatformCharset.h"
#include "nsISeekableStream.h"
#include "nsISupportsImpl.h"
#include "nsISupportsImpl.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "RuntimeService.h"
#include "mozilla/Base64.h"
USING_WORKERS_NAMESPACE
NS_IMPL_ISUPPORTS1(FileReaderSyncPrivate, nsICharsetDetectionObserver)
FileReaderSyncPrivate::FileReaderSyncPrivate()
{
MOZ_COUNT_CTOR(mozilla::dom::workers::FileReaderSyncPrivate);
}
FileReaderSyncPrivate::~FileReaderSyncPrivate()
{
MOZ_COUNT_DTOR(mozilla::dom::workers::FileReaderSyncPrivate);
}
nsresult
FileReaderSyncPrivate::ReadAsArrayBuffer(nsIDOMBlob* aBlob, PRUint32 aLength,
uint8* aBuffer)
{
nsCOMPtr<nsIInputStream> stream;
nsresult rv = aBlob->GetInternalStream(getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 numRead;
rv = stream->Read((char*)aBuffer, aLength, &numRead);
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(numRead == aLength, "failed to read data");
return NS_OK;
}
nsresult
FileReaderSyncPrivate::ReadAsBinaryString(nsIDOMBlob* aBlob, nsAString& aResult)
{
nsCOMPtr<nsIInputStream> stream;
nsresult rv = aBlob->GetInternalStream(getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 numRead;
do {
char readBuf[4096];
rv = stream->Read(readBuf, sizeof(readBuf), &numRead);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 oldLength = aResult.Length();
AppendASCIItoUTF16(Substring(readBuf, readBuf + numRead), aResult);
if (aResult.Length() - oldLength != numRead) {
return NS_ERROR_OUT_OF_MEMORY;
}
} while (numRead > 0);
return NS_OK;
}
nsresult
FileReaderSyncPrivate::ReadAsText(nsIDOMBlob* aBlob,
const nsAString& aEncoding, nsAString& aResult)
{
nsCOMPtr<nsIInputStream> stream;
nsresult rv = aBlob->GetInternalStream(getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
nsCString charsetGuess;
if (aEncoding.IsEmpty()) {
rv = GuessCharset(stream, charsetGuess);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(stream);
NS_ENSURE_TRUE(seekable, NS_ERROR_FAILURE);
// Seek to 0 because guessing the charset advances the stream.
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
NS_ENSURE_SUCCESS(rv, rv);
} else {
CopyUTF16toUTF8(aEncoding, charsetGuess);
}
nsCOMPtr<nsICharsetAlias> alias =
do_GetService(NS_CHARSETALIAS_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCString charset;
rv = alias->GetPreferred(charsetGuess, charset);
NS_ENSURE_SUCCESS(rv, rv);
return ConvertStream(stream, charset.get(), aResult);
}
nsresult
FileReaderSyncPrivate::ReadAsDataURL(nsIDOMBlob* aBlob, nsAString& aResult)
{
nsAutoString scratchResult;
scratchResult.AssignLiteral("data:");
nsString contentType;
aBlob->GetType(contentType);
if (contentType.IsEmpty()) {
scratchResult.AppendLiteral("application/octet-stream");
} else {
scratchResult.Append(contentType);
}
scratchResult.AppendLiteral(";base64,");
nsCOMPtr<nsIInputStream> stream;
nsresult rv = aBlob->GetInternalStream(getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
PRUint64 size;
rv = aBlob->GetSize(&size);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIInputStream> bufferedStream;
rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), stream, size);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString encodedData;
rv = Base64EncodeInputStream(bufferedStream, encodedData, size);
NS_ENSURE_SUCCESS(rv, rv);
scratchResult.Append(encodedData);
aResult = scratchResult;
return NS_OK;
}
nsresult
FileReaderSyncPrivate::ConvertStream(nsIInputStream *aStream,
const char *aCharset,
nsAString &aResult)
{
nsCOMPtr<nsIConverterInputStream> converterStream =
do_CreateInstance("@mozilla.org/intl/converter-input-stream;1");
NS_ENSURE_TRUE(converterStream, NS_ERROR_FAILURE);
nsresult rv = converterStream->Init(aStream, aCharset, 8192,
nsIConverterInputStream::DEFAULT_REPLACEMENT_CHARACTER);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIUnicharInputStream> unicharStream =
do_QueryInterface(converterStream);
NS_ENSURE_TRUE(unicharStream, NS_ERROR_FAILURE);
PRUint32 numChars;
nsString result;
while (NS_SUCCEEDED(unicharStream->ReadString(8192, result, &numChars)) &&
numChars > 0) {
PRUint32 oldLength = aResult.Length();
aResult.Append(result);
if (aResult.Length() - oldLength != result.Length()) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
return rv;
}
nsresult
FileReaderSyncPrivate::GuessCharset(nsIInputStream *aStream,
nsACString &aCharset)
{
// First try the universal charset detector
nsCOMPtr<nsICharsetDetector> detector
= do_CreateInstance(NS_CHARSET_DETECTOR_CONTRACTID_BASE
"universal_charset_detector");
if (!detector) {
RuntimeService* runtime = RuntimeService::GetService();
NS_ASSERTION(runtime, "This should never be null!");
// No universal charset detector, try the default charset detector
const nsACString& detectorName = runtime->GetDetectorName();
if (!detectorName.IsEmpty()) {
nsCAutoString detectorContractID;
detectorContractID.AssignLiteral(NS_CHARSET_DETECTOR_CONTRACTID_BASE);
detectorContractID += detectorName;
detector = do_CreateInstance(detectorContractID.get());
}
}
nsresult rv;
if (detector) {
detector->Init(this);
PRBool done;
PRUint32 numRead;
do {
char readBuf[4096];
rv = aStream->Read(readBuf, sizeof(readBuf), &numRead);
NS_ENSURE_SUCCESS(rv, rv);
if (numRead <= 0) {
break;
}
rv = detector->DoIt(readBuf, numRead, &done);
NS_ENSURE_SUCCESS(rv, rv);
} while (!done);
rv = detector->Done();
NS_ENSURE_SUCCESS(rv, rv);
} else {
// no charset detector available, check the BOM
unsigned char sniffBuf[4];
PRUint32 numRead;
rv = aStream->Read(reinterpret_cast<char*>(sniffBuf),
sizeof(sniffBuf), &numRead);
NS_ENSURE_SUCCESS(rv, rv);
if (numRead >= 4 &&
sniffBuf[0] == 0x00 &&
sniffBuf[1] == 0x00 &&
sniffBuf[2] == 0xfe &&
sniffBuf[3] == 0xff) {
mCharset = "UTF-32BE";
} else if (numRead >= 4 &&
sniffBuf[0] == 0xff &&
sniffBuf[1] == 0xfe &&
sniffBuf[2] == 0x00 &&
sniffBuf[3] == 0x00) {
mCharset = "UTF-32LE";
} else if (numRead >= 2 &&
sniffBuf[0] == 0xfe &&
sniffBuf[1] == 0xff) {
mCharset = "UTF-16BE";
} else if (numRead >= 2 &&
sniffBuf[0] == 0xff &&
sniffBuf[1] == 0xfe) {
mCharset = "UTF-16LE";
} else if (numRead >= 3 &&
sniffBuf[0] == 0xef &&
sniffBuf[1] == 0xbb &&
sniffBuf[2] == 0xbf) {
mCharset = "UTF-8";
}
}
if (mCharset.IsEmpty()) {
RuntimeService* runtime = RuntimeService::GetService();
mCharset = runtime->GetSystemCharset();
}
if (mCharset.IsEmpty()) {
// no sniffed or default charset, try UTF-8
mCharset.AssignLiteral("UTF-8");
}
aCharset = mCharset;
mCharset.Truncate();
return NS_OK;
}
NS_IMETHODIMP
FileReaderSyncPrivate::Notify(const char* aCharset, nsDetectionConfident aConf)
{
mCharset.Assign(aCharset);
return NS_OK;
}

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

@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* William Chen <wchen@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsDOMFileReaderSyncPrivate_h
#define nsDOMFileReaderSyncPrivate_h
#include "Workers.h"
#include "nsICharsetDetectionObserver.h"
#include "nsStringGlue.h"
class nsIInputStream;
class nsIDOMBlob;
BEGIN_WORKERS_NAMESPACE
class FileReaderSyncPrivate : public PrivatizableBase,
public nsICharsetDetectionObserver
{
nsCString mCharset;
nsresult ConvertStream(nsIInputStream *aStream, const char *aCharset,
nsAString &aResult);
nsresult GuessCharset(nsIInputStream *aStream, nsACString &aCharset);
public:
NS_DECL_ISUPPORTS
FileReaderSyncPrivate();
~FileReaderSyncPrivate();
nsresult ReadAsArrayBuffer(nsIDOMBlob* aBlob, PRUint32 aLength,
uint8* aBuffer);
nsresult ReadAsBinaryString(nsIDOMBlob* aBlob, nsAString& aResult);
nsresult ReadAsText(nsIDOMBlob* aBlob, const nsAString& aEncoding,
nsAString& aResult);
nsresult ReadAsDataURL(nsIDOMBlob* aBlob, nsAString& aResult);
// From nsICharsetDetectionObserver
NS_IMETHOD Notify(const char *aCharset, nsDetectionConfident aConf);
};
END_WORKERS_NAMESPACE
#endif

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

@ -57,6 +57,9 @@ CPPSRCS = \
Events.cpp \
EventTarget.cpp \
Exceptions.cpp \
File.cpp \
FileReaderSync.cpp \
FileReaderSyncPrivate.cpp \
ListenerManager.cpp \
Location.cpp \
Navigator.cpp \

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

@ -1,4 +1,5 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -42,6 +43,7 @@
#include "nsIDocument.h"
#include "nsIEffectiveTLDService.h"
#include "nsIObserverService.h"
#include "nsIPlatformCharset.h"
#include "nsIPrincipal.h"
#include "nsIJSContextStack.h"
#include "nsIMemoryReporter.h"
@ -243,15 +245,6 @@ CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate)
return nsnull;
}
// ChromeWorker has extra clone callbacks for passing threadsafe XPCOM
// components.
JSStructuredCloneCallbacks* callbacks =
aWorkerPrivate->IsChromeWorker() ?
ChromeWorkerStructuredCloneCallbacks() :
WorkerStructuredCloneCallbacks();
JS_SetStructuredCloneCallbacks(runtime, callbacks);
JSContext* workerCx = JS_NewContext(runtime, 0);
if (!workerCx) {
JS_DestroyRuntime(runtime);
@ -930,6 +923,15 @@ RuntimeService::Init()
MAX_WORKERS_PER_DOMAIN);
gMaxWorkersPerDomain = NS_MAX(0, maxPerDomain);
mDetectorName = Preferences::GetLocalizedCString("intl.charset.detector");
nsCOMPtr<nsIPlatformCharset> platformCharset =
do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
rv = platformCharset->GetCharset(kPlatformCharsetSel_PlainTextInFile,
mSystemCharset);
}
return NS_OK;
}

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

@ -1,4 +1,5 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -99,6 +100,9 @@ class RuntimeService : public nsIObserver
// Only used on the main thread.
nsCOMPtr<nsITimer> mIdleThreadTimer;
nsCString mDetectorName;
nsCString mSystemCharset;
static PRUint32 sDefaultJSContextOptions;
static PRInt32 sCloseHandlerTimeoutSeconds;
@ -148,6 +152,18 @@ public:
void
ResumeWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
const nsACString&
GetDetectorName() const
{
return mDetectorName;
}
const nsACString&
GetSystemCharset() const
{
return mSystemCharset;
}
const NavigatorStrings&
GetNavigatorStrings() const
{

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

@ -1,4 +1,5 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -40,6 +41,7 @@
#include "nsIClassInfo.h"
#include "nsIConsoleService.h"
#include "nsIDOMFile.h"
#include "nsIDocument.h"
#include "nsIEffectiveTLDService.h"
#include "nsIJSContextStack.h"
@ -68,6 +70,7 @@
#include "Events.h"
#include "Exceptions.h"
#include "File.h"
#include "Principal.h"
#include "RuntimeService.h"
#include "ScriptLoader.h"
@ -143,6 +146,57 @@ struct WorkerStructuredCloneCallbacks
Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32 aTag,
uint32 aData, void* aClosure)
{
// See if object is a nsIDOMFile pointer.
if (aTag == DOMWORKER_SCTAG_FILE) {
JS_ASSERT(!aData);
nsIDOMFile* file;
if (JS_ReadBytes(aReader, &file, sizeof(file))) {
JS_ASSERT(file);
#ifdef DEBUG
{
// File should not be mutable.
nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file);
PRBool isMutable;
NS_ASSERTION(NS_SUCCEEDED(mutableFile->GetMutable(&isMutable)) &&
!isMutable,
"Only immutable file should be passed to worker");
}
#endif
// nsIDOMFiles should be threadsafe, thus we will use the same instance
// in the worker.
JSObject* jsFile = file::CreateFile(aCx, file);
return jsFile;
}
}
// See if object is a nsIDOMBlob pointer.
else if (aTag == DOMWORKER_SCTAG_BLOB) {
JS_ASSERT(!aData);
nsIDOMBlob* blob;
if (JS_ReadBytes(aReader, &blob, sizeof(blob))) {
JS_ASSERT(blob);
#ifdef DEBUG
{
// Blob should not be mutable.
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob);
PRBool isMutable;
NS_ASSERTION(NS_SUCCEEDED(mutableBlob->GetMutable(&isMutable)) &&
!isMutable,
"Only immutable blob should be passed to worker");
}
#endif
// nsIDOMBlob should be threadsafe, thus we will use the same instance
// in the worker.
JSObject* jsBlob = file::CreateBlob(aCx, blob);
return jsBlob;
}
}
Error(aCx, 0);
return nsnull;
}
@ -151,6 +205,38 @@ struct WorkerStructuredCloneCallbacks
Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, JSObject* aObj,
void* aClosure)
{
NS_ASSERTION(aClosure, "Null pointer!");
// We'll stash any nsISupports pointers that need to be AddRef'd here.
nsTArray<nsCOMPtr<nsISupports> >* clonedObjects =
static_cast<nsTArray<nsCOMPtr<nsISupports> >*>(aClosure);
// See if this is a File object.
{
nsIDOMFile* file = file::GetDOMFileFromJSObject(aCx, aObj);
if (file) {
if (JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_FILE, 0) &&
JS_WriteBytes(aWriter, &file, sizeof(file))) {
clonedObjects->AppendElement(file);
return true;
}
}
}
// See if this is a Blob object.
{
nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aCx, aObj);
if (blob) {
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob);
if (mutableBlob && NS_SUCCEEDED(mutableBlob->SetMutable(PR_FALSE)) &&
JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0) &&
JS_WriteBytes(aWriter, &blob, sizeof(blob))) {
clonedObjects->AppendElement(blob);
return true;
}
}
}
Error(aCx, 0);
return false;
}
@ -176,6 +262,73 @@ struct MainThreadWorkerStructuredCloneCallbacks
{
AssertIsOnMainThread();
// See if object is a nsIDOMFile pointer.
if (aTag == DOMWORKER_SCTAG_FILE) {
JS_ASSERT(!aData);
nsIDOMFile* file;
if (JS_ReadBytes(aReader, &file, sizeof(file))) {
JS_ASSERT(file);
#ifdef DEBUG
{
// File should not be mutable.
nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file);
PRBool isMutable;
NS_ASSERTION(NS_SUCCEEDED(mutableFile->GetMutable(&isMutable)) &&
!isMutable,
"Only immutable file should be passed to worker");
}
#endif
// nsIDOMFiles should be threadsafe, thus we will use the same instance
// on the main thread.
jsval wrappedFile;
nsresult rv =
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), file,
&NS_GET_IID(nsIDOMFile), &wrappedFile);
if (NS_FAILED(rv)) {
Error(aCx, DATA_CLONE_ERR);
return nsnull;
}
return JSVAL_TO_OBJECT(wrappedFile);
}
}
// See if object is a nsIDOMBlob pointer.
else if (aTag == DOMWORKER_SCTAG_BLOB) {
JS_ASSERT(!aData);
nsIDOMBlob* blob;
if (JS_ReadBytes(aReader, &blob, sizeof(blob))) {
JS_ASSERT(blob);
#ifdef DEBUG
{
// Blob should not be mutable.
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob);
PRBool isMutable;
NS_ASSERTION(NS_SUCCEEDED(mutableBlob->GetMutable(&isMutable)) &&
!isMutable,
"Only immutable blob should be passed to worker");
}
#endif
// nsIDOMBlobs should be threadsafe, thus we will use the same instance
// on the main thread.
jsval wrappedBlob;
nsresult rv =
nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), blob,
&NS_GET_IID(nsIDOMBlob), &wrappedBlob);
if (NS_FAILED(rv)) {
Error(aCx, DATA_CLONE_ERR);
return nsnull;
}
return JSVAL_TO_OBJECT(wrappedBlob);
}
}
JSObject* clone =
WorkerStructuredCloneCallbacks::Read(aCx, aReader, aTag, aData, aClosure);
if (clone) {
@ -192,6 +345,51 @@ struct MainThreadWorkerStructuredCloneCallbacks
{
AssertIsOnMainThread();
NS_ASSERTION(aClosure, "Null pointer!");
// We'll stash any nsISupports pointers that need to be AddRef'd here.
nsTArray<nsCOMPtr<nsISupports> >* clonedObjects =
static_cast<nsTArray<nsCOMPtr<nsISupports> >*>(aClosure);
// See if this is a wrapped native.
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
nsContentUtils::XPConnect()->
GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative));
if (wrappedNative) {
// Get the raw nsISupports out of it.
nsISupports* wrappedObject = wrappedNative->Native();
NS_ASSERTION(wrappedObject, "Null pointer?!");
// See if the wrapped native is a nsIDOMFile.
nsCOMPtr<nsIDOMFile> file = do_QueryInterface(wrappedObject);
if (file) {
nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file);
if (mutableFile && NS_SUCCEEDED(mutableFile->SetMutable(PR_FALSE))) {
nsIDOMFile* filePtr = file;
if (JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_FILE, 0) &&
JS_WriteBytes(aWriter, &filePtr, sizeof(filePtr))) {
clonedObjects->AppendElement(file);
return true;
}
}
}
// See if the wrapped native is a nsIDOMBlob.
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(wrappedObject);
if (blob) {
nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob);
if (mutableBlob && NS_SUCCEEDED(mutableBlob->SetMutable(PR_FALSE))) {
nsIDOMBlob* blobPtr = blob;
if (JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0) &&
JS_WriteBytes(aWriter, &blobPtr, sizeof(blobPtr))) {
clonedObjects->AppendElement(blob);
return true;
}
}
}
}
JSBool ok =
WorkerStructuredCloneCallbacks::Write(aCx, aWriter, aObj, aClosure);
if (ok) {
@ -519,15 +717,21 @@ class MessageEventRunnable : public WorkerRunnable
{
uint64* mData;
size_t mDataByteCount;
nsTArray<nsCOMPtr<nsISupports> > mClonedObjects;
public:
MessageEventRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget,
JSAutoStructuredCloneBuffer& aData)
JSAutoStructuredCloneBuffer& aData,
nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects)
: WorkerRunnable(aWorkerPrivate, aTarget, aTarget == WorkerThread ?
ModifyBusyCount :
UnchangedBusyCount)
{
aData.steal(&mData, &mDataByteCount);
if (!mClonedObjects.SwapElements(aClonedObjects)) {
NS_ERROR("This should never fail!");
}
}
bool
@ -569,7 +773,8 @@ public:
NS_ASSERTION(target, "This should never be null!");
JSObject* event = events::CreateMessageEvent(aCx, buffer, mainRuntime);
JSObject* event = events::CreateMessageEvent(aCx, buffer, mClonedObjects,
mainRuntime);
if (!event) {
return false;
}
@ -1390,7 +1595,7 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
mJSObject(aObject), mParent(aParent), mParentJSContext(aParentJSContext),
mScriptURL(aScriptURL), mDomain(aDomain), mBusyCount(0),
mParentStatus(Pending), mJSObjectRooted(false), mParentSuspended(false),
mIsChromeWorker(aIsChromeWorker)
mIsChromeWorker(aIsChromeWorker), mPrincipalIsSystem(false)
{
MOZ_COUNT_CTOR(mozilla::dom::workers::WorkerPrivateParent);
@ -1693,7 +1898,12 @@ WorkerPrivateParent<Derived>::PostMessage(JSContext* aCx, jsval aMessage)
JSStructuredCloneCallbacks* callbacks;
if (GetParent()) {
callbacks = nsnull;
if (IsChromeWorker()) {
callbacks = &gChromeWorkerStructuredCloneCallbacks;
}
else {
callbacks = &gWorkerStructuredCloneCallbacks;
}
}
else {
AssertIsOnMainThread();
@ -1706,14 +1916,17 @@ WorkerPrivateParent<Derived>::PostMessage(JSContext* aCx, jsval aMessage)
}
}
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
JSAutoStructuredCloneBuffer buffer;
if (!buffer.write(aCx, aMessage, callbacks, nsnull)) {
if (!buffer.write(aCx, aMessage, callbacks, &clonedObjects)) {
return false;
}
nsRefPtr<MessageEventRunnable> runnable =
new MessageEventRunnable(ParentAsWorkerPrivate(),
WorkerRunnable::WorkerThread, buffer);
WorkerRunnable::WorkerThread, buffer,
clonedObjects);
return runnable->Dispatch(aCx);
}
@ -1839,6 +2052,16 @@ WorkerPrivateParent<Derived>::SetBaseURI(nsIURI* aBaseURI)
return NS_OK;
}
template <class Derived>
void
WorkerPrivateParent<Derived>::SetPrincipal(nsIPrincipal* aPrincipal)
{
AssertIsOnMainThread();
mPrincipal = aPrincipal;
mPrincipalIsSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
}
template <class Derived>
JSContext*
WorkerPrivateParent<Derived>::ParentJSContext() const
@ -2629,13 +2852,21 @@ WorkerPrivate::PostMessageToParent(JSContext* aCx, jsval aMessage)
{
AssertIsOnWorkerThread();
JSStructuredCloneCallbacks* callbacks =
IsChromeWorker() ?
&gChromeWorkerStructuredCloneCallbacks :
&gWorkerStructuredCloneCallbacks;
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
JSAutoStructuredCloneBuffer buffer;
if (!buffer.write(aCx, aMessage, nsnull, nsnull)) {
if (!buffer.write(aCx, aMessage, callbacks, &clonedObjects)) {
return false;
}
nsRefPtr<MessageEventRunnable> runnable =
new MessageEventRunnable(this, WorkerRunnable::ParentThread, buffer);
new MessageEventRunnable(this, WorkerRunnable::ParentThread, buffer,
clonedObjects);
return runnable->Dispatch(aCx);
}
@ -3210,15 +3441,19 @@ GetWorkerPrivateFromContext(JSContext* aCx)
}
JSStructuredCloneCallbacks*
WorkerStructuredCloneCallbacks()
WorkerStructuredCloneCallbacks(bool aMainRuntime)
{
return &gWorkerStructuredCloneCallbacks;
return aMainRuntime ?
&gMainThreadWorkerStructuredCloneCallbacks :
&gWorkerStructuredCloneCallbacks;
}
JSStructuredCloneCallbacks*
ChromeWorkerStructuredCloneCallbacks()
ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime)
{
return &gChromeWorkerStructuredCloneCallbacks;
return aMainRuntime ?
&gMainThreadChromeWorkerStructuredCloneCallbacks :
&gChromeWorkerStructuredCloneCallbacks;
}
END_WORKERS_NAMESPACE

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

@ -219,6 +219,7 @@ private:
bool mJSObjectRooted;
bool mParentSuspended;
bool mIsChromeWorker;
bool mPrincipalIsSystem;
protected:
WorkerPrivateParent(JSContext* aCx, JSObject* aObject, WorkerPrivate* aParent,
@ -398,10 +399,12 @@ public:
}
void
SetPrincipal(nsIPrincipal* aPrincipal)
SetPrincipal(nsIPrincipal* aPrincipal);
bool
UsesSystemPrincipal() const
{
AssertIsOnMainThread();
mPrincipal = aPrincipal;
return mPrincipalIsSystem;
}
nsIDocument*
@ -745,11 +748,19 @@ private:
WorkerPrivate*
GetWorkerPrivateFromContext(JSContext* aCx);
JSStructuredCloneCallbacks*
WorkerStructuredCloneCallbacks();
enum WorkerStructuredDataType
{
DOMWORKER_SCTAG_FILE = JS_SCTAG_USER_MIN + 0x1000,
DOMWORKER_SCTAG_BLOB,
DOMWORKER_SCTAG_END
};
JSStructuredCloneCallbacks*
ChromeWorkerStructuredCloneCallbacks();
WorkerStructuredCloneCallbacks(bool aMainRuntime);
JSStructuredCloneCallbacks*
ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime);
END_WORKERS_NAMESPACE

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

@ -1,4 +1,5 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -49,6 +50,8 @@
#include "Events.h"
#include "EventTarget.h"
#include "Exceptions.h"
#include "File.h"
#include "FileReaderSync.h"
#include "ListenerManager.h"
#include "Location.h"
#include "Navigator.h"
@ -875,6 +878,8 @@ CreateDedicatedWorkerGlobalScope(JSContext* aCx)
// Init other classes we care about.
if (!events::InitClasses(aCx, global, false) ||
!file::InitClasses(aCx, global) ||
!filereadersync::InitClass(aCx, global) ||
!exceptions::InitClasses(aCx, global) ||
!xhr::InitClasses(aCx, global, eventTargetProto) ||
!location::InitClass(aCx, global) ||

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

@ -120,6 +120,24 @@ _SUBDIR_TEST_FILES = \
_CHROME_TEST_FILES = \
test_chromeWorker.xul \
test_chromeWorkerJSM.xul \
test_file.xul \
test_fileMozSlice.xul \
test_fileBlobPosting.xul \
test_filePosting.xul \
test_fileReaderSync.xul \
test_fileReaderSyncErrors.xul \
test_fileReadMozSlice.xul \
test_fileSubWorker.xul \
test_fileBlobSubWorker.xul \
file_worker.js \
fileBlob_worker.js \
fileMozSlice_worker.js \
filePosting_worker.js \
fileReaderSync_worker.js \
fileReaderSyncErrors_worker.js \
fileReadMozSlice_worker.js \
fileSubWorker_worker.js \
fileBlobSubWorker_worker.js \
WorkerTest.jsm \
WorkerTest_worker.js \
WorkerTest_subworker.js \

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

@ -0,0 +1,17 @@
/**
* Expects a blob. Returns an object containing the size, type.
* Used to test posting of blob from worker to worker.
*/
onmessage = function(event) {
var worker = new Worker("fileBlob_worker.js");
worker.postMessage(event.data);
worker.onmessage = function(event) {
postMessage(event.data);
}
worker.onerror = function(event) {
postMessage(undefined);
}
};

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

@ -0,0 +1,13 @@
/**
* Expects a blob. Returns an object containing the size, type.
*/
onmessage = function(event) {
var file = event.data;
var rtnObj = new Object();
rtnObj.size = file.size;
rtnObj.type = file.type;
postMessage(rtnObj);
};

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

@ -0,0 +1,27 @@
/**
* Expects an object containing a blob, a start offset, an end offset
* and an optional content type to slice the blob. Returns an object
* containing the size and type of the sliced blob.
*/
onmessage = function(event) {
var blob = event.data.blob;
var start = event.data.start;
var end = event.data.end;
var contentType = event.data.contentType;
var slicedBlob;
if (contentType == undefined && end == undefined) {
slicedBlob = blob.mozSlice(start);
} else if (contentType == undefined) {
slicedBlob = blob.mozSlice(start, end);
} else {
slicedBlob = blob.mozSlice(start, end, contentType);
}
var rtnObj = new Object();
rtnObj.size = slicedBlob.size;
rtnObj.type = slicedBlob.type;
postMessage(rtnObj);
};

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

@ -0,0 +1,3 @@
onmessage = function(event) {
postMessage(event.data);
};

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

@ -0,0 +1,16 @@
/**
* Expects an object containing a blob, a start index and an end index
* for slicing. Returns the contents of the blob read as text.
*/
onmessage = function(event) {
var blob = event.data.blob;
var start = event.data.start;
var end = event.data.end;
var slicedBlob = blob.mozSlice(start, end);
var fileReader = new FileReaderSync();
var text = fileReader.readAsText(slicedBlob);
postMessage(text);
};

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

@ -0,0 +1,79 @@
/**
* Delegates "is" evaluation back to main thread.
*/
function is(actual, expected, message) {
var rtnObj = new Object();
rtnObj.actual = actual;
rtnObj.expected = expected;
rtnObj.message = message;
postMessage(rtnObj);
}
/**
* Tries to write to property.
*/
function writeProperty(file, property) {
try {
var oldValue = file[property];
file[property] = -1;
is(false, true, "Should have thrown an exception setting a read only property.");
} catch (ex) {
is(true, true, "Should have thrown an exception setting a read only property.");
}
}
/**
* Passes junk arguments to FileReaderSync methods and expects an exception to
* be thrown.
*/
function fileReaderJunkArgument(blob) {
var fileReader = new FileReaderSync();
try {
fileReader.readAsBinaryString(blob);
is(false, true, "Should have thrown an exception calling readAsBinaryString.");
} catch(ex) {
is(true, true, "Should have thrown an exception.");
}
try {
fileReader.readAsDataURL(blob);
is(false, true, "Should have thrown an exception calling readAsDataURL.");
} catch(ex) {
is(true, true, "Should have thrown an exception.");
}
try {
fileReader.readAsArrayBuffer(blob);
is(false, true, "Should have thrown an exception calling readAsArrayBuffer.");
} catch(ex) {
is(true, true, "Should have thrown an exception.");
}
try {
fileReader.readAsText(blob);
is(false, true, "Should have thrown an exception calling readAsText.");
} catch(ex) {
is(true, true, "Should have thrown an exception.");
}
}
onmessage = function(event) {
var file = event.data;
// Test read only properties.
writeProperty(file, "size");
writeProperty(file, "type");
writeProperty(file, "name");
writeProperty(file, "mozFullPath");
// Bad types.
fileReaderJunkArgument(undefined);
fileReaderJunkArgument(-1);
fileReaderJunkArgument(1);
fileReaderJunkArgument(new Object());
fileReaderJunkArgument("hello");
// Post undefined to indicate that testing has finished.
postMessage(undefined);
};

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

@ -0,0 +1,25 @@
var reader = new FileReaderSync();
/**
* Expects an object containing a file and an encoding then uses a
* FileReaderSync to read the file. Returns an object containing the
* file read a binary string, text, url and ArrayBuffer.
*/
onmessage = function(event) {
var file = event.data.file;
var encoding = event.data.encoding;
var rtnObj = new Object();
if (encoding != undefined) {
rtnObj.text = reader.readAsText(file, encoding);
} else {
rtnObj.text = reader.readAsText(file);
}
rtnObj.bin = reader.readAsBinaryString(file);
rtnObj.url = reader.readAsDataURL(file);
rtnObj.arrayBuffer = reader.readAsArrayBuffer(file);
postMessage(rtnObj);
};

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

@ -0,0 +1,17 @@
/**
* Expects a file. Returns an object containing the size, type, name and path
* using another worker. Used to test posting of file from worker to worker.
*/
onmessage = function(event) {
var worker = new Worker("file_worker.js");
worker.postMessage(event.data);
worker.onmessage = function(event) {
postMessage(event.data);
}
worker.onerror = function(event) {
postMessage(undefined);
}
};

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

@ -0,0 +1,15 @@
/**
* Expects a file. Returns an object containing the size, type, name and path.
*/
onmessage = function(event) {
var file = event.data;
var rtnObj = new Object();
rtnObj.size = file.size;
rtnObj.type = file.type;
rtnObj.name = file.name;
rtnObj.mozFullPath = file.mozFullPath;
postMessage(rtnObj);
};

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

@ -0,0 +1,97 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=123456
-->
<window title="Mozilla Bug 123456"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=123456"
target="_blank">Mozilla Bug 123456</a>
<div id="content" style="display: none">
<input id="fileList" type="file"></input>
</div>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 123456 **/
var fileNum = 0;
/**
* Create a file which contains the given data and optionally adds the specified file extension.
*/
function createFileWithData(fileData, /** optional */ extension) {
var testFile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
var fileExtension = (extension == undefined) ? "" : "." + extension;
testFile.append("workerFile" + fileNum++ + fileExtension);
var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
0666, 0);
outStream.write(fileData, fileData.length);
outStream.close();
var fileList = document.getElementById('fileList');
fileList.value = testFile.path;
return fileList.files[0];
}
/**
* Create a worker to access file properties.
*/
function accessFileProperties(file, expectedSize, expectedType) {
var worker = new Worker("file_worker.js");
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
};
worker.onmessage = function(event) {
is(event.data.size, expectedSize, "size proproperty accessed from worker is not the same as on main thread.");
is(event.data.type, expectedType, "type proproperty accessed from worker is incorrect.");
is(event.data.name, file.name, "name proproperty accessed from worker is incorrect.");
is(event.data.mozFullPath, file.mozFullPath, "mozFullPath proproperty accessed from worker is not the same as on main thread.");
SimpleTest.finish();
};
worker.postMessage(file);
SimpleTest.waitForExplicitFinish();
}
// Empty file.
accessFileProperties(createFileWithData(""), 0, "");
// Typical use case.
accessFileProperties(createFileWithData("Hello"), 5, "");
// Longish file.
var text = "";
for (var i = 0; i < 10000; ++i) {
text += "long";
}
accessFileProperties(createFileWithData(text), 40000, "");
// Type detection based on extension.
accessFileProperties(createFileWithData("text", "txt"), 4, "text/plain");
]]>
</script>
</window>

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

@ -0,0 +1,87 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=664783
-->
<window title="Mozilla Bug 664783"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=664783"
target="_blank">Mozilla Bug 664783</a>
<div id="content" style="display: none">
<input id="fileList" type="file"></input>
</div>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 664783 **/
var fileNum = 0;
/**
* Create a file which contains the given data.
*/
function createFileWithData(fileData) {
var testFile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
testFile.append("workerBlobPosting" + fileNum++);
var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
0666, 0);
outStream.write(fileData, fileData.length);
outStream.close();
var fileList = document.getElementById('fileList');
fileList.value = testFile.path;
return fileList.files[0];
}
/**
* Create a worker which posts the same blob given. Used to test cloning of blobs.
* Checks the size, type, name and path of the file posted from the worker to ensure it
* is the same as the original.
*/
function postBlob(file) {
var worker = new Worker("filePosting_worker.js");
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
};
worker.onmessage = function(event) {
console.log(event.data);
is(event.data.size, file.size, "size of file posted from worker does not match file posted to worker.");
SimpleTest.finish();
};
var blob = file.mozSlice();
worker.postMessage(blob);
SimpleTest.waitForExplicitFinish();
}
// Empty file.
postBlob(createFileWithData(""));
// Typical use case.
postBlob(createFileWithData("Hello"));
]]>
</script>
</window>

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

@ -0,0 +1,99 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=664783
-->
<window title="Mozilla Bug 664783"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=664783"
target="_blank">Mozilla Bug 664783</a>
<div id="content" style="display: none">
<input id="fileList" type="file"></input>
</div>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 664783 **/
var fileNum = 0;
/**
* Create a file which contains the given data and optionally adds the specified file extension.
*/
function createFileWithData(fileData, /** optional */ extension) {
var testFile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
var fileExtension = (extension == undefined) ? "" : "." + extension;
testFile.append("workerBlobSubWorker" + fileNum++ + fileExtension);
var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
0666, 0);
outStream.write(fileData, fileData.length);
outStream.close();
var fileList = document.getElementById('fileList');
fileList.value = testFile.path;
return fileList.files[0];
}
/**
* Create a worker to access blob properties.
*/
function accessFileProperties(file, expectedSize) {
var worker = new Worker("fileBlobSubWorker_worker.js");
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
};
worker.onmessage = function(event) {
if (event.data == undefined) {
ok(false, "Worker had an error.");
} else {
is(event.data.size, expectedSize, "size proproperty accessed from worker is not the same as on main thread.");
}
SimpleTest.finish();
};
var blob = file.mozSlice();
worker.postMessage(blob);
SimpleTest.waitForExplicitFinish();
}
// Empty file.
accessFileProperties(createFileWithData(""), 0);
// Typical use case.
accessFileProperties(createFileWithData("Hello"), 5);
// Longish file.
var text = "";
for (var i = 0; i < 10000; ++i) {
text += "long";
}
accessFileProperties(createFileWithData(text), 40000);
// Type detection based on extension.
accessFileProperties(createFileWithData("text", "txt"), 4);
]]>
</script>
</window>

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

@ -0,0 +1,107 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=664783
-->
<window title="Mozilla Bug 664783"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=664783"
target="_blank">Mozilla Bug 664783</a>
<div id="content" style="display: none">
<input id="fileList" type="file"></input>
</div>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 664783 **/
var fileNum = 0;
/**
* Create a file which contains the given data and optionally adds the specified file extension.
*/
function createFileWithData(fileData, /** optional */ extension) {
var testFile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
var fileExtension = (extension == undefined) ? "" : "." + extension;
testFile.append("workerMozSlice" + fileNum++ + fileExtension);
var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
0666, 0);
outStream.write(fileData, fileData.length);
outStream.close();
var fileList = document.getElementById('fileList');
fileList.value = testFile.path;
return fileList.files[0];
}
/**
* Starts a worker which slices the blob to the given start offset and optional end offset and
* content type. It then verifies that the size and type of the sliced blob is correct.
*/
function createMozSlice(blob, start, expectedLength, /** optional */ end, /** optional */ contentType) {
var worker = new Worker("fileMozSlice_worker.js");
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
};
worker.onmessage = function(event) {
is(event.data.size, expectedLength, "size property of slice is incorrect.");
is(event.data.type, contentType ? contentType : blob.type, "type property of slice is incorrect.");
SimpleTest.finish();
};
var params = {blob: blob, start: start, end: end, contentType: contentType};
worker.postMessage(params);
SimpleTest.waitForExplicitFinish();
}
// Empty file.
createMozSlice(createFileWithData(""), 0, 0, 0);
// Typical use case.
createMozSlice(createFileWithData("Hello"), 1, 1, 2);
// Longish file.
var text = "";
for (var i = 0; i < 10000; ++i) {
text += "long";
}
createMozSlice(createFileWithData(text), 2000, 2000, 4000);
// Slice to different type.
createMozSlice(createFileWithData("text", "txt"), 0, 2, 2, "image/png");
// Length longer than blob.
createMozSlice(createFileWithData("text"), 0, 4, 20);
// Start longer than blob.
createMozSlice(createFileWithData("text"), 20, 0, 4);
// No optional arguments
createMozSlice(createFileWithData("text"), 0, 4);
createMozSlice(createFileWithData("text"), 2, 2);
]]>
</script>
</window>

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

@ -0,0 +1,88 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=664783
-->
<window title="Mozilla Bug 664783"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=664783"
target="_blank">Mozilla Bug 664783</a>
<div id="content" style="display: none">
<input id="fileList" type="file"></input>
</div>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 664783 **/
var fileNum = 0;
/**
* Create a file which contains the given data.
*/
function createFileWithData(fileData) {
var testFile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
testFile.append("workerFilePosting" + fileNum++);
var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
0666, 0);
outStream.write(fileData, fileData.length);
outStream.close();
var fileList = document.getElementById('fileList');
fileList.value = testFile.path;
return fileList.files[0];
}
/**
* Create a worker which posts the same file given. Used to test cloning of files.
* Checks the size, type, name and path of the file posted from the worker to ensure it
* is the same as the original.
*/
function postFile(file) {
var worker = new Worker("file_worker.js");
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
};
worker.onmessage = function(event) {
is(event.data.size, file.size, "size of file posted from worker does not match file posted to worker.");
is(event.data.type, file.type, "type of file posted from worker does not match file posted to worker.");
is(event.data.name, file.name, "name of file posted from worker does not match file posted to worker.");
is(event.data.mozFullPath, file.mozFullPath, "mozFullPath of file posted from worker does not match file posted to worker.");
SimpleTest.finish();
};
worker.postMessage(file);
SimpleTest.waitForExplicitFinish();
}
// Empty file.
postFile(createFileWithData(""));
// Typical use case.
postFile(createFileWithData("Hello"));
]]>
</script>
</window>

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

@ -0,0 +1,91 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=664783
-->
<window title="Mozilla Bug 664783"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=664783"
target="_blank">Mozilla Bug 664783</a>
<div id="content" style="display: none">
<input id="fileList" type="file"></input>
</div>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 664783 **/
var fileNum = 0;
/**
* Create a file which contains the given data.
*/
function createFileWithData(fileData) {
var testFile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
testFile.append("workerReadMozSlice" + fileNum++);
var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
0666, 0);
outStream.write(fileData, fileData.length);
outStream.close();
var fileList = document.getElementById('fileList');
fileList.value = testFile.path;
return fileList.files[0];
}
/**
* Creates a worker which slices a blob to the given start and end offset and
* reads the content as text.
*/
function readMozSlice(blob, start, end, expectedText) {
var worker = new Worker("fileReadMozSlice_worker.js");
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
};
worker.onmessage = function(event) {
is(event.data, expectedText, "Text from sliced blob in worker is incorrect.");
SimpleTest.finish();
};
var params = {blob: blob, start: start, end: end};
worker.postMessage(params);
SimpleTest.waitForExplicitFinish();
}
// Empty file.
readMozSlice(createFileWithData(""), 0, 0, "");
// Typical use case.
readMozSlice(createFileWithData("HelloBye"), 5, 8, "Bye");
// End offset too large.
readMozSlice(createFileWithData("HelloBye"), 5, 9, "Bye");
// Start of file.
readMozSlice(createFileWithData("HelloBye"), 0, 5, "Hello");
]]>
</script>
</window>

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

@ -0,0 +1,200 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=664783
-->
<window title="Mozilla Bug 664783"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=664783"
target="_blank">Mozilla Bug 664783</a>
<div id="content" style="display: none">
<input id="fileList" type="file"></input>
</div>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 664783 **/
var fileNum = 0;
/**
* Create a file which contains the given data and optionally adds the specified file extension.
*/
function createFileWithData(fileData, /** optional */ extension) {
var testFile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
var fileExtension = (extension == undefined) ? "" : "." + extension;
testFile.append("workerFileReaderSync" + fileNum++ + fileExtension);
var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
0666, 0);
outStream.write(fileData, fileData.length);
outStream.close();
var fileList = document.getElementById('fileList');
fileList.value = testFile.path;
return fileList.files[0];
}
function convertToUTF16(s) {
res = "";
for (var i = 0; i < s.length; ++i) {
c = s.charCodeAt(i);
res += String.fromCharCode(c >>> 8, c & 255);
}
return res;
}
/**
* Converts the given string to a data URL of the specified mime type.
*/
function convertToDataURL(mime, s) {
return "data:" + mime + ";base64," + btoa(s);
}
/**
* Create a worker to read a file containing fileData using FileReaderSync and
* checks the return type against the expected type. Optionally set an encoding
* for reading the file as text.
*/
function readFileData(fileData, expectedText, /** optional */ encoding) {
var worker = new Worker("fileReaderSync_worker.js");
worker.onmessage = function(event) {
is(event.data.text, expectedText, "readAsText in worker returned incorrect result.");
is(event.data.bin, fileData, "readAsBinaryString in worker returned incorrect result.");
is(event.data.url, convertToDataURL("application/octet-stream", fileData), "readAsDataURL in worker returned incorrect result.");
is(event.data.arrayBuffer.byteLength, fileData.length, "readAsArrayBuffer returned buffer of incorrect length.");
SimpleTest.finish();
};
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
};
var params = {file: createFileWithData(fileData), encoding: encoding};
worker.postMessage(params);
SimpleTest.waitForExplicitFinish();
}
/**
* Create a worker which reuses a FileReaderSync to read multiple files as DataURLs.
*/
function reuseReaderForURL(files, expected) {
var worker = new Worker("fileReaderSync_worker.js");
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
};
var k = 0;
worker.onmessage = function(event) {
is(event.data.url, expected[k], "readAsDataURL in worker returned incorrect result when reusing FileReaderSync.");
k++;
SimpleTest.finish();
};
for (var i = 0; i < files.length; ++i) {
var params = {file: files[i], encoding: undefined};
worker.postMessage(params);
SimpleTest.waitForExplicitFinish();
}
}
/**
* Create a worker which reuses a FileReaderSync to read multiple files as text.
*/
function reuseReaderForText(fileData, expected) {
var worker = new Worker("fileReaderSync_worker.js");
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
};
var k = 0;
worker.onmessage = function(event) {
is(event.data.text, expected[k++], "readAsText in worker returned incorrect result when reusing FileReaderSync.");
SimpleTest.finish();
};
for (var i = 0; i < fileData.length; ++i) {
var params = {file: createFileWithData(fileData[i]), encoding: undefined};
worker.postMessage(params);
SimpleTest.waitForExplicitFinish();
}
}
/**
* Creates a a worker which reads a file containing fileData as an ArrayBuffer.
* Verifies that the ArrayBuffer when interpreted as a string matches the original data.
*/
function readArrayBuffer(fileData) {
var worker = new Worker("fileReaderSync_worker.js");
worker.onmessage = function(event) {
var view = new Uint8Array(event.data.arrayBuffer);
is(event.data.arrayBuffer.byteLength, fileData.length, "readAsArrayBuffer returned buffer of incorrect length.");
is(String.fromCharCode.apply(String, view), fileData, "readAsArrayBuffer returned buffer containing incorrect data.");
SimpleTest.finish();
};
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
};
var params = {file: createFileWithData(fileData), encoding: undefined};
worker.postMessage(params);
SimpleTest.waitForExplicitFinish();
}
// Empty file.
readFileData("", "");
// Typical use case.
readFileData("text", "text");
// Test reading UTF-16 characters.
readFileData(convertToUTF16("text"), "text", "UTF-16");
// First read a file of type "text/plain", then read a file of type "application/octet-stream".
reuseReaderForURL([createFileWithData("text", "txt"), createFileWithData("text")],
[convertToDataURL("text/plain", "text"),
convertToDataURL("application/octet-stream", "text")]);
// First read UTF-16 characters marked using BOM, then read UTF-8 characters.
reuseReaderForText([convertToUTF16("\ufefftext"), "text"],
["text", "text"]);
// Reading data as ArrayBuffer.
readArrayBuffer("");
readArrayBuffer("text");
]]>
</script>
</window>

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

@ -0,0 +1,85 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=664783
-->
<window title="Mozilla Bug 664783"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=664783"
target="_blank">Mozilla Bug 664783</a>
<div id="content" style="display: none">
<input id="fileList" type="file"></input>
</div>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 664783 **/
var fileNum = 0;
/**
* Create a file which contains the given data.
*/
function createFileWithData(fileData) {
var testFile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
testFile.append("workerFileReaderSyncErrors" + fileNum++);
var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
0666, 0);
outStream.write(fileData, fileData.length);
outStream.close();
var fileList = document.getElementById('fileList');
fileList.value = testFile.path;
return fileList.files[0];
}
/**
* Creates a worker which runs errors cases.
*/
function runWorkerErrors(file) {
var worker = new Worker("fileReaderSyncErrors_worker.js");
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
};
worker.onmessage = function(event) {
if(event.data == undefined) {
// Worker returns undefined when tests have finished running.
SimpleTest.finish();
} else {
// Otherwise worker will return results of tests to be evaluated.
is(event.data.actual, event.data.expected, event.data.message);
}
};
worker.postMessage(file);
SimpleTest.waitForExplicitFinish();
}
// Run worker which creates exceptions.
runWorkerErrors(createFileWithData("text"));
]]>
</script>
</window>

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

@ -0,0 +1,101 @@
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=664783
-->
<window title="Mozilla Bug 664783"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=664783"
target="_blank">Mozilla Bug 664783</a>
<div id="content" style="display: none">
<input id="fileList" type="file"></input>
</div>
</body>
<!-- test code goes here -->
<script type="application/javascript">
<![CDATA[
/** Test for Bug 664783 **/
var fileNum = 0;
/**
* Create a file which contains the given data and optionally adds the specified file extension.
*/
function createFileWithData(fileData, /** optional */ extension) {
var testFile = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("ProfD", Components.interfaces.nsIFile);
var fileExtension = (extension == undefined) ? "" : "." + extension;
testFile.append("workerSubWorker" + fileNum++ + fileExtension);
var outStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
0666, 0);
outStream.write(fileData, fileData.length);
outStream.close();
var fileList = document.getElementById('fileList');
fileList.value = testFile.path;
return fileList.files[0];
}
/**
* Create a worker to access file properties.
*/
function accessFileProperties(file, expectedSize, expectedType) {
var worker = new Worker("fileSubWorker_worker.js");
worker.onerror = function(event) {
ok(false, "Worker had an error: " + event.data);
SimpleTest.finish();
};
worker.onmessage = function(event) {
if (event.data == undefined) {
ok(false, "Worker had an error.");
} else {
is(event.data.size, expectedSize, "size proproperty accessed from worker is not the same as on main thread.");
is(event.data.type, expectedType, "type proproperty accessed from worker is incorrect.");
is(event.data.name, file.name, "name proproperty accessed from worker is incorrect.");
is(event.data.mozFullPath, file.mozFullPath, "mozFullPath proproperty accessed from worker is not the same as on main thread.");
}
SimpleTest.finish();
};
worker.postMessage(file);
SimpleTest.waitForExplicitFinish();
}
// Empty file.
accessFileProperties(createFileWithData(""), 0, "");
// Typical use case.
accessFileProperties(createFileWithData("Hello"), 5, "");
// Longish file.
var text = "";
for (var i = 0; i < 10000; ++i) {
text += "long";
}
accessFileProperties(createFileWithData(text), 40000, "");
// Type detection based on extension.
accessFileProperties(createFileWithData("text", "txt"), 4, "text/plain");
]]>
</script>
</window>