diff options
Diffstat (limited to 'Source/WebCore/fileapi')
-rw-r--r-- | Source/WebCore/fileapi/AsyncFileStream.cpp | 73 | ||||
-rw-r--r-- | Source/WebCore/fileapi/AsyncFileStream.h | 9 | ||||
-rw-r--r-- | Source/WebCore/fileapi/Blob.cpp | 73 | ||||
-rw-r--r-- | Source/WebCore/fileapi/Blob.h | 11 | ||||
-rw-r--r-- | Source/WebCore/fileapi/Blob.idl | 7 | ||||
-rw-r--r-- | Source/WebCore/fileapi/File.cpp | 17 | ||||
-rw-r--r-- | Source/WebCore/fileapi/File.h | 7 | ||||
-rw-r--r-- | Source/WebCore/fileapi/File.idl | 4 | ||||
-rw-r--r-- | Source/WebCore/fileapi/FileError.idl | 3 | ||||
-rw-r--r-- | Source/WebCore/fileapi/FileException.idl | 4 | ||||
-rw-r--r-- | Source/WebCore/fileapi/FileList.idl | 6 | ||||
-rw-r--r-- | Source/WebCore/fileapi/FileReader.cpp | 2 | ||||
-rw-r--r-- | Source/WebCore/fileapi/FileReader.idl | 32 | ||||
-rw-r--r-- | Source/WebCore/fileapi/FileReaderLoader.cpp | 80 | ||||
-rw-r--r-- | Source/WebCore/fileapi/FileReaderLoader.h | 16 | ||||
-rw-r--r-- | Source/WebCore/fileapi/FileReaderSync.idl | 13 | ||||
-rw-r--r-- | Source/WebCore/fileapi/FileThread.cpp | 6 | ||||
-rw-r--r-- | Source/WebCore/fileapi/ThreadableBlobRegistry.cpp | 2 | ||||
-rw-r--r-- | Source/WebCore/fileapi/WebKitBlobBuilder.cpp | 8 | ||||
-rw-r--r-- | Source/WebCore/fileapi/WebKitBlobBuilder.h | 4 |
20 files changed, 268 insertions, 109 deletions
diff --git a/Source/WebCore/fileapi/AsyncFileStream.cpp b/Source/WebCore/fileapi/AsyncFileStream.cpp index e948a7a42..64252670d 100644 --- a/Source/WebCore/fileapi/AsyncFileStream.cpp +++ b/Source/WebCore/fileapi/AsyncFileStream.cpp @@ -36,32 +36,47 @@ #include "AsyncFileStream.h" #include "Blob.h" -#include "CrossThreadTask.h" #include "FileStream.h" #include "FileStreamClient.h" #include "FileThread.h" #include "FileThreadTask.h" -#include "ScriptExecutionContext.h" +#include "MainThreadTask.h" +#include <wtf/MainThread.h> #include <wtf/text/WTFString.h> namespace WebCore { -inline AsyncFileStream::AsyncFileStream(ScriptExecutionContext* context, FileStreamClient* client) - : m_context(context) - , m_stream(FileStream::create()) +static PassRefPtr<FileThread> createFileThread() +{ + RefPtr<FileThread> thread = FileThread::create(); + if (!thread->start()) + return 0; + return thread.release(); +} + +static FileThread* fileThread() +{ + ASSERT(isMainThread()); + static FileThread* thread = createFileThread().leakRef(); + return thread; +} + +inline AsyncFileStream::AsyncFileStream(FileStreamClient* client) + : m_stream(FileStream::create()) , m_client(client) { + ASSERT(isMainThread()); } -PassRefPtr<AsyncFileStream> AsyncFileStream::create(ScriptExecutionContext* context, FileStreamClient* client) +PassRefPtr<AsyncFileStream> AsyncFileStream::create(FileStreamClient* client) { - RefPtr<AsyncFileStream> proxy = adoptRef(new AsyncFileStream(context, client)); + RefPtr<AsyncFileStream> proxy = adoptRef(new AsyncFileStream(client)); // Hold a reference so that the instance will not get deleted while there are tasks on the file thread. // This is balanced by the deref in derefProxyOnContext below. proxy->ref(); - proxy->fileThread()->postTask(createFileThreadTask(proxy.get(), &AsyncFileStream::startOnFileThread)); + fileThread()->postTask(createFileThreadTask(proxy.get(), &AsyncFileStream::startOnFileThread)); return proxy.release(); } @@ -70,14 +85,7 @@ AsyncFileStream::~AsyncFileStream() { } -FileThread* AsyncFileStream::fileThread() -{ - ASSERT(m_context->isContextThread()); - ASSERT(m_context->fileThread()); - return m_context->fileThread(); -} - -static void didStart(ScriptExecutionContext*, AsyncFileStream* proxy) +static void didStart(AsyncFileStream* proxy) { if (proxy->client()) proxy->client()->didStart(); @@ -85,22 +93,23 @@ static void didStart(ScriptExecutionContext*, AsyncFileStream* proxy) void AsyncFileStream::startOnFileThread() { - if (!client()) + // FIXME: It is not correct to check m_client from a secondary thread - stop() could be racing with this check. + if (!m_client) return; m_stream->start(); - m_context->postTask(createCallbackTask(&didStart, AllowCrossThreadAccess(this))); + callOnMainThread(didStart, AllowCrossThreadAccess(this)); } void AsyncFileStream::stop() { - // Clear the client so that we won't be calling callbacks on the client. + // Clear the client so that we won't be invoking callbacks on the client. setClient(0); fileThread()->unscheduleTasks(m_stream.get()); fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::stopOnFileThread)); } -static void derefProxyOnContext(ScriptExecutionContext*, AsyncFileStream* proxy) +static void derefProxyOnMainThread(AsyncFileStream* proxy) { ASSERT(proxy->hasOneRef()); proxy->deref(); @@ -109,10 +118,10 @@ static void derefProxyOnContext(ScriptExecutionContext*, AsyncFileStream* proxy) void AsyncFileStream::stopOnFileThread() { m_stream->stop(); - m_context->postTask(createCallbackTask(&derefProxyOnContext, AllowCrossThreadAccess(this))); + callOnMainThread(derefProxyOnMainThread, AllowCrossThreadAccess(this)); } -static void didGetSize(ScriptExecutionContext*, AsyncFileStream* proxy, long long size) +static void didGetSize(AsyncFileStream* proxy, long long size) { if (proxy->client()) proxy->client()->didGetSize(size); @@ -126,10 +135,10 @@ void AsyncFileStream::getSize(const String& path, double expectedModificationTim void AsyncFileStream::getSizeOnFileThread(const String& path, double expectedModificationTime) { long long size = m_stream->getSize(path, expectedModificationTime); - m_context->postTask(createCallbackTask(&didGetSize, AllowCrossThreadAccess(this), size)); + callOnMainThread(didGetSize, AllowCrossThreadAccess(this), size); } -static void didOpen(ScriptExecutionContext*, AsyncFileStream* proxy, bool success) +static void didOpen(AsyncFileStream* proxy, bool success) { if (proxy->client()) proxy->client()->didOpen(success); @@ -143,7 +152,7 @@ void AsyncFileStream::openForRead(const String& path, long long offset, long lon void AsyncFileStream::openForReadOnFileThread(const String& path, long long offset, long long length) { bool success = m_stream->openForRead(path, offset, length); - m_context->postTask(createCallbackTask(&didOpen, AllowCrossThreadAccess(this), success)); + callOnMainThread(didOpen, AllowCrossThreadAccess(this), success); } void AsyncFileStream::openForWrite(const String& path) @@ -156,7 +165,7 @@ void AsyncFileStream::openForWrite(const String& path) void AsyncFileStream::openForWriteOnFileThread(const String& path) { bool success = m_stream->openForWrite(path); - m_context->postTask(createCallbackTask(&didOpen, AllowCrossThreadAccess(this), success)); + callOnMainThread(didOpen, AllowCrossThreadAccess(this), success); } void AsyncFileStream::close() @@ -169,7 +178,7 @@ void AsyncFileStream::closeOnFileThread() m_stream->close(); } -static void didRead(ScriptExecutionContext*, AsyncFileStream* proxy, int bytesRead) +static void didRead(AsyncFileStream* proxy, int bytesRead) { if (proxy->client()) proxy->client()->didRead(bytesRead); @@ -185,10 +194,10 @@ void AsyncFileStream::read(char* buffer, int length) void AsyncFileStream::readOnFileThread(char* buffer, int length) { int bytesRead = m_stream->read(buffer, length); - m_context->postTask(createCallbackTask(&didRead, AllowCrossThreadAccess(this), bytesRead)); + callOnMainThread(didRead, AllowCrossThreadAccess(this), bytesRead); } -static void didWrite(ScriptExecutionContext*, AsyncFileStream* proxy, int bytesWritten) +static void didWrite(AsyncFileStream* proxy, int bytesWritten) { if (proxy->client()) proxy->client()->didWrite(bytesWritten); @@ -202,10 +211,10 @@ void AsyncFileStream::write(const KURL& blobURL, long long position, int length) void AsyncFileStream::writeOnFileThread(const KURL& blobURL, long long position, int length) { int bytesWritten = m_stream->write(blobURL, position, length); - m_context->postTask(createCallbackTask(&didWrite, AllowCrossThreadAccess(this), bytesWritten)); + callOnMainThread(didWrite, AllowCrossThreadAccess(this), bytesWritten); } -static void didTruncate(ScriptExecutionContext*, AsyncFileStream* proxy, bool success) +static void didTruncate(AsyncFileStream* proxy, bool success) { if (proxy->client()) proxy->client()->didTruncate(success); @@ -219,7 +228,7 @@ void AsyncFileStream::truncate(long long position) void AsyncFileStream::truncateOnFileThread(long long position) { bool success = m_stream->truncate(position); - m_context->postTask(createCallbackTask(&didTruncate, AllowCrossThreadAccess(this), success)); + callOnMainThread(didTruncate, AllowCrossThreadAccess(this), success); } } // namespace WebCore diff --git a/Source/WebCore/fileapi/AsyncFileStream.h b/Source/WebCore/fileapi/AsyncFileStream.h index 04be2db0c..68f23e99c 100644 --- a/Source/WebCore/fileapi/AsyncFileStream.h +++ b/Source/WebCore/fileapi/AsyncFileStream.h @@ -42,13 +42,11 @@ namespace WebCore { class FileStreamClient; class FileStream; -class FileThread; class KURL; -class ScriptExecutionContext; class AsyncFileStream : public RefCounted<AsyncFileStream> { public: - static PassRefPtr<AsyncFileStream> create(ScriptExecutionContext*, FileStreamClient*); + static PassRefPtr<AsyncFileStream> create(FileStreamClient*); ~AsyncFileStream(); void getSize(const String& path, double expectedModificationTime); @@ -67,9 +65,7 @@ public: void setClient(FileStreamClient* client) { m_client = client; } private: - AsyncFileStream(ScriptExecutionContext*, FileStreamClient*); - - FileThread* fileThread(); + AsyncFileStream(FileStreamClient*); // Called on File thread. void startOnFileThread(); @@ -82,7 +78,6 @@ private: void writeOnFileThread(const KURL& blobURL, long long position, int length); void truncateOnFileThread(long long position); - RefPtr<ScriptExecutionContext> m_context; RefPtr<FileStream> m_stream; FileStreamClient* m_client; diff --git a/Source/WebCore/fileapi/Blob.cpp b/Source/WebCore/fileapi/Blob.cpp index 291a22729..7640f5f50 100644 --- a/Source/WebCore/fileapi/Blob.cpp +++ b/Source/WebCore/fileapi/Blob.cpp @@ -37,6 +37,7 @@ #include "ScriptCallStack.h" #include "ScriptExecutionContext.h" #include "ThreadableBlobRegistry.h" +#include <wtf/text/CString.h> namespace WebCore { @@ -73,7 +74,7 @@ Blob::Blob(PassOwnPtr<BlobData> blobData, long long size) } Blob::Blob(const KURL& srcURL, const String& type, long long size) - : m_type(type) + : m_type(Blob::normalizedContentType(type)) , m_size(size) { // Create a new internal URL and register it with the same blob data as the source URL. @@ -86,6 +87,74 @@ Blob::~Blob() ThreadableBlobRegistry::unregisterBlobURL(m_internalURL); } +bool Blob::isValidContentType(const String& contentType) +{ + if (contentType.isNull()) + return true; + + size_t length = contentType.length(); + if (contentType.is8Bit()) { + const LChar* characters = contentType.characters8(); + for (size_t i = 0; i < length; ++i) { + if (characters[i] < 0x20 || characters[i] > 0x7e) + return false; + } + } else { + const UChar* characters = contentType.characters16(); + for (size_t i = 0; i < length; ++i) { + if (characters[i] < 0x20 || characters[i] > 0x7e) + return false; + } + } + return true; +} + +String Blob::normalizedContentType(const String& contentType) +{ + if (Blob::isValidContentType(contentType)) + return contentType.lower(); + return emptyString(); +} + +bool Blob::isNormalizedContentType(const String& contentType) +{ + if (contentType.isNull()) + return true; + + size_t length = contentType.length(); + if (contentType.is8Bit()) { + const LChar* characters = contentType.characters8(); + for (size_t i = 0; i < length; ++i) { + if (characters[i] < 0x20 || characters[i] > 0x7e) + return false; + if (characters[i] >= 'A' && characters[i] <= 'Z') + return false; + } + } else { + const UChar* characters = contentType.characters16(); + for (size_t i = 0; i < length; ++i) { + if (characters[i] < 0x20 || characters[i] > 0x7e) + return false; + if (characters[i] >= 'A' && characters[i] <= 'Z') + return false; + } + } + return true; +} + +bool Blob::isNormalizedContentType(const CString& contentType) +{ + size_t length = contentType.length(); + const char* characters = contentType.data(); + for (size_t i = 0; i < length; ++i) { + if (characters[i] < 0x20 || characters[i] > 0x7e) + return false; + if (characters[i] >= 'A' && characters[i] <= 'Z') + return false; + } + return true; +} + #if ENABLE(BLOB) PassRefPtr<Blob> Blob::slice(long long start, long long end, const String& contentType) const { @@ -122,7 +191,7 @@ PassRefPtr<Blob> Blob::slice(long long start, long long end, const String& conte long long length = end - start; OwnPtr<BlobData> blobData = BlobData::create(); - blobData->setContentType(contentType); + blobData->setContentType(Blob::normalizedContentType(contentType)); if (isFile()) { #if ENABLE(FILE_SYSTEM) if (!toFile(this)->fileSystemURL().isEmpty()) diff --git a/Source/WebCore/fileapi/Blob.h b/Source/WebCore/fileapi/Blob.h index f4a01af89..bf4a2851d 100644 --- a/Source/WebCore/fileapi/Blob.h +++ b/Source/WebCore/fileapi/Blob.h @@ -37,7 +37,6 @@ #include <wtf/PassOwnPtr.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> -#include <wtf/Vector.h> #include <wtf/text/WTFString.h> namespace WebCore { @@ -59,6 +58,7 @@ public: // For deserialization. static PassRefPtr<Blob> create(const KURL& srcURL, const String& type, long long size) { + ASSERT(Blob::isNormalizedContentType(type)); return adoptRef(new Blob(srcURL, type, size)); } @@ -70,6 +70,14 @@ public: virtual unsigned long long size() const { return static_cast<unsigned long long>(m_size); } virtual bool isFile() const { return false; } + // The checks described in the File API spec. + static bool isValidContentType(const String&); + // The normalization procedure described in the File API spec. + static String normalizedContentType(const String&); + // Intended for use in ASSERT statements. + static bool isNormalizedContentType(const String&); + static bool isNormalizedContentType(const CString&); + #if ENABLE(BLOB) PassRefPtr<Blob> slice(long long start = 0, long long end = std::numeric_limits<long long>::max(), const String& contentType = String()) const; #endif @@ -93,3 +101,4 @@ protected: } // namespace WebCore #endif // Blob_h + diff --git a/Source/WebCore/fileapi/Blob.idl b/Source/WebCore/fileapi/Blob.idl index 15babb788..17cd5e2ba 100644 --- a/Source/WebCore/fileapi/Blob.idl +++ b/Source/WebCore/fileapi/Blob.idl @@ -29,18 +29,19 @@ */ [ - JSGenerateIsReachable=Impl, + GlobalContext=DOMWindow&WorkerGlobalScope, + GenerateIsReachable=Impl, CustomToJSObject, JSNoStaticTables, CustomConstructor, - ConstructorParameters=2 + CustomConstructor(sequence<any> blobParts, optional BlobPropertyBag options) ] interface Blob { readonly attribute unsigned long long size; readonly attribute DOMString type; #if !defined(LANGUAGE_OBJECTIVE_C) #if defined(ENABLE_BLOB) && ENABLE_BLOB - Blob slice(in [Optional] long long start, in [Optional] long long end, in [Optional, TreatNullAs=NullString, TreatUndefinedAs=NullString] DOMString contentType); + Blob slice(optional long long start, optional long long end, [TreatNullAs=NullString, TreatUndefinedAs=NullString] optional DOMString contentType); #endif #endif }; diff --git a/Source/WebCore/fileapi/File.cpp b/Source/WebCore/fileapi/File.cpp index 692bde1ac..54e5a9001 100644 --- a/Source/WebCore/fileapi/File.cpp +++ b/Source/WebCore/fileapi/File.cpp @@ -20,7 +20,7 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -30,6 +30,7 @@ #include "FileSystem.h" #include "MIMETypeRegistry.h" #include <wtf/CurrentTime.h> +#include <wtf/DateMath.h> #include <wtf/text/WTFString.h> namespace WebCore { @@ -52,6 +53,7 @@ static String getContentTypeFromFileName(const String& name, File::ContentTypeLo static PassOwnPtr<BlobData> createBlobDataForFileWithType(const String& path, const String& contentType) { OwnPtr<BlobData> blobData = BlobData::create(); + ASSERT(Blob::isNormalizedContentType(contentType)); blobData->setContentType(contentType); blobData->appendFile(path); return blobData.release(); @@ -116,7 +118,7 @@ File::File(const String& path, const KURL& url, const String& type) m_name = pathGetFileName(path); // FIXME: File object serialization/deserialization does not include // newer file object data members: m_name and m_relativePath. - // See SerializedScriptValue.cpp for js and v8. + // See SerializedScriptValue.cpp } File::File(const String& path, const String& name, ContentTypeLookupPolicy policy) @@ -152,16 +154,15 @@ File::File(const KURL& fileSystemURL, const FileMetadata& metadata) double File::lastModifiedDate() const { #if ENABLE(FILE_SYSTEM) - if (hasValidSnapshotMetadata()) - return m_snapshotModificationTime * 1000.0; + if (hasValidSnapshotMetadata() && isValidFileTime(m_snapshotModificationTime)) + return m_snapshotModificationTime * msPerSecond; #endif time_t modificationTime; - if (!getFileModificationTime(m_path, modificationTime)) - return invalidFileTime(); + if (getFileModificationTime(m_path, modificationTime) && isValidFileTime(modificationTime)) + return modificationTime * msPerSecond; - // Needs to return epoch time in milliseconds for Date. - return modificationTime * 1000.0; + return currentTime() * msPerSecond; } unsigned long long File::size() const diff --git a/Source/WebCore/fileapi/File.h b/Source/WebCore/fileapi/File.h index d466adce8..abe5544e3 100644 --- a/Source/WebCore/fileapi/File.h +++ b/Source/WebCore/fileapi/File.h @@ -28,7 +28,6 @@ #include "Blob.h" #include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> #include <wtf/text/WTFString.h> namespace WebCore { @@ -91,7 +90,7 @@ public: const String& path() const { return m_path; } const String& name() const { return m_name; } - // This may return NaN (which is converted to null Date in javascript layer) if getFileModificationTime() platform call has failed or the information is not available. + // This returns the current date and time if the file's last modifiecation date is not known (per spec: http://www.w3.org/TR/FileAPI/#dfn-lastModifiedDate). double lastModifiedDate() const; #if ENABLE(DIRECTORY_UPLOAD) @@ -136,13 +135,13 @@ private: inline File* toFile(Blob* blob) { - ASSERT(!blob || blob->isFile()); + ASSERT_WITH_SECURITY_IMPLICATION(!blob || blob->isFile()); return static_cast<File*>(blob); } inline const File* toFile(const Blob* blob) { - ASSERT(!blob || blob->isFile()); + ASSERT_WITH_SECURITY_IMPLICATION(!blob || blob->isFile()); return static_cast<const File*>(blob); } diff --git a/Source/WebCore/fileapi/File.idl b/Source/WebCore/fileapi/File.idl index ddfb9a24e..1d9dc51fc 100644 --- a/Source/WebCore/fileapi/File.idl +++ b/Source/WebCore/fileapi/File.idl @@ -32,8 +32,6 @@ #if !defined(LANGUAGE_GOBJECT) || !LANGUAGE_GOBJECT readonly attribute Date lastModifiedDate; #endif -#if defined(ENABLE_DIRECTORY_UPLOAD) && ENABLE_DIRECTORY_UPLOAD - readonly attribute DOMString webkitRelativePath; -#endif + [Conditional=DIRECTORY_UPLOAD] readonly attribute DOMString webkitRelativePath; }; diff --git a/Source/WebCore/fileapi/FileError.idl b/Source/WebCore/fileapi/FileError.idl index 70a2768d5..c588100d0 100644 --- a/Source/WebCore/fileapi/FileError.idl +++ b/Source/WebCore/fileapi/FileError.idl @@ -30,7 +30,8 @@ [ Conditional=BLOB|FILE_SYSTEM, - JSNoStaticTables + JSNoStaticTables, + ImplementationLacksVTable ] interface FileError { #if !defined(LANGUAGE_OBJECTIVE_C) // FIXME: Some of constant names are already defined in DOMException.h for Objective-C binding and we cannot have the same names here (they are translated into a enum in the same namespace). diff --git a/Source/WebCore/fileapi/FileException.idl b/Source/WebCore/fileapi/FileException.idl index 6059d22aa..97ca308c7 100644 --- a/Source/WebCore/fileapi/FileException.idl +++ b/Source/WebCore/fileapi/FileException.idl @@ -29,9 +29,11 @@ */ [ + NoInterfaceObject, Conditional=BLOB|FILE_SYSTEM, DoNotCheckConstants, - JSNoStaticTables + JSNoStaticTables, + ImplementationLacksVTable ] exception FileException { readonly attribute unsigned short code; diff --git a/Source/WebCore/fileapi/FileList.idl b/Source/WebCore/fileapi/FileList.idl index 6b790f73f..f0d4ce482 100644 --- a/Source/WebCore/fileapi/FileList.idl +++ b/Source/WebCore/fileapi/FileList.idl @@ -24,10 +24,10 @@ */ [ - IndexedGetter, - JSNoStaticTables + JSNoStaticTables, + ImplementationLacksVTable ] interface FileList { readonly attribute unsigned long length; - File item(in unsigned long index); + getter File item(unsigned long index); }; diff --git a/Source/WebCore/fileapi/FileReader.cpp b/Source/WebCore/fileapi/FileReader.cpp index 128eb645c..bf8c33d96 100644 --- a/Source/WebCore/fileapi/FileReader.cpp +++ b/Source/WebCore/fileapi/FileReader.cpp @@ -56,7 +56,7 @@ PassRefPtr<FileReader> FileReader::create(ScriptExecutionContext* context) } FileReader::FileReader(ScriptExecutionContext* context) - : ActiveDOMObject(context, this) + : ActiveDOMObject(context) , m_state(EMPTY) , m_aborting(false) , m_readType(FileReaderLoader::ReadAsBinaryString) diff --git a/Source/WebCore/fileapi/FileReader.idl b/Source/WebCore/fileapi/FileReader.idl index 14baf07b4..0d5af4f27 100644 --- a/Source/WebCore/fileapi/FileReader.idl +++ b/Source/WebCore/fileapi/FileReader.idl @@ -30,10 +30,11 @@ */ [ + GlobalContext=DOMWindow&WorkerGlobalScope, Conditional=BLOB, ActiveDOMObject, Constructor, - CallWith=ScriptExecutionContext, + ConstructorCallWith=ScriptExecutionContext, EventTarget, JSNoStaticTables ] interface FileReader { @@ -44,31 +45,26 @@ readonly attribute unsigned short readyState; // async read methods - void readAsArrayBuffer(in Blob blob) - raises(DOMException); - void readAsBinaryString(in Blob blob) - raises(DOMException); - void readAsText(in Blob blob, in [Optional] DOMString encoding) - raises(DOMException); - void readAsDataURL(in Blob blob) - raises(DOMException); + [RaisesException] void readAsArrayBuffer(Blob blob); + [RaisesException] void readAsBinaryString(Blob blob); + [RaisesException] void readAsText(Blob blob, optional DOMString encoding); + [RaisesException] void readAsDataURL(Blob blob); void abort(); // file data - [Custom] readonly attribute DOMObject result; + [Custom] readonly attribute any result; readonly attribute FileError error; // EventTarget interface - void addEventListener(in DOMString type, - in EventListener listener, - in [Optional] boolean useCapture); - void removeEventListener(in DOMString type, - in EventListener listener, - in [Optional] boolean useCapture); - boolean dispatchEvent(in Event evt) - raises(EventException); + void addEventListener(DOMString type, + EventListener listener, + optional boolean useCapture); + void removeEventListener(DOMString type, + EventListener listener, + optional boolean useCapture); + [RaisesException] boolean dispatchEvent(Event evt); attribute EventListener onloadstart; attribute EventListener onprogress; diff --git a/Source/WebCore/fileapi/FileReaderLoader.cpp b/Source/WebCore/fileapi/FileReaderLoader.cpp index f24cdc82f..77c05fe81 100644 --- a/Source/WebCore/fileapi/FileReaderLoader.cpp +++ b/Source/WebCore/fileapi/FileReaderLoader.cpp @@ -54,13 +54,19 @@ using namespace std; namespace WebCore { +const int defaultBufferLength = 32768; + FileReaderLoader::FileReaderLoader(ReadType readType, FileReaderLoaderClient* client) : m_readType(readType) , m_client(client) , m_isRawDataConverted(false) , m_stringResult("") + , m_variableLength(false) , m_bytesLoaded(0) , m_totalBytes(0) + , m_hasRange(false) + , m_rangeStart(0) + , m_rangeEnd(0) , m_errorCode(0) { } @@ -85,6 +91,8 @@ void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, Blo // Construct and load the request. ResourceRequest request(m_urlForReading); request.setHTTPMethod("GET"); + if (m_hasRange) + request.setHTTPHeaderField("Range", String::format("bytes=%d-%d", m_rangeStart, m_rangeEnd)); ThreadableLoaderOptions options; options.sendLoadCallbacks = SendCallbacks; @@ -133,6 +141,16 @@ void FileReaderLoader::didReceiveResponse(unsigned long, const ResourceResponse& unsigned long long length = response.expectedContentLength(); + // A value larger than INT_MAX means that the content length wasn't + // specified, so the buffer will need to be dynamically grown. + if (length > INT_MAX) { + m_variableLength = true; + if (m_hasRange) + length = 1 + m_rangeEnd - m_rangeStart; + else + length = defaultBufferLength; + } + // Check that we can cast to unsigned since we have to do // so to call ArrayBuffer's create function. // FIXME: Support reading more than the current size limit of ArrayBuffer. @@ -166,8 +184,25 @@ void FileReaderLoader::didReceiveData(const char* data, int dataLength) int length = dataLength; unsigned remainingBufferSpace = m_totalBytes - m_bytesLoaded; - if (length > static_cast<long long>(remainingBufferSpace)) - length = static_cast<int>(remainingBufferSpace); + if (length > static_cast<long long>(remainingBufferSpace)) { + // If the buffer has hit maximum size, it can't be grown any more. + if (m_totalBytes >= numeric_limits<unsigned>::max()) { + failed(FileError::NOT_READABLE_ERR); + return; + } + if (m_variableLength) { + unsigned long long newLength = m_totalBytes * 2; + if (newLength > numeric_limits<unsigned>::max()) + newLength = numeric_limits<unsigned>::max(); + RefPtr<ArrayBuffer> newData = + ArrayBuffer::create(static_cast<unsigned>(newLength), 1); + memcpy(static_cast<char*>(newData->data()), static_cast<char*>(m_rawData->data()), m_bytesLoaded); + + m_rawData = newData; + m_totalBytes = static_cast<unsigned>(newLength); + } else + length = remainingBufferSpace; + } if (length <= 0) return; @@ -183,6 +218,12 @@ void FileReaderLoader::didReceiveData(const char* data, int dataLength) void FileReaderLoader::didFinishLoading(unsigned long, double) { + if (m_variableLength && m_totalBytes > m_bytesLoaded) { + RefPtr<ArrayBuffer> newData = m_rawData->slice(0, m_bytesLoaded); + + m_rawData = newData; + m_totalBytes = m_bytesLoaded; + } cleanup(); if (m_client) m_client->didFinishLoading(); @@ -233,9 +274,32 @@ PassRefPtr<ArrayBuffer> FileReaderLoader::arrayBufferResult() const return ArrayBuffer::create(m_rawData.get()); } +#if ENABLE(STREAM) +PassRefPtr<Blob> FileReaderLoader::blobResult() +{ + ASSERT(m_readType == ReadAsBlob); + + // If the loading is not finished or an error occurs, return an empty result. + if (!m_rawData || m_errorCode || !isCompleted()) + return 0; + + if (!m_blobResult) { + OwnPtr<BlobData> blobData = BlobData::create(); + size_t size = 0; + RefPtr<RawData> rawData = RawData::create(); + size = m_rawData->byteLength(); + rawData->mutableData()->append(static_cast<char*>(m_rawData->data()), size); + blobData->appendData(rawData, 0, size); + blobData->setContentType(m_dataType); + m_blobResult = Blob::create(blobData.release(), size); + } + return m_blobResult; +} +#endif // ENABLE(STREAM) + String FileReaderLoader::stringResult() { - ASSERT(m_readType != ReadAsArrayBuffer); + ASSERT(m_readType != ReadAsArrayBuffer && m_readType != ReadAsBlob); // If the loading is not started or an error occurs, return an empty result. if (!m_rawData || m_errorCode) @@ -320,6 +384,16 @@ void FileReaderLoader::setEncoding(const String& encoding) m_encoding = TextEncoding(encoding); } +#if ENABLE(STREAM) +void FileReaderLoader::setRange(unsigned start, unsigned length) +{ + ASSERT(length > 0); + m_hasRange = true; + m_rangeStart = start; + m_rangeEnd = start + length - 1; +} +#endif // ENABLE(STREAM) + } // namespace WebCore #endif // ENABLE(BLOB) diff --git a/Source/WebCore/fileapi/FileReaderLoader.h b/Source/WebCore/fileapi/FileReaderLoader.h index 34f54387b..ec1bdfdb2 100644 --- a/Source/WebCore/fileapi/FileReaderLoader.h +++ b/Source/WebCore/fileapi/FileReaderLoader.h @@ -53,6 +53,7 @@ public: enum ReadType { ReadAsArrayBuffer, ReadAsBinaryString, + ReadAsBlob, ReadAsText, ReadAsDataURL }; @@ -72,13 +73,19 @@ public: String stringResult(); PassRefPtr<ArrayBuffer> arrayBufferResult() const; +#if ENABLE(STREAM) + PassRefPtr<Blob> blobResult(); +#endif // ENABLE(STREAM) unsigned bytesLoaded() const { return m_bytesLoaded; } unsigned totalBytes() const { return m_totalBytes; } int errorCode() const { return m_errorCode; } void setEncoding(const String&); void setDataType(const String& dataType) { m_dataType = dataType; } - +#if ENABLE(STREAM) + void setRange(unsigned, unsigned); +#endif // ENABLE(STREAM) + private: void terminate(); void cleanup(); @@ -102,12 +109,19 @@ private: bool m_isRawDataConverted; String m_stringResult; + RefPtr<Blob> m_blobResult; // The decoder used to decode the text data. RefPtr<TextResourceDecoder> m_decoder; + bool m_variableLength; unsigned m_bytesLoaded; unsigned m_totalBytes; + + bool m_hasRange; + unsigned m_rangeStart; + unsigned m_rangeEnd; + int m_errorCode; }; diff --git a/Source/WebCore/fileapi/FileReaderSync.idl b/Source/WebCore/fileapi/FileReaderSync.idl index bc3f86def..8ef0f6a56 100644 --- a/Source/WebCore/fileapi/FileReaderSync.idl +++ b/Source/WebCore/fileapi/FileReaderSync.idl @@ -29,16 +29,13 @@ */ [ + GlobalContext=WorkerGlobalScope, Conditional=BLOB, Constructor, JSNoStaticTables ] interface FileReaderSync { - [CallWith=ScriptExecutionContext] ArrayBuffer readAsArrayBuffer(in Blob blob) - raises(FileException); - [CallWith=ScriptExecutionContext] DOMString readAsBinaryString(in Blob blob) - raises(FileException); - [CallWith=ScriptExecutionContext] DOMString readAsText(in Blob blob, in [Optional] DOMString encoding) - raises(FileException); - [CallWith=ScriptExecutionContext] DOMString readAsDataURL(in Blob blob) - raises(FileException); + [CallWith=ScriptExecutionContext, RaisesException] ArrayBuffer readAsArrayBuffer(Blob blob); + [CallWith=ScriptExecutionContext, RaisesException] DOMString readAsBinaryString(Blob blob); + [CallWith=ScriptExecutionContext, RaisesException] DOMString readAsText(Blob blob, optional DOMString encoding); + [CallWith=ScriptExecutionContext, RaisesException] DOMString readAsDataURL(Blob blob); }; diff --git a/Source/WebCore/fileapi/FileThread.cpp b/Source/WebCore/fileapi/FileThread.cpp index 4f4f473fd..ef280c8a3 100644 --- a/Source/WebCore/fileapi/FileThread.cpp +++ b/Source/WebCore/fileapi/FileThread.cpp @@ -34,8 +34,8 @@ #include "FileThread.h" -#include "AutodrainedPool.h" #include "Logging.h" +#include <wtf/AutodrainedPool.h> namespace WebCore { @@ -98,10 +98,10 @@ void FileThread::runLoop() LOG(FileAPI, "Started FileThread %p", this); } - AutodrainedPool pool; while (OwnPtr<Task> task = m_queue.waitForMessage()) { + AutodrainedPool pool; + task->performTask(); - pool.cycle(); } LOG(FileAPI, "About to detach thread %i and clear the ref to FileThread %p, which currently has %i ref(s)", m_threadID, this, refCount()); diff --git a/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp b/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp index afe5b66cc..10bfb2ee0 100644 --- a/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp +++ b/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp @@ -155,7 +155,7 @@ void ThreadableBlobRegistry::unregisterBlobURL(const KURL&) { } -PassRefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const KURL& url) +PassRefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const KURL&) { return 0; } diff --git a/Source/WebCore/fileapi/WebKitBlobBuilder.cpp b/Source/WebCore/fileapi/WebKitBlobBuilder.cpp index 8312a547c..1622e2fe4 100644 --- a/Source/WebCore/fileapi/WebKitBlobBuilder.cpp +++ b/Source/WebCore/fileapi/WebKitBlobBuilder.cpp @@ -39,7 +39,6 @@ #include "HistogramSupport.h" #include "LineEnding.h" #include "ScriptCallStack.h" -#include "ScriptExecutionContext.h" #include "TextEncoding.h" #include <wtf/ArrayBuffer.h> #include <wtf/ArrayBufferView.h> @@ -89,11 +88,8 @@ void BlobBuilder::append(const String& text, const String& endingType) } #if ENABLE(BLOB) -void BlobBuilder::append(ScriptExecutionContext* context, ArrayBuffer* arrayBuffer) +void BlobBuilder::append(ArrayBuffer* arrayBuffer) { - String consoleMessage("ArrayBuffer values are deprecated in Blob Constructor. Use ArrayBufferView instead."); - context->addConsoleMessage(JSMessageSource, LogMessageType, WarningMessageLevel, consoleMessage); - HistogramSupport::histogramEnumeration("WebCore.Blob.constructor.ArrayBufferOrView", BlobConstructorArrayBuffer, BlobConstructorArrayBufferOrViewMax); if (!arrayBuffer) @@ -150,7 +146,7 @@ void BlobBuilder::appendBytesData(const void* data, size_t length) PassRefPtr<Blob> BlobBuilder::getBlob(const String& contentType) { OwnPtr<BlobData> blobData = BlobData::create(); - blobData->setContentType(contentType); + blobData->setContentType(Blob::normalizedContentType(contentType)); blobData->swapItems(m_items); RefPtr<Blob> blob = Blob::create(blobData.release(), m_size); diff --git a/Source/WebCore/fileapi/WebKitBlobBuilder.h b/Source/WebCore/fileapi/WebKitBlobBuilder.h index 75090ba3e..335bc766d 100644 --- a/Source/WebCore/fileapi/WebKitBlobBuilder.h +++ b/Source/WebCore/fileapi/WebKitBlobBuilder.h @@ -33,14 +33,12 @@ #include "BlobData.h" #include <wtf/Forward.h> -#include <wtf/RefCounted.h> namespace WebCore { // FIXME: Move this file to BlobBuilder.h class Blob; -class ScriptExecutionContext; class TextEncoding; typedef int ExceptionCode; @@ -52,7 +50,7 @@ public: void append(Blob*); void append(const String& text, const String& ending); #if ENABLE(BLOB) - void append(ScriptExecutionContext*, ArrayBuffer*); + void append(ArrayBuffer*); void append(ArrayBufferView*); #endif |