зеркало из https://github.com/mozilla/gecko-dev.git
Bug 664783 - Implement FileReaderSync for Workers. r=bent+sicking.
This commit is contained in:
Родитель
c35631abba
Коммит
a5a375d3a6
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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>
|
Загрузка…
Ссылка в новой задаче