summaryrefslogtreecommitdiff
path: root/Source/WebCore/fileapi
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/fileapi
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/fileapi')
-rw-r--r--Source/WebCore/fileapi/AsyncFileStream.cpp255
-rw-r--r--Source/WebCore/fileapi/AsyncFileStream.h50
-rw-r--r--Source/WebCore/fileapi/Blob.cpp197
-rw-r--r--Source/WebCore/fileapi/Blob.h69
-rw-r--r--Source/WebCore/fileapi/Blob.idl22
-rw-r--r--Source/WebCore/fileapi/BlobBuilder.cpp (renamed from Source/WebCore/fileapi/FileThread.h)104
-rw-r--r--Source/WebCore/fileapi/BlobBuilder.h (renamed from Source/WebCore/fileapi/WebKitBlobBuilder.h)37
-rw-r--r--Source/WebCore/fileapi/BlobLineEndings.h35
-rw-r--r--Source/WebCore/fileapi/BlobLineEndings.idl27
-rw-r--r--Source/WebCore/fileapi/BlobPropertyBag.h38
-rw-r--r--Source/WebCore/fileapi/BlobPropertyBag.idl31
-rw-r--r--Source/WebCore/fileapi/BlobURL.cpp2
-rw-r--r--Source/WebCore/fileapi/BlobURL.h9
-rw-r--r--Source/WebCore/fileapi/File.cpp126
-rw-r--r--Source/WebCore/fileapi/File.h90
-rw-r--r--Source/WebCore/fileapi/File.idl18
-rw-r--r--Source/WebCore/fileapi/FileError.h13
-rw-r--r--Source/WebCore/fileapi/FileError.idl6
-rw-r--r--Source/WebCore/fileapi/FileException.cpp9
-rw-r--r--Source/WebCore/fileapi/FileException.h13
-rw-r--r--Source/WebCore/fileapi/FileException.idl14
-rw-r--r--Source/WebCore/fileapi/FileList.h28
-rw-r--r--Source/WebCore/fileapi/FileList.idl1
-rw-r--r--Source/WebCore/fileapi/FileReader.cpp152
-rw-r--r--Source/WebCore/fileapi/FileReader.h82
-rw-r--r--Source/WebCore/fileapi/FileReader.idl40
-rw-r--r--Source/WebCore/fileapi/FileReaderLoader.cpp108
-rw-r--r--Source/WebCore/fileapi/FileReaderLoader.h27
-rw-r--r--Source/WebCore/fileapi/FileReaderLoaderClient.h9
-rw-r--r--Source/WebCore/fileapi/FileReaderSync.cpp65
-rw-r--r--Source/WebCore/fileapi/FileReaderSync.h36
-rw-r--r--Source/WebCore/fileapi/FileReaderSync.idl13
-rw-r--r--Source/WebCore/fileapi/FileThread.cpp117
-rw-r--r--Source/WebCore/fileapi/FileThreadTask.h206
-rw-r--r--Source/WebCore/fileapi/ThreadableBlobRegistry.cpp144
-rw-r--r--Source/WebCore/fileapi/ThreadableBlobRegistry.h20
-rw-r--r--Source/WebCore/fileapi/WebKitBlobBuilder.cpp156
37 files changed, 880 insertions, 1489 deletions
diff --git a/Source/WebCore/fileapi/AsyncFileStream.cpp b/Source/WebCore/fileapi/AsyncFileStream.cpp
index 374fac0e3..168e4e277 100644
--- a/Source/WebCore/fileapi/AsyncFileStream.cpp
+++ b/Source/WebCore/fileapi/AsyncFileStream.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -30,211 +30,148 @@
*/
#include "config.h"
-
-#if ENABLE(BLOB)
-
#include "AsyncFileStream.h"
-#include "Blob.h"
#include "FileStream.h"
#include "FileStreamClient.h"
-#include "FileThread.h"
-#include "FileThreadTask.h"
-#include "MainThreadTask.h"
+#include "URL.h"
+#include <mutex>
+#include <wtf/AutodrainedPool.h>
+#include <wtf/Function.h>
#include <wtf/MainThread.h>
-#include <wtf/text/WTFString.h>
-
-#if PLATFORM(IOS)
-#include "WebCoreThread.h"
-#endif
+#include <wtf/MessageQueue.h>
+#include <wtf/NeverDestroyed.h>
namespace WebCore {
-static PassRefPtr<FileThread> createFileThread()
-{
- RefPtr<FileThread> thread = FileThread::create();
- if (!thread->start())
- return 0;
- return thread.release();
-}
+struct AsyncFileStream::Internals {
+ explicit Internals(FileStreamClient&);
+
+ FileStream stream;
+ FileStreamClient& client;
+#if !COMPILER(MSVC)
+ std::atomic_bool destroyed { false };
+#else
+ std::atomic_bool destroyed;
+#endif
+};
-static FileThread* fileThread()
+inline AsyncFileStream::Internals::Internals(FileStreamClient& client)
+ : client(client)
{
- ASSERT(isMainThread());
- static FileThread* thread = createFileThread().leakRef();
- return thread;
+#if COMPILER(MSVC)
+ // Work around a bug that prevents the default value above from compiling.
+ atomic_init(&destroyed, false);
+#endif
}
-inline AsyncFileStream::AsyncFileStream(FileStreamClient* client)
- : m_stream(FileStream::create())
- , m_client(client)
+static void callOnFileThread(Function<void ()>&& function)
{
ASSERT(isMainThread());
-}
+ ASSERT(function);
-PassRefPtr<AsyncFileStream> AsyncFileStream::create(FileStreamClient* client)
-{
- RefPtr<AsyncFileStream> proxy = adoptRef(new AsyncFileStream(client));
+ static NeverDestroyed<MessageQueue<Function<void ()>>> queue;
- // 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();
+ static std::once_flag createFileThreadOnce;
+ std::call_once(createFileThreadOnce, [] {
+ createThread("WebCore: AsyncFileStream", [] {
+ for (;;) {
+ AutodrainedPool pool;
- fileThread()->postTask(createFileThreadTask(proxy.get(), &AsyncFileStream::startOnFileThread));
+ auto function = queue.get().waitForMessage();
- return proxy.release();
-}
+ // This can never be null because we never kill the MessageQueue.
+ ASSERT(function);
-AsyncFileStream::~AsyncFileStream()
-{
-}
+ // This can bever be null because we never queue a function that is null.
+ ASSERT(*function);
-static void didStart(AsyncFileStream* proxy)
-{
- if (proxy->client())
- proxy->client()->didStart();
-}
+ (*function)();
+ }
+ });
+ });
-void AsyncFileStream::startOnFileThread()
-{
- // 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();
- callOnMainThread(didStart, AllowCrossThreadAccess(this));
+ queue.get().append(std::make_unique<Function<void ()>>(WTFMove(function)));
}
-void AsyncFileStream::stop()
+AsyncFileStream::AsyncFileStream(FileStreamClient& client)
+ : m_internals(std::make_unique<Internals>(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));
+ ASSERT(isMainThread());
}
-static void derefProxyOnMainThread(AsyncFileStream* proxy)
+AsyncFileStream::~AsyncFileStream()
{
- ASSERT(proxy->hasOneRef());
- proxy->deref();
-}
+ ASSERT(isMainThread());
-void AsyncFileStream::stopOnFileThread()
-{
- m_stream->stop();
- callOnMainThread(derefProxyOnMainThread, AllowCrossThreadAccess(this));
-}
+ // Set flag to prevent client callbacks and also prevent queued operations from starting.
+ m_internals->destroyed = true;
-static void didGetSize(AsyncFileStream* proxy, long long size)
-{
- if (proxy->client())
- proxy->client()->didGetSize(size);
+ // Call through file thread and back to main thread to make sure deletion happens
+ // after all file thread functions and all main thread functions called from them.
+ callOnFileThread([internals = WTFMove(m_internals)]() mutable {
+ callOnMainThread([internals = WTFMove(internals)] {
+ });
+ });
}
-void AsyncFileStream::getSize(const String& path, double expectedModificationTime)
-{
- fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::getSizeOnFileThread, path, expectedModificationTime));
-}
-
-void AsyncFileStream::getSizeOnFileThread(const String& path, double expectedModificationTime)
+void AsyncFileStream::perform(Function<std::function<void(FileStreamClient&)>(FileStream&)>&& operation)
{
- long long size = m_stream->getSize(path, expectedModificationTime);
- callOnMainThread(didGetSize, AllowCrossThreadAccess(this), size);
+ auto& internals = *m_internals;
+ callOnFileThread([&internals, operation = WTFMove(operation)] {
+ // Don't do the operation if stop was already called on the main thread. Note that there is
+ // a race here, but since skipping the operation is an optimization it's OK that we can't
+ // guarantee exactly which operations are skipped. Note that this is also the only reason
+ // we use an atomic_bool rather than just a bool for destroyed.
+ if (internals.destroyed)
+ return;
+ callOnMainThread([&internals, mainThreadWork = operation(internals.stream)] {
+ if (internals.destroyed)
+ return;
+ mainThreadWork(internals.client);
+ });
+ });
}
-static void didOpen(AsyncFileStream* proxy, bool success)
+void AsyncFileStream::getSize(const String& path, double expectedModificationTime)
{
- if (proxy->client())
- proxy->client()->didOpen(success);
+ // FIXME: Explicit return type here and in all the other cases like this below is a workaround for a deficiency
+ // in the Windows compiler at the time of this writing. Could remove it if that is resolved.
+ perform([path = path.isolatedCopy(), expectedModificationTime](FileStream& stream) -> std::function<void(FileStreamClient&)> {
+ long long size = stream.getSize(path, expectedModificationTime);
+ return [size](FileStreamClient& client) {
+ client.didGetSize(size);
+ };
+ });
}
void AsyncFileStream::openForRead(const String& path, long long offset, long long length)
{
- fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::openForReadOnFileThread, path, offset, length));
-}
-
-void AsyncFileStream::openForReadOnFileThread(const String& path, long long offset, long long length)
-{
- bool success = m_stream->openForRead(path, offset, length);
- callOnMainThread(didOpen, AllowCrossThreadAccess(this), success);
-}
-
-void AsyncFileStream::openForWrite(const String& path)
-{
- fileThread()->postTask(
- createFileThreadTask(this,
- &AsyncFileStream::openForWriteOnFileThread, path));
-}
-
-void AsyncFileStream::openForWriteOnFileThread(const String& path)
-{
- bool success = m_stream->openForWrite(path);
- callOnMainThread(didOpen, AllowCrossThreadAccess(this), success);
+ // FIXME: Explicit return type here is a workaround for a deficiency in the Windows compiler at the time of this writing.
+ perform([path = path.isolatedCopy(), offset, length](FileStream& stream) -> std::function<void(FileStreamClient&)> {
+ bool success = stream.openForRead(path, offset, length);
+ return [success](FileStreamClient& client) {
+ client.didOpen(success);
+ };
+ });
}
void AsyncFileStream::close()
{
- fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::closeOnFileThread));
-}
-
-void AsyncFileStream::closeOnFileThread()
-{
- m_stream->close();
-}
-
-static void didRead(AsyncFileStream* proxy, int bytesRead)
-{
- if (proxy->client())
- proxy->client()->didRead(bytesRead);
+ auto& internals = *m_internals;
+ callOnFileThread([&internals] {
+ internals.stream.close();
+ });
}
void AsyncFileStream::read(char* buffer, int length)
{
- fileThread()->postTask(
- createFileThreadTask(this, &AsyncFileStream::readOnFileThread,
- AllowCrossThreadAccess(buffer), length));
-}
-
-void AsyncFileStream::readOnFileThread(char* buffer, int length)
-{
- int bytesRead = m_stream->read(buffer, length);
- callOnMainThread(didRead, AllowCrossThreadAccess(this), bytesRead);
-}
-
-static void didWrite(AsyncFileStream* proxy, int bytesWritten)
-{
- if (proxy->client())
- proxy->client()->didWrite(bytesWritten);
-}
-
-void AsyncFileStream::write(const URL& blobURL, long long position, int length)
-{
- fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::writeOnFileThread, blobURL, position, length));
-}
-
-void AsyncFileStream::writeOnFileThread(const URL& blobURL, long long position, int length)
-{
- int bytesWritten = m_stream->write(blobURL, position, length);
- callOnMainThread(didWrite, AllowCrossThreadAccess(this), bytesWritten);
-}
-
-static void didTruncate(AsyncFileStream* proxy, bool success)
-{
- if (proxy->client())
- proxy->client()->didTruncate(success);
-}
-
-void AsyncFileStream::truncate(long long position)
-{
- fileThread()->postTask(createFileThreadTask(this, &AsyncFileStream::truncateOnFileThread, position));
-}
-
-void AsyncFileStream::truncateOnFileThread(long long position)
-{
- bool success = m_stream->truncate(position);
- callOnMainThread(didTruncate, AllowCrossThreadAccess(this), success);
+ perform([buffer, length](FileStream& stream) -> std::function<void(FileStreamClient&)> {
+ int bytesRead = stream.read(buffer, length);
+ return [bytesRead](FileStreamClient& client) {
+ client.didRead(bytesRead);
+ };
+ });
}
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
diff --git a/Source/WebCore/fileapi/AsyncFileStream.h b/Source/WebCore/fileapi/AsyncFileStream.h
index 849ea2bc9..2098ee3f4 100644
--- a/Source/WebCore/fileapi/AsyncFileStream.h
+++ b/Source/WebCore/fileapi/AsyncFileStream.h
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- * Copyright (C) 2010, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2010, 2012, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -29,14 +29,11 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AsyncFileStream_h
-#define AsyncFileStream_h
-
-#if ENABLE(BLOB)
+#pragma once
+#include <functional>
#include <wtf/Forward.h>
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
+#include <wtf/Function.h>
namespace WebCore {
@@ -44,47 +41,22 @@ class FileStreamClient;
class FileStream;
class URL;
-class AsyncFileStream : public RefCounted<AsyncFileStream> {
+class WEBCORE_EXPORT AsyncFileStream {
public:
- static PassRefPtr<AsyncFileStream> create(FileStreamClient*);
+ explicit AsyncFileStream(FileStreamClient&);
~AsyncFileStream();
void getSize(const String& path, double expectedModificationTime);
void openForRead(const String& path, long long offset, long long length);
- void openForWrite(const String& path);
void close();
void read(char* buffer, int length);
- void write(const URL& blobURL, long long position, int length);
- void truncate(long long position);
-
- // Stops the proxy and schedules it to be destructed. All the pending tasks will be aborted and the file stream will be closed.
- // Note: the caller should deref the instance immediately after calling stop().
- void stop();
-
- FileStreamClient* client() const { return m_client; }
- void setClient(FileStreamClient* client) { m_client = client; }
private:
- AsyncFileStream(FileStreamClient*);
-
- // Called on File thread.
- void startOnFileThread();
- void stopOnFileThread();
- void getSizeOnFileThread(const String& path, double expectedModificationTime);
- void openForReadOnFileThread(const String& path, long long offset, long long length);
- void openForWriteOnFileThread(const String& path);
- void closeOnFileThread();
- void readOnFileThread(char* buffer, int length);
- void writeOnFileThread(const URL& blobURL, long long position, int length);
- void truncateOnFileThread(long long position);
+ void start();
+ void perform(Function<std::function<void(FileStreamClient&)>(FileStream&)>&&);
- RefPtr<FileStream> m_stream;
-
- FileStreamClient* m_client;
+ struct Internals;
+ std::unique_ptr<Internals> m_internals;
};
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
-
-#endif // AsyncFileStream_h
diff --git a/Source/WebCore/fileapi/Blob.cpp b/Source/WebCore/fileapi/Blob.cpp
index 6726bf470..f595b1d25 100644
--- a/Source/WebCore/fileapi/Blob.cpp
+++ b/Source/WebCore/fileapi/Blob.cpp
@@ -31,40 +31,30 @@
#include "config.h"
#include "Blob.h"
+#include "BlobBuilder.h"
+#include "BlobPart.h"
#include "BlobURL.h"
#include "File.h"
-#include "HistogramSupport.h"
-#include "ScriptCallStack.h"
#include "ScriptExecutionContext.h"
#include "ThreadableBlobRegistry.h"
+#include <wtf/NeverDestroyed.h>
#include <wtf/text/CString.h>
namespace WebCore {
-namespace {
-
-// Used in histograms to see when we can actually deprecate the prefixed slice.
-enum SliceHistogramEnum {
- SliceWithoutPrefix,
- SliceWithPrefix,
- SliceHistogramEnumMax,
-};
-
-} // namespace
-
class BlobURLRegistry final : public URLRegistry {
public:
- virtual void registerURL(SecurityOrigin*, const URL&, URLRegistrable*) override;
- virtual void unregisterURL(const URL&) override;
+ void registerURL(SecurityOrigin*, const URL&, URLRegistrable&) override;
+ void unregisterURL(const URL&) override;
static URLRegistry& registry();
};
-void BlobURLRegistry::registerURL(SecurityOrigin* origin, const URL& publicURL, URLRegistrable* blob)
+void BlobURLRegistry::registerURL(SecurityOrigin* origin, const URL& publicURL, URLRegistrable& blob)
{
- ASSERT(&blob->registry() == this);
- ThreadableBlobRegistry::registerBlobURL(origin, publicURL, static_cast<Blob*>(blob)->url());
+ ASSERT(&blob.registry() == this);
+ ThreadableBlobRegistry::registerBlobURL(origin, publicURL, static_cast<Blob&>(blob).url());
}
void BlobURLRegistry::unregisterURL(const URL& url)
@@ -74,39 +64,65 @@ void BlobURLRegistry::unregisterURL(const URL& url)
URLRegistry& BlobURLRegistry::registry()
{
- DEFINE_STATIC_LOCAL(BlobURLRegistry, instance, ());
+ static NeverDestroyed<BlobURLRegistry> instance;
return instance;
}
+Blob::Blob(UninitializedContructor)
+{
+}
Blob::Blob()
: m_size(0)
{
- auto blobData = std::make_unique<BlobData>();
-
- // Create a new internal URL and register it with the provided blob data.
m_internalURL = BlobURL::createInternalURL();
- ThreadableBlobRegistry::registerBlobURL(m_internalURL, std::move(blobData));
+ ThreadableBlobRegistry::registerBlobURL(m_internalURL, { }, { });
}
-Blob::Blob(std::unique_ptr<BlobData> blobData, long long size)
- : m_type(blobData->contentType())
- , m_size(size)
+Blob::Blob(Vector<BlobPartVariant>&& blobPartVariants, const BlobPropertyBag& propertyBag)
+ : m_internalURL(BlobURL::createInternalURL())
+ , m_type(normalizedContentType(propertyBag.type))
+ , m_size(-1)
{
- ASSERT(blobData);
+ BlobBuilder builder(propertyBag.endings);
+ for (auto& blobPartVariant : blobPartVariants) {
+ WTF::switchOn(blobPartVariant,
+ [&] (auto& part) {
+ builder.append(WTFMove(part));
+ }
+ );
+ }
- // Create a new internal URL and register it with the provided blob data.
+ ThreadableBlobRegistry::registerBlobURL(m_internalURL, builder.finalize(), m_type);
+}
+
+Blob::Blob(Vector<uint8_t>&& data, const String& contentType)
+ : m_type(contentType)
+ , m_size(data.size())
+{
+ Vector<BlobPart> blobParts;
+ blobParts.append(BlobPart(WTFMove(data)));
m_internalURL = BlobURL::createInternalURL();
- ThreadableBlobRegistry::registerBlobURL(m_internalURL, std::move(blobData));
+ ThreadableBlobRegistry::registerBlobURL(m_internalURL, WTFMove(blobParts), contentType);
}
-Blob::Blob(const URL& srcURL, const String& type, long long size)
- : m_type(Blob::normalizedContentType(type))
+Blob::Blob(DeserializationContructor, const URL& srcURL, const String& type, long long size, const String& fileBackedPath)
+ : m_type(normalizedContentType(type))
, m_size(size)
{
- // Create a new internal URL and register it with the same blob data as the source URL.
m_internalURL = BlobURL::createInternalURL();
- ThreadableBlobRegistry::registerBlobURL(0, m_internalURL, srcURL);
+ if (fileBackedPath.isEmpty())
+ ThreadableBlobRegistry::registerBlobURL(nullptr, m_internalURL, srcURL);
+ else
+ ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked(m_internalURL, srcURL, fileBackedPath, m_type);
+}
+
+Blob::Blob(const URL& srcURL, long long start, long long end, const String& type)
+ : m_type(normalizedContentType(type))
+ , m_size(-1) // size is not necessarily equal to end - start.
+{
+ m_internalURL = BlobURL::createInternalURL();
+ ThreadableBlobRegistry::registerBlobURLForSlice(m_internalURL, srcURL, start, end);
}
Blob::~Blob()
@@ -114,118 +130,63 @@ Blob::~Blob()
ThreadableBlobRegistry::unregisterBlobURL(m_internalURL);
}
-bool Blob::isValidContentType(const String& contentType)
+unsigned long long Blob::size() const
{
- if (contentType.isNull())
- return true;
+ if (m_size < 0) {
+ // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to
+ // come up with an exception to throw if file size is not representable.
+ unsigned long long actualSize = ThreadableBlobRegistry::blobSize(m_internalURL);
+ m_size = WTF::isInBounds<long long>(actualSize) ? static_cast<long long>(actualSize) : 0;
+ }
- 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 static_cast<unsigned long long>(m_size);
+}
+
+bool Blob::isValidContentType(const String& contentType)
+{
+ // FIXME: Do we really want to treat the empty string and null string as valid content types?
+ unsigned length = contentType.length();
+ for (unsigned i = 0; i < length; ++i) {
+ if (contentType[i] < 0x20 || contentType[i] > 0x7e)
+ return false;
}
return true;
}
String Blob::normalizedContentType(const String& contentType)
{
- if (Blob::isValidContentType(contentType))
- return contentType.lower();
- return emptyString();
+ if (!isValidContentType(contentType))
+ return emptyString();
+ return contentType.convertToASCIILowercase();
}
+#if !ASSERT_DISABLED
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;
- }
+ // FIXME: Do we really want to treat the empty string and null string as valid content types?
+ unsigned length = contentType.length();
+ for (size_t i = 0; i < length; ++i) {
+ if (contentType[i] < 0x20 || contentType[i] > 0x7e)
+ return false;
+ if (isASCIIUpper(contentType[i]))
+ return false;
}
return true;
}
bool Blob::isNormalizedContentType(const CString& contentType)
{
+ // FIXME: Do we really want to treat the empty string and null string as valid content types?
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')
+ if (isASCIIUpper(characters[i]))
return false;
}
return true;
}
-
-#if ENABLE(BLOB)
-PassRefPtr<Blob> Blob::slice(long long start, long long end, const String& contentType) const
-{
- // When we slice a file for the first time, we obtain a snapshot of the file by capturing its current size and modification time.
- // The modification time will be used to verify if the file has been changed or not, when the underlying data are accessed.
- long long size;
- double modificationTime;
- if (isFile()) {
- // FIXME: This involves synchronous file operation. We need to figure out how to make it asynchronous.
- toFile(this)->captureSnapshot(size, modificationTime);
- } else {
- ASSERT(m_size != -1);
- size = m_size;
- }
-
- // Convert the negative value that is used to select from the end.
- if (start < 0)
- start = start + size;
- if (end < 0)
- end = end + size;
-
- // Clamp the range if it exceeds the size limit.
- if (start < 0)
- start = 0;
- if (end < 0)
- end = 0;
- if (start >= size) {
- start = 0;
- end = 0;
- } else if (end < start)
- end = start;
- else if (end > size)
- end = size;
-
- long long length = end - start;
- auto blobData = std::make_unique<BlobData>();
- blobData->setContentType(Blob::normalizedContentType(contentType));
- if (isFile())
- blobData->appendFile(toFile(this)->path(), start, length, modificationTime);
- else
- blobData->appendBlob(m_internalURL, start, length);
-
- return Blob::create(std::move(blobData), length);
-}
#endif
URLRegistry& Blob::registry() const
diff --git a/Source/WebCore/fileapi/Blob.h b/Source/WebCore/fileapi/Blob.h
index 3e1e2ad9f..e7b6f8e8f 100644
--- a/Source/WebCore/fileapi/Blob.h
+++ b/Source/WebCore/fileapi/Blob.h
@@ -28,38 +28,47 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef Blob_h
-#define Blob_h
+#pragma once
-#include "BlobData.h"
-#include "URL.h"
+#include "BlobPropertyBag.h"
#include "ScriptWrappable.h"
+#include "URL.h"
#include "URLRegistry.h"
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/text/WTFString.h>
+#include <wtf/Variant.h>
+
+namespace JSC {
+class ArrayBufferView;
+class ArrayBuffer;
+}
namespace WebCore {
+class Blob;
class ScriptExecutionContext;
+using BlobPartVariant = Variant<RefPtr<JSC::ArrayBufferView>, RefPtr<JSC::ArrayBuffer>, RefPtr<Blob>, String>;
+
class Blob : public ScriptWrappable, public URLRegistrable, public RefCounted<Blob> {
public:
- static PassRefPtr<Blob> create()
+ static Ref<Blob> create()
{
- return adoptRef(new Blob);
+ return adoptRef(*new Blob);
}
- static PassRefPtr<Blob> create(std::unique_ptr<BlobData> blobData, long long size)
+ static Ref<Blob> create(Vector<BlobPartVariant>&& blobPartVariants, const BlobPropertyBag& propertyBag)
{
- return adoptRef(new Blob(std::move(blobData), size));
+ return adoptRef(*new Blob(WTFMove(blobPartVariants), propertyBag));
}
- // For deserialization.
- static PassRefPtr<Blob> create(const URL& srcURL, const String& type, long long size)
+ static Ref<Blob> create(Vector<uint8_t>&& data, const String& contentType)
+ {
+ return adoptRef(*new Blob(WTFMove(data), contentType));
+ }
+
+ static Ref<Blob> deserialize(const URL& srcURL, const String& type, long long size, const String& fileBackedPath)
{
ASSERT(Blob::isNormalizedContentType(type));
- return adoptRef(new Blob(srcURL, type, size));
+ return adoptRef(*new Blob(deserializationContructor, srcURL, type, size, fileBackedPath));
}
virtual ~Blob();
@@ -67,30 +76,39 @@ public:
const URL& url() const { return m_internalURL; }
const String& type() const { return m_type; }
- virtual unsigned long long size() const { return static_cast<unsigned long long>(m_size); }
+ WEBCORE_EXPORT unsigned long long size() const;
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.
+#if !ASSERT_DISABLED
static bool isNormalizedContentType(const String&);
static bool isNormalizedContentType(const CString&);
+#endif
// URLRegistrable
- virtual URLRegistry& registry() const override;
+ URLRegistry& registry() const override;
-#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
+ Ref<Blob> slice(long long start = 0, long long end = std::numeric_limits<long long>::max(), const String& contentType = String()) const
+ {
+ return adoptRef(*new Blob(m_internalURL, start, end, contentType));
+ }
protected:
Blob();
- Blob(std::unique_ptr<BlobData>, long long size);
+ Blob(Vector<BlobPartVariant>&&, const BlobPropertyBag&);
+ Blob(Vector<uint8_t>&&, const String& contentType);
+
+ enum UninitializedContructor { uninitializedContructor };
+ Blob(UninitializedContructor);
- // For deserialization.
- Blob(const URL& srcURL, const String& type, long long size);
+ enum DeserializationContructor { deserializationContructor };
+ Blob(DeserializationContructor, const URL& srcURL, const String& type, long long size, const String& fileBackedPath);
+
+ // For slicing.
+ Blob(const URL& srcURL, long long start, long long end, const String& contentType);
// This is an internal URL referring to the blob data associated with this object. It serves
// as an identifier for this blob. The internal URL is never used to source the blob's content
@@ -98,10 +116,7 @@ protected:
URL m_internalURL;
String m_type;
- long long m_size;
+ mutable long long m_size;
};
} // namespace WebCore
-
-#endif // Blob_h
-
diff --git a/Source/WebCore/fileapi/Blob.idl b/Source/WebCore/fileapi/Blob.idl
index ca2dd343b..1ff0e308f 100644
--- a/Source/WebCore/fileapi/Blob.idl
+++ b/Source/WebCore/fileapi/Blob.idl
@@ -28,21 +28,23 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+typedef (ArrayBufferView or ArrayBuffer) BufferSource;
+typedef (BufferSource or Blob or USVString) BlobPart;
+
[
- GlobalContext=DOMWindow&WorkerGlobalScope,
+ Exposed=(Window,Worker),
GenerateIsReachable=Impl,
CustomToJSObject,
- JSNoStaticTables,
- CustomConstructor,
- CustomConstructor(sequence<any> blobParts, optional BlobPropertyBag options),
+ Constructor(optional sequence<BlobPart> 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(optional long long start, optional long long end, [TreatNullAs=NullString, TreatUndefinedAs=NullString] optional DOMString contentType);
-#endif
-#endif
-};
+ // slice Blob into byte-ranged chunks
+ Blob slice(optional long long start = 0, optional long long end = 0x7FFFFFFFFFFFFFFF, optional DOMString? contentType = null);
+ // FIXME: Implement:
+ // readonly attribute boolean isClosed;
+ // void close();
+
+};
diff --git a/Source/WebCore/fileapi/FileThread.h b/Source/WebCore/fileapi/BlobBuilder.cpp
index 4b9739e4f..d66dc9ff0 100644
--- a/Source/WebCore/fileapi/FileThread.h
+++ b/Source/WebCore/fileapi/BlobBuilder.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -28,61 +28,63 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FileThread_h
-#define FileThread_h
+#include "config.h"
+#include "BlobBuilder.h"
-#if ENABLE(BLOB)
-
-#include <wtf/MessageQueue.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/Threading.h>
+#include "Blob.h"
+#include "LineEnding.h"
+#include "TextEncoding.h"
+#include <runtime/ArrayBuffer.h>
+#include <runtime/ArrayBufferView.h>
+#include <wtf/text/CString.h>
namespace WebCore {
-class FileStream;
-
-class FileThread : public ThreadSafeRefCounted<FileThread> {
-public:
- static PassRefPtr<FileThread> create()
- {
- return adoptRef(new FileThread());
+BlobBuilder::BlobBuilder(BlobLineEndings endings)
+ : m_endings(endings)
+{
+}
+
+void BlobBuilder::append(RefPtr<ArrayBuffer>&& arrayBuffer)
+{
+ if (!arrayBuffer)
+ return;
+ m_appendableData.append(static_cast<const char*>(arrayBuffer->data()), arrayBuffer->byteLength());
+}
+
+void BlobBuilder::append(RefPtr<ArrayBufferView>&& arrayBufferView)
+{
+ if (!arrayBufferView)
+ return;
+ m_appendableData.append(static_cast<const char*>(arrayBufferView->baseAddress()), arrayBufferView->byteLength());
+}
+
+void BlobBuilder::append(RefPtr<Blob>&& blob)
+{
+ if (!blob)
+ return;
+ if (!m_appendableData.isEmpty())
+ m_items.append(BlobPart(WTFMove(m_appendableData)));
+ m_items.append(BlobPart(blob->url()));
+}
+
+void BlobBuilder::append(const String& text)
+{
+ CString utf8Text = UTF8Encoding().encode(text, EntitiesForUnencodables);
+
+ if (m_endings == BlobLineEndings::Native)
+ normalizeLineEndingsToNative(utf8Text, m_appendableData);
+ else {
+ ASSERT(m_endings == BlobLineEndings::Transparent);
+ m_appendableData.append(utf8Text.data(), utf8Text.length());
}
+}
- ~FileThread();
-
- bool start();
- void stop();
-
- class Task {
- WTF_MAKE_NONCOPYABLE(Task);
- public:
- virtual ~Task() { }
- virtual void performTask() = 0;
- void* instance() const { return m_instance; }
- protected:
- Task(void* instance) : m_instance(instance) { }
- void* m_instance;
- };
-
- void postTask(std::unique_ptr<Task>);
-
- void unscheduleTasks(const void* instance);
-
-private:
- FileThread();
-
- static void fileThreadStart(void*);
- void runLoop();
-
- ThreadIdentifier m_threadID;
- RefPtr<FileThread> m_selfRef;
- MessageQueue<Task> m_queue;
-
- Mutex m_threadCreationMutex;
-};
+Vector<BlobPart> BlobBuilder::finalize()
+{
+ if (!m_appendableData.isEmpty())
+ m_items.append(BlobPart(WTFMove(m_appendableData)));
+ return WTFMove(m_items);
+}
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
-
-#endif // FileThread_h
diff --git a/Source/WebCore/fileapi/WebKitBlobBuilder.h b/Source/WebCore/fileapi/BlobBuilder.h
index bd2bbdfd9..976de344c 100644
--- a/Source/WebCore/fileapi/WebKitBlobBuilder.h
+++ b/Source/WebCore/fileapi/BlobBuilder.h
@@ -28,11 +28,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef WebKitBlobBuilder_h
-#define WebKitBlobBuilder_h
+#pragma once
-#include "BlobData.h"
-#include <wtf/Forward.h>
+#include "BlobPart.h"
+#include "BlobPropertyBag.h"
namespace JSC {
class ArrayBuffer;
@@ -41,35 +40,23 @@ class ArrayBufferView;
namespace WebCore {
-// FIXME: Move this file to BlobBuilder.h
-
class Blob;
-class TextEncoding;
-
-typedef int ExceptionCode;
class BlobBuilder {
public:
- BlobBuilder();
+ BlobBuilder(BlobLineEndings);
- void append(Blob*);
- void append(const String& text, const String& ending);
-#if ENABLE(BLOB)
- void append(JSC::ArrayBuffer*);
- void append(PassRefPtr<JSC::ArrayBufferView>);
-#endif
+ void append(RefPtr<JSC::ArrayBuffer>&&);
+ void append(RefPtr<JSC::ArrayBufferView>&&);
+ void append(RefPtr<Blob>&&);
+ void append(const String& text);
- PassRefPtr<Blob> getBlob(const String& contentType);
+ Vector<BlobPart> finalize();
private:
- void appendBytesData(const void*, size_t);
-
- Vector<char>& getBuffer();
-
- long long m_size;
- BlobDataItemList m_items;
+ BlobLineEndings m_endings;
+ Vector<BlobPart> m_items;
+ Vector<uint8_t> m_appendableData;
};
} // namespace WebCore
-
-#endif // WebKitBlobBuilder_h
diff --git a/Source/WebCore/fileapi/BlobLineEndings.h b/Source/WebCore/fileapi/BlobLineEndings.h
new file mode 100644
index 000000000..92a62c369
--- /dev/null
+++ b/Source/WebCore/fileapi/BlobLineEndings.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 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.
+ */
+
+#pragma once
+
+namespace WebCore {
+
+enum class BlobLineEndings {
+ Transparent,
+ Native
+};
+
+}
diff --git a/Source/WebCore/fileapi/BlobLineEndings.idl b/Source/WebCore/fileapi/BlobLineEndings.idl
new file mode 100644
index 000000000..36831693b
--- /dev/null
+++ b/Source/WebCore/fileapi/BlobLineEndings.idl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 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.
+ */
+
+// FIXME: This is no longer in the FileAPI spec.
+enum BlobLineEndings { "transparent", "native" };
diff --git a/Source/WebCore/fileapi/BlobPropertyBag.h b/Source/WebCore/fileapi/BlobPropertyBag.h
new file mode 100644
index 000000000..ac99ce9b0
--- /dev/null
+++ b/Source/WebCore/fileapi/BlobPropertyBag.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 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.
+ */
+
+#pragma once
+
+#include "BlobLineEndings.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+struct BlobPropertyBag {
+ String type;
+ BlobLineEndings endings = BlobLineEndings::Transparent;
+};
+
+}
diff --git a/Source/WebCore/fileapi/BlobPropertyBag.idl b/Source/WebCore/fileapi/BlobPropertyBag.idl
new file mode 100644
index 000000000..73d3d4338
--- /dev/null
+++ b/Source/WebCore/fileapi/BlobPropertyBag.idl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 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.
+ */
+
+dictionary BlobPropertyBag {
+ DOMString type = "";
+
+ // FIXME: This is no longer in the FileAPI spec.
+ BlobLineEndings endings = "transparent";
+};
diff --git a/Source/WebCore/fileapi/BlobURL.cpp b/Source/WebCore/fileapi/BlobURL.cpp
index 3debf3831..847ea493b 100644
--- a/Source/WebCore/fileapi/BlobURL.cpp
+++ b/Source/WebCore/fileapi/BlobURL.cpp
@@ -39,7 +39,7 @@
namespace WebCore {
-const char BlobURL::kBlobProtocol[] = "blob";
+const char* kBlobProtocol = "blob";
URL BlobURL::createPublicURL(SecurityOrigin* securityOrigin)
{
diff --git a/Source/WebCore/fileapi/BlobURL.h b/Source/WebCore/fileapi/BlobURL.h
index c7fa4fe74..359eaaf7f 100644
--- a/Source/WebCore/fileapi/BlobURL.h
+++ b/Source/WebCore/fileapi/BlobURL.h
@@ -28,8 +28,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef BlobURL_h
-#define BlobURL_h
+#pragma once
#include "URL.h"
@@ -52,14 +51,10 @@ public:
static URL createInternalURL();
static String getOrigin(const URL&);
static String getIdentifier(const URL&);
- static const char* blobProtocol() { return kBlobProtocol; }
private:
static URL createBlobURL(const String& originString);
- static const char kBlobProtocol[];
BlobURL() { }
};
-}
-
-#endif // BlobURL_h
+} // namespace WebCore
diff --git a/Source/WebCore/fileapi/File.cpp b/Source/WebCore/fileapi/File.cpp
index 6f6dd0e61..1298e02a8 100644
--- a/Source/WebCore/fileapi/File.cpp
+++ b/Source/WebCore/fileapi/File.cpp
@@ -26,114 +26,98 @@
#include "config.h"
#include "File.h"
+#include "BlobURL.h"
#include "FileMetadata.h"
#include "FileSystem.h"
#include "MIMETypeRegistry.h"
+#include "ThreadableBlobRegistry.h"
#include <wtf/CurrentTime.h>
#include <wtf/DateMath.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
-static String getContentTypeFromFileName(const String& name, File::ContentTypeLookupPolicy policy)
-{
- String type;
- int index = name.reverseFind('.');
- if (index != -1) {
- if (policy == File::WellKnownContentTypes)
- type = MIMETypeRegistry::getWellKnownMIMETypeForExtension(name.substring(index + 1));
- else {
- ASSERT(policy == File::AllContentTypes);
- type = MIMETypeRegistry::getMIMETypeForExtension(name.substring(index + 1));
- }
- }
- return type;
-}
-
-static std::unique_ptr<BlobData> createBlobDataForFileWithType(const String& path, const String& contentType)
+File::File(const String& path)
+ : Blob(uninitializedContructor)
+ , m_path(path)
{
- auto blobData = std::make_unique<BlobData>();
- ASSERT(Blob::isNormalizedContentType(contentType));
- blobData->setContentType(contentType);
- blobData->appendFile(path);
- return blobData;
+ m_internalURL = BlobURL::createInternalURL();
+ m_size = -1;
+ computeNameAndContentType(m_path, String(), m_name, m_type);
+ ThreadableBlobRegistry::registerFileBlobURL(m_internalURL, path, m_type);
}
-static std::unique_ptr<BlobData> createBlobDataForFile(const String& path, File::ContentTypeLookupPolicy policy)
+File::File(const String& path, const String& nameOverride)
+ : Blob(uninitializedContructor)
+ , m_path(path)
{
- return createBlobDataForFileWithType(path, getContentTypeFromFileName(path, policy));
+ m_internalURL = BlobURL::createInternalURL();
+ m_size = -1;
+ computeNameAndContentType(m_path, nameOverride, m_name, m_type);
+ ThreadableBlobRegistry::registerFileBlobURL(m_internalURL, path, m_type);
}
-static std::unique_ptr<BlobData> createBlobDataForFileWithName(const String& path, const String& fileSystemName, File::ContentTypeLookupPolicy policy)
+File::File(DeserializationContructor, const String& path, const URL& url, const String& type, const String& name)
+ : Blob(deserializationContructor, url, type, -1, path)
+ , m_path(path)
+ , m_name(name)
{
- return createBlobDataForFileWithType(path, getContentTypeFromFileName(fileSystemName, policy));
}
-#if ENABLE(DIRECTORY_UPLOAD)
-PassRefPtr<File> File::createWithRelativePath(const String& path, const String& relativePath)
+static BlobPropertyBag convertPropertyBag(const File::PropertyBag& initialBag)
{
- RefPtr<File> file = adoptRef(new File(path, AllContentTypes));
- file->m_relativePath = relativePath;
- return file.release();
+ BlobPropertyBag bag;
+ bag.type = initialBag.type;
+ return bag;
}
-#endif
-File::File(const String& path, ContentTypeLookupPolicy policy)
- : Blob(createBlobDataForFile(path, policy), -1)
- , m_path(path)
- , m_name(pathGetFileName(path))
+File::File(Vector<BlobPartVariant>&& blobPartVariants, const String& filename, const PropertyBag& propertyBag)
+ : Blob(WTFMove(blobPartVariants), convertPropertyBag(propertyBag))
+ , m_name(filename)
+ , m_overrideLastModifiedDate(propertyBag.lastModified.value_or(currentTimeMS()))
{
}
-File::File(const String& path, const URL& url, const String& type)
- : Blob(url, type, -1)
- , m_path(path)
+double File::lastModified() const
{
- 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
-}
+ if (m_overrideLastModifiedDate)
+ return m_overrideLastModifiedDate.value();
-File::File(const String& path, const String& name, ContentTypeLookupPolicy policy)
- : Blob(createBlobDataForFileWithName(path, name, policy), -1)
- , m_path(path)
- , m_name(name)
-{
-}
+ double result;
-double File::lastModifiedDate() const
-{
+ // FIXME: This does sync-i/o on the main thread and also recalculates every time the method is called.
+ // The i/o should be performed on a background thread,
+ // and the result should be cached along with an asynchronous monitor for changes to the file.
time_t modificationTime;
if (getFileModificationTime(m_path, modificationTime) && isValidFileTime(modificationTime))
- return modificationTime * msPerSecond;
+ result = modificationTime * msPerSecond;
+ else
+ result = currentTime() * msPerSecond;
- return currentTime() * msPerSecond;
+ return WTF::timeClip(result);
}
-unsigned long long File::size() const
+void File::computeNameAndContentType(const String& path, const String& nameOverride, String& effectiveName, String& effectiveContentType)
{
- // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to
- // come up with an exception to throw if file size is not representable.
- long long size;
- if (!getFileSize(m_path, size))
- return 0;
- return static_cast<unsigned long long>(size);
+#if ENABLE(FILE_REPLACEMENT)
+ if (shouldReplaceFile(path)) {
+ computeNameAndContentTypeForReplacedFile(path, nameOverride, effectiveName, effectiveContentType);
+ return;
+ }
+#endif
+ effectiveName = nameOverride.isNull() ? pathGetFileName(path) : nameOverride;
+ size_t index = effectiveName.reverseFind('.');
+ if (index != notFound)
+ effectiveContentType = MIMETypeRegistry::getMIMETypeForExtension(effectiveName.substring(index + 1));
}
-void File::captureSnapshot(long long& snapshotSize, double& snapshotModificationTime) const
+String File::contentTypeForFile(const String& path)
{
- // Obtains a snapshot of the file by capturing its current size and modification time. This is used when we slice a file for the first time.
- // If we fail to retrieve the size or modification time, probably due to that the file has been deleted, 0 size is returned.
- FileMetadata metadata;
- if (!getFileMetadata(m_path, metadata)) {
- snapshotSize = 0;
- snapshotModificationTime = invalidFileTime();
- return;
- }
+ String name;
+ String type;
+ computeNameAndContentType(path, String(), name, type);
- snapshotSize = metadata.length;
- snapshotModificationTime = metadata.modificationTime;
+ return type;
}
} // namespace WebCore
diff --git a/Source/WebCore/fileapi/File.h b/Source/WebCore/fileapi/File.h
index edf485582..fbe357254 100644
--- a/Source/WebCore/fileapi/File.h
+++ b/Source/WebCore/fileapi/File.h
@@ -23,94 +23,80 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef File_h
-#define File_h
+#pragma once
#include "Blob.h"
-#include <wtf/PassRefPtr.h>
+#include <wtf/Optional.h>
+#include <wtf/Ref.h>
+#include <wtf/TypeCasts.h>
#include <wtf/text/WTFString.h>
namespace WebCore {
-struct FileMetadata;
class URL;
-class File : public Blob {
+class File final : public Blob {
public:
- // AllContentTypes should only be used when the full path/name are trusted; otherwise, it could
- // allow arbitrary pages to determine what applications an user has installed.
- enum ContentTypeLookupPolicy {
- WellKnownContentTypes,
- AllContentTypes,
+ struct PropertyBag : BlobPropertyBag {
+ std::optional<long long> lastModified;
};
- static PassRefPtr<File> create(const String& path, ContentTypeLookupPolicy policy = WellKnownContentTypes)
+ static Ref<File> create(const String& path)
{
- return adoptRef(new File(path, policy));
+ return adoptRef(*new File(path));
}
- // For deserialization.
- static PassRefPtr<File> create(const String& path, const URL& srcURL, const String& type)
+ // Create a File using the 'new File' constructor.
+ static Ref<File> create(Vector<BlobPartVariant>&& blobPartVariants, const String& filename, const PropertyBag& propertyBag)
{
- return adoptRef(new File(path, srcURL, type));
+ return adoptRef(*new File(WTFMove(blobPartVariants), filename, propertyBag));
}
-#if ENABLE(DIRECTORY_UPLOAD)
- static PassRefPtr<File> createWithRelativePath(const String& path, const String& relativePath);
-#endif
+ static Ref<File> deserialize(const String& path, const URL& srcURL, const String& type, const String& name)
+ {
+ return adoptRef(*new File(deserializationContructor, path, srcURL, type, name));
+ }
// Create a file with a name exposed to the author (via File.name and associated DOM properties) that differs from the one provided in the path.
- static PassRefPtr<File> createWithName(const String& path, const String& name, ContentTypeLookupPolicy policy = WellKnownContentTypes)
+ static Ref<File> createWithName(const String& path, const String& nameOverride)
{
- if (name.isEmpty())
- return adoptRef(new File(path, policy));
- return adoptRef(new File(path, name, policy));
+ if (nameOverride.isEmpty())
+ return adoptRef(*new File(path));
+ return adoptRef(*new File(path, nameOverride));
}
- virtual unsigned long long size() const override;
- virtual bool isFile() const override { return true; }
+ bool isFile() const override { return true; }
const String& path() const { return m_path; }
const String& name() const { return m_name; }
+ WEBCORE_EXPORT double lastModified() const;
- // 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;
+ static String contentTypeForFile(const String& path);
-#if ENABLE(DIRECTORY_UPLOAD)
- // Returns the relative path of this file in the context of a directory selection.
- const String& webkitRelativePath() const { return m_relativePath; }
+#if ENABLE(FILE_REPLACEMENT)
+ static bool shouldReplaceFile(const String& path);
#endif
- // Note that this involves synchronous file operation. Think twice before calling this function.
- void captureSnapshot(long long& snapshotSize, double& snapshotModificationTime) const;
-
private:
- File(const String& path, ContentTypeLookupPolicy);
+ WEBCORE_EXPORT explicit File(const String& path);
+ File(const String& path, const String& nameOverride);
+ File(Vector<BlobPartVariant>&& blobPartVariants, const String& filename, const PropertyBag&);
- // For deserialization.
- File(const String& path, const URL& srcURL, const String& type);
- File(const String& path, const String& name, ContentTypeLookupPolicy);
+ File(DeserializationContructor, const String& path, const URL& srcURL, const String& type, const String& name);
+
+ static void computeNameAndContentType(const String& path, const String& nameOverride, String& effectiveName, String& effectiveContentType);
+#if ENABLE(FILE_REPLACEMENT)
+ static void computeNameAndContentTypeForReplacedFile(const String& path, const String& nameOverride, String& effectiveName, String& effectiveContentType);
+#endif
String m_path;
String m_name;
-#if ENABLE(DIRECTORY_UPLOAD)
- String m_relativePath;
-#endif
+ std::optional<int64_t> m_overrideLastModifiedDate;
};
-inline File* toFile(Blob* blob)
-{
- ASSERT_WITH_SECURITY_IMPLICATION(!blob || blob->isFile());
- return static_cast<File*>(blob);
-}
-
-inline const File* toFile(const Blob* blob)
-{
- ASSERT_WITH_SECURITY_IMPLICATION(!blob || blob->isFile());
- return static_cast<const File*>(blob);
-}
-
} // namespace WebCore
-#endif // File_h
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::File)
+ static bool isType(const WebCore::Blob& blob) { return blob.isFile(); }
+SPECIALIZE_TYPE_TRAITS_END()
diff --git a/Source/WebCore/fileapi/File.idl b/Source/WebCore/fileapi/File.idl
index 1d9dc51fc..372bd8155 100644
--- a/Source/WebCore/fileapi/File.idl
+++ b/Source/WebCore/fileapi/File.idl
@@ -23,15 +23,21 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+typedef (ArrayBufferView or ArrayBuffer) BufferSource;
+typedef (BufferSource or Blob or USVString) BlobPart;
+
+// FIXME: This should be exposed on Workers as well.
[
- JSGenerateToNativeObject,
+ Constructor(sequence<BlobPart> fileBits, USVString fileName, optional FilePropertyBag options),
+ ExportMacro=WEBCORE_EXPORT,
+ Exposed=(Window),
JSGenerateToJSObject,
- JSNoStaticTables
+ JSGenerateToNativeObject,
] interface File : Blob {
readonly attribute DOMString name;
-#if !defined(LANGUAGE_GOBJECT) || !LANGUAGE_GOBJECT
- readonly attribute Date lastModifiedDate;
-#endif
- [Conditional=DIRECTORY_UPLOAD] readonly attribute DOMString webkitRelativePath;
+ readonly attribute long long lastModified;
};
+dictionary FilePropertyBag : BlobPropertyBag {
+ long long lastModified;
+};
diff --git a/Source/WebCore/fileapi/FileError.h b/Source/WebCore/fileapi/FileError.h
index 7678a5154..5bc57aa9a 100644
--- a/Source/WebCore/fileapi/FileError.h
+++ b/Source/WebCore/fileapi/FileError.h
@@ -28,12 +28,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FileError_h
-#define FileError_h
+#pragma once
-#if ENABLE(BLOB)
-
-#include <wtf/PassRefPtr.h>
+#include <wtf/Ref.h>
#include <wtf/RefCounted.h>
namespace WebCore {
@@ -56,7 +53,7 @@ public:
PATH_EXISTS_ERR = 12,
};
- static PassRefPtr<FileError> create(ErrorCode code) { return adoptRef(new FileError(code)); }
+ static Ref<FileError> create(ErrorCode code) { return adoptRef(*new FileError(code)); }
ErrorCode code() const { return m_code; }
@@ -69,7 +66,3 @@ private:
};
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
-
-#endif // FileError_h
diff --git a/Source/WebCore/fileapi/FileError.idl b/Source/WebCore/fileapi/FileError.idl
index 866ce9274..34fa4acb5 100644
--- a/Source/WebCore/fileapi/FileError.idl
+++ b/Source/WebCore/fileapi/FileError.idl
@@ -29,12 +29,8 @@
*/
[
- Conditional=BLOB,
- 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).
const unsigned short NOT_FOUND_ERR = 1;
const unsigned short SECURITY_ERR = 2;
const unsigned short ABORT_ERR = 3;
@@ -47,6 +43,6 @@
const unsigned short QUOTA_EXCEEDED_ERR = 10;
const unsigned short TYPE_MISMATCH_ERR = 11;
const unsigned short PATH_EXISTS_ERR = 12;
-#endif
+
readonly attribute unsigned short code;
};
diff --git a/Source/WebCore/fileapi/FileException.cpp b/Source/WebCore/fileapi/FileException.cpp
index 357fb495d..975d1c708 100644
--- a/Source/WebCore/fileapi/FileException.cpp
+++ b/Source/WebCore/fileapi/FileException.cpp
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -27,11 +27,10 @@
*/
#include "config.h"
-
-#if ENABLE(BLOB)
-
#include "FileException.h"
+#include "ExceptionCodeDescription.h"
+
namespace WebCore {
static struct FileExceptionNameDescription {
@@ -71,5 +70,3 @@ bool FileException::initializeDescription(ExceptionCode ec, ExceptionCodeDescrip
}
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
diff --git a/Source/WebCore/fileapi/FileException.h b/Source/WebCore/fileapi/FileException.h
index ccf7982df..dc2d15b9a 100644
--- a/Source/WebCore/fileapi/FileException.h
+++ b/Source/WebCore/fileapi/FileException.h
@@ -28,10 +28,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FileException_h
-#define FileException_h
-
-#if ENABLE(BLOB)
+#pragma once
#include "ExceptionBase.h"
@@ -39,9 +36,9 @@ namespace WebCore {
class FileException : public ExceptionBase {
public:
- static PassRefPtr<FileException> create(const ExceptionCodeDescription& description)
+ static Ref<FileException> create(const ExceptionCodeDescription& description)
{
- return adoptRef(new FileException(description));
+ return adoptRef(*new FileException(description));
}
static const int FileExceptionOffset = 1100;
@@ -79,7 +76,3 @@ private:
};
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
-
-#endif // FileException_h
diff --git a/Source/WebCore/fileapi/FileException.idl b/Source/WebCore/fileapi/FileException.idl
index 8ff47c524..416e22584 100644
--- a/Source/WebCore/fileapi/FileException.idl
+++ b/Source/WebCore/fileapi/FileException.idl
@@ -29,21 +29,15 @@
*/
[
- NoInterfaceObject,
- Conditional=BLOB,
DoNotCheckConstants,
- JSNoStaticTables,
ImplementationLacksVTable,
+ NoInterfaceObject,
] exception FileException {
+ readonly attribute unsigned short code;
+ readonly attribute DOMString name;
+ readonly attribute DOMString message;
- readonly attribute unsigned short code;
- readonly attribute DOMString name;
- readonly attribute DOMString message;
-
-#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT
- // Override in a Mozilla compatible format
[NotEnumerable] DOMString toString();
-#endif
// FileExceptionCode
const unsigned short NOT_FOUND_ERR = 1;
diff --git a/Source/WebCore/fileapi/FileList.h b/Source/WebCore/fileapi/FileList.h
index 1e982ee77..7296bc5de 100644
--- a/Source/WebCore/fileapi/FileList.h
+++ b/Source/WebCore/fileapi/FileList.h
@@ -23,12 +23,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FileList_h
-#define FileList_h
+#pragma once
#include "File.h"
#include "ScriptWrappable.h"
-#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
@@ -37,25 +35,35 @@ namespace WebCore {
class FileList : public ScriptWrappable, public RefCounted<FileList> {
public:
- static PassRefPtr<FileList> create()
+ static Ref<FileList> create()
{
- return adoptRef(new FileList);
+ return adoptRef(*new FileList);
+ }
+
+ static Ref<FileList> create(Vector<RefPtr<File>>&& files)
+ {
+ return adoptRef(*new FileList(WTFMove(files)));
}
unsigned length() const { return m_files.size(); }
- File* item(unsigned index) const;
+ WEBCORE_EXPORT File* item(unsigned index) const;
bool isEmpty() const { return m_files.isEmpty(); }
- void clear() { m_files.clear(); }
- void append(PassRefPtr<File> file) { m_files.append(file); }
Vector<String> paths() const;
private:
FileList();
+ FileList(Vector<RefPtr<File>>&& files)
+ : m_files(WTFMove(files))
+ { }
+
+ // FileLists can only be changed by their owners.
+ friend class DataTransfer;
+ friend class FileInputType;
+ void append(RefPtr<File>&& file) { m_files.append(WTFMove(file)); }
+ void clear() { m_files.clear(); }
Vector<RefPtr<File>> m_files;
};
} // namespace WebCore
-
-#endif // FileList_h
diff --git a/Source/WebCore/fileapi/FileList.idl b/Source/WebCore/fileapi/FileList.idl
index 258f9ccb6..42d553814 100644
--- a/Source/WebCore/fileapi/FileList.idl
+++ b/Source/WebCore/fileapi/FileList.idl
@@ -24,7 +24,6 @@
*/
[
- JSNoStaticTables,
ImplementationLacksVTable,
] interface FileList {
readonly attribute unsigned long length;
diff --git a/Source/WebCore/fileapi/FileReader.cpp b/Source/WebCore/fileapi/FileReader.cpp
index 0025bc045..ea46dd9d6 100644
--- a/Source/WebCore/fileapi/FileReader.cpp
+++ b/Source/WebCore/fileapi/FileReader.cpp
@@ -29,12 +29,9 @@
*/
#include "config.h"
-
-#if ENABLE(BLOB)
-
#include "FileReader.h"
-#include "CrossThreadTask.h"
+#include "EventNames.h"
#include "ExceptionCode.h"
#include "File.h"
#include "Logging.h"
@@ -46,109 +43,107 @@
namespace WebCore {
-static const auto progressNotificationInterval = std::chrono::milliseconds(50);
+// Fire the progress event at least every 50ms.
+static const auto progressNotificationInterval = 50ms;
-PassRefPtr<FileReader> FileReader::create(ScriptExecutionContext& context)
+Ref<FileReader> FileReader::create(ScriptExecutionContext& context)
{
- RefPtr<FileReader> fileReader(adoptRef(new FileReader(context)));
+ auto fileReader = adoptRef(*new FileReader(context));
fileReader->suspendIfNeeded();
- return fileReader.release();
+ return fileReader;
}
FileReader::FileReader(ScriptExecutionContext& context)
: ActiveDOMObject(&context)
- , m_state(EMPTY)
- , m_aborting(false)
- , m_readType(FileReaderLoader::ReadAsBinaryString)
{
}
FileReader::~FileReader()
{
- terminate();
+ if (m_loader)
+ m_loader->cancel();
}
-bool FileReader::canSuspend() const
+bool FileReader::canSuspendForDocumentSuspension() const
{
// FIXME: It is not currently possible to suspend a FileReader, so pages with FileReader can not go into page cache.
return false;
}
+const char* FileReader::activeDOMObjectName() const
+{
+ return "FileReader";
+}
+
void FileReader::stop()
{
- terminate();
+ if (m_loader) {
+ m_loader->cancel();
+ m_loader = nullptr;
+ }
+ m_state = DONE;
}
-void FileReader::readAsArrayBuffer(Blob* blob, ExceptionCode& ec)
+ExceptionOr<void> FileReader::readAsArrayBuffer(Blob* blob)
{
if (!blob)
- return;
+ return { };
- LOG(FileAPI, "FileReader: reading as array buffer: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? toFile(blob)->path().utf8().data() : "");
+ LOG(FileAPI, "FileReader: reading as array buffer: %s %s\n", blob->url().string().utf8().data(), is<File>(*blob) ? downcast<File>(*blob).path().utf8().data() : "");
- readInternal(blob, FileReaderLoader::ReadAsArrayBuffer, ec);
+ return readInternal(*blob, FileReaderLoader::ReadAsArrayBuffer);
}
-void FileReader::readAsBinaryString(Blob* blob, ExceptionCode& ec)
+ExceptionOr<void> FileReader::readAsBinaryString(Blob* blob)
{
if (!blob)
- return;
+ return { };
- LOG(FileAPI, "FileReader: reading as binary: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? toFile(blob)->path().utf8().data() : "");
+ LOG(FileAPI, "FileReader: reading as binary: %s %s\n", blob->url().string().utf8().data(), is<File>(*blob) ? downcast<File>(*blob).path().utf8().data() : "");
- readInternal(blob, FileReaderLoader::ReadAsBinaryString, ec);
+ return readInternal(*blob, FileReaderLoader::ReadAsBinaryString);
}
-void FileReader::readAsText(Blob* blob, const String& encoding, ExceptionCode& ec)
+ExceptionOr<void> FileReader::readAsText(Blob* blob, const String& encoding)
{
if (!blob)
- return;
+ return { };
- LOG(FileAPI, "FileReader: reading as text: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? toFile(blob)->path().utf8().data() : "");
+ LOG(FileAPI, "FileReader: reading as text: %s %s\n", blob->url().string().utf8().data(), is<File>(*blob) ? downcast<File>(*blob).path().utf8().data() : "");
m_encoding = encoding;
- readInternal(blob, FileReaderLoader::ReadAsText, ec);
-}
-
-void FileReader::readAsText(Blob* blob, ExceptionCode& ec)
-{
- readAsText(blob, String(), ec);
+ return readInternal(*blob, FileReaderLoader::ReadAsText);
}
-void FileReader::readAsDataURL(Blob* blob, ExceptionCode& ec)
+ExceptionOr<void> FileReader::readAsDataURL(Blob* blob)
{
if (!blob)
- return;
+ return { };
- LOG(FileAPI, "FileReader: reading as data URL: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? toFile(blob)->path().utf8().data() : "");
+ LOG(FileAPI, "FileReader: reading as data URL: %s %s\n", blob->url().string().utf8().data(), is<File>(*blob) ? downcast<File>(*blob).path().utf8().data() : "");
- readInternal(blob, FileReaderLoader::ReadAsDataURL, ec);
+ return readInternal(*blob, FileReaderLoader::ReadAsDataURL);
}
-void FileReader::readInternal(Blob* blob, FileReaderLoader::ReadType type, ExceptionCode& ec)
+ExceptionOr<void> FileReader::readInternal(Blob& blob, FileReaderLoader::ReadType type)
{
// If multiple concurrent read methods are called on the same FileReader, INVALID_STATE_ERR should be thrown when the state is LOADING.
- if (m_state == LOADING) {
- ec = INVALID_STATE_ERR;
- return;
- }
+ if (m_state == LOADING)
+ return Exception { INVALID_STATE_ERR };
setPendingActivity(this);
- m_blob = blob;
+ m_blob = &blob;
m_readType = type;
m_state = LOADING;
- m_error = 0;
+ m_error = nullptr;
- m_loader = std::make_unique<FileReaderLoader>(m_readType, this);
+ m_loader = std::make_unique<FileReaderLoader>(m_readType, static_cast<FileReaderLoaderClient*>(this));
m_loader->setEncoding(m_encoding);
m_loader->setDataType(m_blob->type());
- m_loader->start(scriptExecutionContext(), m_blob.get());
-}
+ m_loader->start(scriptExecutionContext(), blob);
-static void delayedAbort(ScriptExecutionContext*, FileReader* reader)
-{
- reader->doAbort();
+ return { };
}
void FileReader::abort()
@@ -160,34 +155,21 @@ void FileReader::abort()
m_aborting = true;
// Schedule to have the abort done later since abort() might be called from the event handler and we do not want the resource loading code to be in the stack.
- scriptExecutionContext()->postTask(
- createCallbackTask(&delayedAbort, AllowAccessLater(this)));
-}
-
-void FileReader::doAbort()
-{
- ASSERT(m_state != DONE);
+ scriptExecutionContext()->postTask([this] (ScriptExecutionContext&) {
+ ASSERT(m_state != DONE);
- terminate();
- m_aborting = false;
+ stop();
+ m_aborting = false;
- m_error = FileError::create(FileError::ABORT_ERR);
+ m_error = FileError::create(FileError::ABORT_ERR);
- fireEvent(eventNames().errorEvent);
- fireEvent(eventNames().abortEvent);
- fireEvent(eventNames().loadendEvent);
+ fireEvent(eventNames().errorEvent);
+ fireEvent(eventNames().abortEvent);
+ fireEvent(eventNames().loadendEvent);
- // All possible events have fired and we're done, no more pending activity.
- unsetPendingActivity(this);
-}
-
-void FileReader::terminate()
-{
- if (m_loader) {
- m_loader->cancel();
- m_loader = nullptr;
- }
- m_state = DONE;
+ // All possible events have fired and we're done, no more pending activity.
+ unsetPendingActivity(this);
+ });
}
void FileReader::didStartLoading()
@@ -197,13 +179,11 @@ void FileReader::didStartLoading()
void FileReader::didReceiveData()
{
- // Fire the progress event at least every 50ms.
auto now = std::chrono::steady_clock::now();
if (!m_lastProgressNotificationTime.time_since_epoch().count()) {
m_lastProgressNotificationTime = now;
return;
}
-
if (now - m_lastProgressNotificationTime > progressNotificationInterval) {
fireEvent(eventNames().progressEvent);
m_lastProgressNotificationTime = now;
@@ -248,20 +228,20 @@ void FileReader::fireEvent(const AtomicString& type)
dispatchEvent(ProgressEvent::create(type, true, m_loader ? m_loader->bytesLoaded() : 0, m_loader ? m_loader->totalBytes() : 0));
}
-PassRefPtr<ArrayBuffer> FileReader::arrayBufferResult() const
+std::optional<Variant<String, RefPtr<JSC::ArrayBuffer>>> FileReader::result() const
{
if (!m_loader || m_error)
- return 0;
- return m_loader->arrayBufferResult();
-}
-
-String FileReader::stringResult()
-{
- if (!m_loader || m_error)
- return String();
- return m_loader->stringResult();
+ return std::nullopt;
+ if (m_readType == FileReaderLoader::ReadAsArrayBuffer) {
+ auto result = m_loader->arrayBufferResult();
+ if (!result)
+ return std::nullopt;
+ return { result };
+ }
+ String result = m_loader->stringResult();
+ if (result.isNull())
+ return std::nullopt;
+ return { WTFMove(result) };
}
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
diff --git a/Source/WebCore/fileapi/FileReader.h b/Source/WebCore/fileapi/FileReader.h
index 789701635..c13a5929b 100644
--- a/Source/WebCore/fileapi/FileReader.h
+++ b/Source/WebCore/fileapi/FileReader.h
@@ -28,20 +28,15 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FileReader_h
-#define FileReader_h
-
-#if ENABLE(BLOB)
+#pragma once
#include "ActiveDOMObject.h"
#include "EventTarget.h"
+#include "ExceptionOr.h"
#include "FileError.h"
#include "FileReaderLoader.h"
#include "FileReaderLoaderClient.h"
#include <chrono>
-#include <wtf/Forward.h>
-#include <wtf/RefCounted.h>
-#include <wtf/text/WTFString.h>
namespace JSC {
class ArrayBuffer;
@@ -50,13 +45,10 @@ class ArrayBuffer;
namespace WebCore {
class Blob;
-class ScriptExecutionContext;
-
-typedef int ExceptionCode;
-class FileReader final : public RefCounted<FileReader>, public ActiveDOMObject, public EventTargetWithInlineData, public FileReaderLoaderClient {
+class FileReader final : public RefCounted<FileReader>, public ActiveDOMObject, public EventTargetWithInlineData, private FileReaderLoaderClient {
public:
- static PassRefPtr<FileReader> create(ScriptExecutionContext&);
+ static Ref<FileReader> create(ScriptExecutionContext&);
virtual ~FileReader();
@@ -66,61 +58,47 @@ public:
DONE = 2
};
- void readAsArrayBuffer(Blob*, ExceptionCode&);
- void readAsBinaryString(Blob*, ExceptionCode&);
- void readAsText(Blob*, const String& encoding, ExceptionCode&);
- void readAsText(Blob*, ExceptionCode&);
- void readAsDataURL(Blob*, ExceptionCode&);
+ ExceptionOr<void> readAsArrayBuffer(Blob*);
+ ExceptionOr<void> readAsBinaryString(Blob*);
+ ExceptionOr<void> readAsText(Blob*, const String& encoding);
+ ExceptionOr<void> readAsDataURL(Blob*);
void abort();
void doAbort();
ReadyState readyState() const { return m_state; }
- PassRefPtr<FileError> error() { return m_error; }
+ RefPtr<FileError> error() { return m_error; }
FileReaderLoader::ReadType readType() const { return m_readType; }
- PassRefPtr<JSC::ArrayBuffer> arrayBufferResult() const;
- String stringResult();
-
- // EventTarget
- virtual EventTargetInterface eventTargetInterface() const override { return FileReaderEventTargetInterfaceType; }
- virtual ScriptExecutionContext* scriptExecutionContext() const override { return ActiveDOMObject::scriptExecutionContext(); }
-
- // FileReaderLoaderClient
- virtual void didStartLoading() override;
- virtual void didReceiveData() override;
- virtual void didFinishLoading() override;
- virtual void didFail(int errorCode) override;
+ std::optional<Variant<String, RefPtr<JSC::ArrayBuffer>>> result() const;
- using RefCounted<FileReader>::ref;
- using RefCounted<FileReader>::deref;
-
- DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(progress);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(load);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(loadend);
+ using RefCounted::ref;
+ using RefCounted::deref;
private:
explicit FileReader(ScriptExecutionContext&);
- // ActiveDOMObject
- virtual bool canSuspend() const override;
- virtual void stop() override;
+ const char* activeDOMObjectName() const final;
+ bool canSuspendForDocumentSuspension() const final;
+ void stop() final;
+
+ EventTargetInterface eventTargetInterface() const final { return FileReaderEventTargetInterfaceType; }
+ ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); }
+ void refEventTarget() final { ref(); }
+ void derefEventTarget() final { deref(); }
- // EventTarget
- virtual void refEventTarget() override { ref(); }
- virtual void derefEventTarget() override { deref(); }
+ void didStartLoading() final;
+ void didReceiveData() final;
+ void didFinishLoading() final;
+ void didFail(int errorCode) final;
- void terminate();
- void readInternal(Blob*, FileReaderLoader::ReadType, ExceptionCode&);
+ ExceptionOr<void> readInternal(Blob&, FileReaderLoader::ReadType);
void fireErrorEvent(int httpStatusCode);
void fireEvent(const AtomicString& type);
- ReadyState m_state;
- bool m_aborting;
+ ReadyState m_state { EMPTY };
+ bool m_aborting { false };
RefPtr<Blob> m_blob;
- FileReaderLoader::ReadType m_readType;
+ FileReaderLoader::ReadType m_readType { FileReaderLoader::ReadAsBinaryString };
String m_encoding;
std::unique_ptr<FileReaderLoader> m_loader;
RefPtr<FileError> m_error;
@@ -128,7 +106,3 @@ private:
};
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
-
-#endif // FileReader_h
diff --git a/Source/WebCore/fileapi/FileReader.idl b/Source/WebCore/fileapi/FileReader.idl
index 6ad56e323..a033a3b8d 100644
--- a/Source/WebCore/fileapi/FileReader.idl
+++ b/Source/WebCore/fileapi/FileReader.idl
@@ -30,46 +30,34 @@
*/
[
- GlobalContext=DOMWindow&WorkerGlobalScope,
- Conditional=BLOB,
+ Exposed=(Window,Worker),
ActiveDOMObject,
Constructor,
ConstructorCallWith=ScriptExecutionContext,
- EventTarget,
- JSNoStaticTables,
-] interface FileReader {
+] interface FileReader : EventTarget {
// ready states
const unsigned short EMPTY = 0;
const unsigned short LOADING = 1;
const unsigned short DONE = 2;
readonly attribute unsigned short readyState;
+ // FIXME: In all four methods found below, the blob parameter should not be nullable.
// async read methods
- [RaisesException] void readAsArrayBuffer(Blob blob);
- [RaisesException] void readAsBinaryString(Blob blob);
- [RaisesException] void readAsText(Blob blob, optional DOMString encoding);
- [RaisesException] void readAsDataURL(Blob blob);
+ [MayThrowException] void readAsArrayBuffer(Blob? blob);
+ [MayThrowException] void readAsBinaryString(Blob? blob);
+ [MayThrowException] void readAsText(Blob? blob, optional DOMString encoding);
+ [MayThrowException] void readAsDataURL(Blob? blob);
void abort();
- // file data
- [Custom] readonly attribute any result;
+ readonly attribute (DOMString or ArrayBuffer)? result;
readonly attribute FileError error;
- // EventTarget interface
- 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;
- attribute EventListener onload;
- attribute EventListener onabort;
- attribute EventListener onerror;
- attribute EventListener onloadend;
+ attribute EventHandler onloadstart;
+ attribute EventHandler onprogress;
+ attribute EventHandler onload;
+ attribute EventHandler onabort;
+ attribute EventHandler onerror;
+ attribute EventHandler onloadend;
};
diff --git a/Source/WebCore/fileapi/FileReaderLoader.cpp b/Source/WebCore/fileapi/FileReaderLoader.cpp
index 007ff70a9..7fd08fea1 100644
--- a/Source/WebCore/fileapi/FileReaderLoader.cpp
+++ b/Source/WebCore/fileapi/FileReaderLoader.cpp
@@ -30,13 +30,13 @@
#include "config.h"
-#if ENABLE(BLOB)
-
#include "FileReaderLoader.h"
#include "Blob.h"
#include "BlobURL.h"
#include "FileReaderLoaderClient.h"
+#include "HTTPHeaderNames.h"
+#include "ResourceError.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
#include "ScriptExecutionContext.h"
@@ -44,7 +44,6 @@
#include "ThreadableBlobRegistry.h"
#include "ThreadableLoader.h"
#include <runtime/ArrayBuffer.h>
-#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
#include <wtf/text/Base64.h>
@@ -58,13 +57,10 @@ FileReaderLoader::FileReaderLoader(ReadType readType, FileReaderLoaderClient* cl
: m_readType(readType)
, m_client(client)
, m_isRawDataConverted(false)
- , m_stringResult("")
+ , m_stringResult(emptyString())
, m_variableLength(false)
, m_bytesLoaded(0)
, m_totalBytes(0)
- , m_hasRange(false)
- , m_rangeStart(0)
- , m_rangeEnd(0)
, m_errorCode(0)
{
}
@@ -76,33 +72,33 @@ FileReaderLoader::~FileReaderLoader()
ThreadableBlobRegistry::unregisterBlobURL(m_urlForReading);
}
-void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, Blob* blob)
+void FileReaderLoader::start(ScriptExecutionContext* scriptExecutionContext, Blob& blob)
{
+ ASSERT(scriptExecutionContext);
+
// The blob is read by routing through the request handling layer given a temporary public url.
m_urlForReading = BlobURL::createPublicURL(scriptExecutionContext->securityOrigin());
if (m_urlForReading.isEmpty()) {
failed(FileError::SECURITY_ERR);
return;
}
- ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), m_urlForReading, blob->url());
+ ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), m_urlForReading, blob.url());
// 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;
- options.sniffContent = DoNotSniffContent;
- options.preflightPolicy = ConsiderPreflight;
- options.allowCredentials = AllowStoredCredentials;
- options.crossOriginRequestPolicy = DenyCrossOriginRequests;
+ options.dataBufferingPolicy = DoNotBufferData;
+ options.credentials = FetchOptions::Credentials::Include;
+ options.mode = FetchOptions::Mode::SameOrigin;
+ options.contentSecurityPolicyEnforcement = ContentSecurityPolicyEnforcement::DoNotEnforce;
if (m_client)
- m_loader = ThreadableLoader::create(scriptExecutionContext, this, request, options);
+ m_loader = ThreadableLoader::create(*scriptExecutionContext, *this, WTFMove(request), options);
else
- ThreadableLoader::loadResourceSynchronously(scriptExecutionContext, request, *this, options);
+ ThreadableLoader::loadResourceSynchronously(*scriptExecutionContext, WTFMove(request), *this, options);
}
void FileReaderLoader::cancel()
@@ -121,12 +117,12 @@ void FileReaderLoader::terminate()
void FileReaderLoader::cleanup()
{
- m_loader = 0;
+ m_loader = nullptr;
// If we get any error, we do not need to keep a buffer around.
if (m_errorCode) {
- m_rawData = 0;
- m_stringResult = "";
+ m_rawData = nullptr;
+ m_stringResult = emptyString();
}
}
@@ -137,16 +133,12 @@ void FileReaderLoader::didReceiveResponse(unsigned long, const ResourceResponse&
return;
}
- unsigned long long length = response.expectedContentLength();
+ 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) {
+ // A negative value means that the content length wasn't specified, so the buffer will need to be dynamically grown.
+ if (length < 0) {
m_variableLength = true;
- if (m_hasRange)
- length = 1 + m_rangeEnd - m_rangeStart;
- else
- length = defaultBufferLength;
+ length = defaultBufferLength;
}
// Check that we can cast to unsigned since we have to do
@@ -158,7 +150,7 @@ void FileReaderLoader::didReceiveResponse(unsigned long, const ResourceResponse&
}
ASSERT(!m_rawData);
- m_rawData = ArrayBuffer::create(static_cast<unsigned>(length), 1);
+ m_rawData = ArrayBuffer::tryCreate(static_cast<unsigned>(length), 1);
if (!m_rawData) {
failed(FileError::NOT_READABLE_ERR);
@@ -189,17 +181,26 @@ void FileReaderLoader::didReceiveData(const char* data, int dataLength)
return;
}
if (m_variableLength) {
- unsigned long long newLength = m_totalBytes * 2;
- if (newLength > std::numeric_limits<unsigned>::max())
- newLength = std::numeric_limits<unsigned>::max();
- RefPtr<ArrayBuffer> newData =
- ArrayBuffer::create(static_cast<unsigned>(newLength), 1);
+ unsigned newLength = m_totalBytes + static_cast<unsigned>(dataLength);
+ if (newLength < m_totalBytes) {
+ failed(FileError::NOT_READABLE_ERR);
+ return;
+ }
+ newLength = std::max(newLength, m_totalBytes + m_totalBytes / 4 + 1);
+ auto newData = ArrayBuffer::tryCreate(newLength, 1);
+ if (!newData) {
+ // Not enough memory.
+ failed(FileError::NOT_READABLE_ERR);
+ return;
+ }
memcpy(static_cast<char*>(newData->data()), static_cast<char*>(m_rawData->data()), m_bytesLoaded);
m_rawData = newData;
m_totalBytes = static_cast<unsigned>(newLength);
- } else
+ } else {
+ // This can only happen if we get more data than indicated in expected content length (i.e. never, unless the networking layer is buggy).
length = remainingBufferSpace;
+ }
}
if (length <= 0)
@@ -227,13 +228,13 @@ void FileReaderLoader::didFinishLoading(unsigned long, double)
m_client->didFinishLoading();
}
-void FileReaderLoader::didFail(const ResourceError&)
+void FileReaderLoader::didFail(const ResourceError& error)
{
// If we're aborting, do not proceed with normal error handling since it is covered in aborting code.
if (m_errorCode == FileError::ABORT_ERR)
return;
- failed(FileError::NOT_READABLE_ERR);
+ failed(toErrorCode(static_cast<BlobResourceHandle::Error>(error.errorCode())));
}
void FileReaderLoader::failed(int errorCode)
@@ -244,32 +245,40 @@ void FileReaderLoader::failed(int errorCode)
m_client->didFail(m_errorCode);
}
+FileError::ErrorCode FileReaderLoader::toErrorCode(BlobResourceHandle::Error error)
+{
+ switch (error) {
+ case BlobResourceHandle::Error::NotFoundError:
+ return FileError::NOT_FOUND_ERR;
+ default:
+ return FileError::NOT_READABLE_ERR;
+ }
+}
+
FileError::ErrorCode FileReaderLoader::httpStatusCodeToErrorCode(int httpStatusCode)
{
switch (httpStatusCode) {
case 403:
return FileError::SECURITY_ERR;
- case 404:
- return FileError::NOT_FOUND_ERR;
default:
return FileError::NOT_READABLE_ERR;
}
}
-PassRefPtr<ArrayBuffer> FileReaderLoader::arrayBufferResult() const
+RefPtr<ArrayBuffer> FileReaderLoader::arrayBufferResult() const
{
ASSERT(m_readType == ReadAsArrayBuffer);
// If the loading is not started or an error occurs, return an empty result.
if (!m_rawData || m_errorCode)
- return 0;
+ return nullptr;
// If completed, we can simply return our buffer.
if (isCompleted())
return m_rawData;
// Otherwise, return a copy.
- return ArrayBuffer::create(m_rawData.get());
+ return ArrayBuffer::create(*m_rawData);
}
String FileReaderLoader::stringResult()
@@ -316,21 +325,18 @@ void FileReaderLoader::convertToText()
// requirement in order to be consistent with how WebKit decodes the web content: always has the BOM override the
// provided encoding.
// FIXME: consider supporting incremental decoding to improve the perf.
- StringBuilder builder;
if (!m_decoder)
m_decoder = TextResourceDecoder::create("text/plain", m_encoding.isValid() ? m_encoding : UTF8Encoding());
- builder.append(m_decoder->decode(static_cast<const char*>(m_rawData->data()), m_bytesLoaded));
-
if (isCompleted())
- builder.append(m_decoder->flush());
-
- m_stringResult = builder.toString();
+ m_stringResult = m_decoder->decodeAndFlush(static_cast<const char*>(m_rawData->data()), m_bytesLoaded);
+ else
+ m_stringResult = m_decoder->decode(static_cast<const char*>(m_rawData->data()), m_bytesLoaded);
}
void FileReaderLoader::convertToDataURL()
{
StringBuilder builder;
- builder.append("data:");
+ builder.appendLiteral("data:");
if (!m_bytesLoaded) {
m_stringResult = builder.toString();
@@ -338,7 +344,7 @@ void FileReaderLoader::convertToDataURL()
}
builder.append(m_dataType);
- builder.append(";base64,");
+ builder.appendLiteral(";base64,");
Vector<char> out;
base64Encode(m_rawData->data(), m_bytesLoaded, out);
@@ -360,5 +366,3 @@ void FileReaderLoader::setEncoding(const String& encoding)
}
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
diff --git a/Source/WebCore/fileapi/FileReaderLoader.h b/Source/WebCore/fileapi/FileReaderLoader.h
index 435662613..5f4e73ed8 100644
--- a/Source/WebCore/fileapi/FileReaderLoader.h
+++ b/Source/WebCore/fileapi/FileReaderLoader.h
@@ -28,11 +28,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FileReaderLoader_h
-#define FileReaderLoader_h
-
-#if ENABLE(BLOB)
+#pragma once
+#include "BlobResourceHandle.h"
#include "FileError.h"
#include "URL.h"
#include "TextEncoding.h"
@@ -66,17 +64,17 @@ public:
FileReaderLoader(ReadType, FileReaderLoaderClient*);
~FileReaderLoader();
- void start(ScriptExecutionContext*, Blob*);
+ void start(ScriptExecutionContext*, Blob&);
void cancel();
// ThreadableLoaderClient
- virtual void didReceiveResponse(unsigned long, const ResourceResponse&);
- virtual void didReceiveData(const char*, int);
- virtual void didFinishLoading(unsigned long, double);
- virtual void didFail(const ResourceError&);
+ void didReceiveResponse(unsigned long, const ResourceResponse&) override;
+ void didReceiveData(const char*, int) override;
+ void didFinishLoading(unsigned long, double) override;
+ void didFail(const ResourceError&) override;
String stringResult();
- PassRefPtr<JSC::ArrayBuffer> arrayBufferResult() const;
+ RefPtr<JSC::ArrayBuffer> arrayBufferResult() const;
unsigned bytesLoaded() const { return m_bytesLoaded; }
unsigned totalBytes() const { return m_totalBytes; }
int errorCode() const { return m_errorCode; }
@@ -94,6 +92,7 @@ private:
bool isCompleted() const;
static FileError::ErrorCode httpStatusCodeToErrorCode(int);
+ static FileError::ErrorCode toErrorCode(BlobResourceHandle::Error);
ReadType m_readType;
FileReaderLoaderClient* m_client;
@@ -116,15 +115,7 @@ private:
unsigned m_bytesLoaded;
unsigned m_totalBytes;
- bool m_hasRange;
- unsigned m_rangeStart;
- unsigned m_rangeEnd;
-
int m_errorCode;
};
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
-
-#endif // FileReaderLoader_h
diff --git a/Source/WebCore/fileapi/FileReaderLoaderClient.h b/Source/WebCore/fileapi/FileReaderLoaderClient.h
index 4acb8ad3a..c2faaba10 100644
--- a/Source/WebCore/fileapi/FileReaderLoaderClient.h
+++ b/Source/WebCore/fileapi/FileReaderLoaderClient.h
@@ -28,10 +28,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FileReaderLoaderClient_h
-#define FileReaderLoaderClient_h
-
-#if ENABLE(BLOB)
+#pragma once
namespace WebCore {
@@ -46,7 +43,3 @@ public:
};
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
-
-#endif // FileReaderLoaderClient_h
diff --git a/Source/WebCore/fileapi/FileReaderSync.cpp b/Source/WebCore/fileapi/FileReaderSync.cpp
index 2d53afd1b..da475d504 100644
--- a/Source/WebCore/fileapi/FileReaderSync.cpp
+++ b/Source/WebCore/fileapi/FileReaderSync.cpp
@@ -30,8 +30,6 @@
#include "config.h"
-#if ENABLE(BLOB)
-
#include "FileReaderSync.h"
#include "Blob.h"
@@ -39,7 +37,6 @@
#include "FileException.h"
#include "FileReaderLoader.h"
#include <runtime/ArrayBuffer.h>
-#include <wtf/PassRefPtr.h>
namespace WebCore {
@@ -47,63 +44,49 @@ FileReaderSync::FileReaderSync()
{
}
-PassRefPtr<ArrayBuffer> FileReaderSync::readAsArrayBuffer(ScriptExecutionContext* scriptExecutionContext, Blob* blob, ExceptionCode& ec)
+ExceptionOr<RefPtr<ArrayBuffer>> FileReaderSync::readAsArrayBuffer(ScriptExecutionContext& scriptExecutionContext, Blob& blob)
{
- if (!blob) {
- ec = NOT_FOUND_ERR;
- return 0;
- }
-
FileReaderLoader loader(FileReaderLoader::ReadAsArrayBuffer, 0);
- startLoading(scriptExecutionContext, loader, blob, ec);
-
+ auto result = startLoading(scriptExecutionContext, loader, blob);
+ if (result.hasException())
+ return result.releaseException();
return loader.arrayBufferResult();
}
-String FileReaderSync::readAsBinaryString(ScriptExecutionContext* scriptExecutionContext, Blob* blob, ExceptionCode& ec)
+ExceptionOr<String> FileReaderSync::readAsBinaryString(ScriptExecutionContext& scriptExecutionContext, Blob& blob)
{
- if (!blob) {
- ec = NOT_FOUND_ERR;
- return String();
- }
-
FileReaderLoader loader(FileReaderLoader::ReadAsBinaryString, 0);
- startLoading(scriptExecutionContext, loader, blob, ec);
- return loader.stringResult();
+ return startLoadingString(scriptExecutionContext, loader, blob);
}
-String FileReaderSync::readAsText(ScriptExecutionContext* scriptExecutionContext, Blob* blob, const String& encoding, ExceptionCode& ec)
+ExceptionOr<String> FileReaderSync::readAsText(ScriptExecutionContext& scriptExecutionContext, Blob& blob, const String& encoding)
{
- if (!blob) {
- ec = NOT_FOUND_ERR;
- return String();
- }
-
FileReaderLoader loader(FileReaderLoader::ReadAsText, 0);
loader.setEncoding(encoding);
- startLoading(scriptExecutionContext, loader, blob, ec);
- return loader.stringResult();
+ return startLoadingString(scriptExecutionContext, loader, blob);
}
-String FileReaderSync::readAsDataURL(ScriptExecutionContext* scriptExecutionContext, Blob* blob, ExceptionCode& ec)
+ExceptionOr<String> FileReaderSync::readAsDataURL(ScriptExecutionContext& scriptExecutionContext, Blob& blob)
{
- if (!blob) {
- ec = NOT_FOUND_ERR;
- return String();
- }
-
FileReaderLoader loader(FileReaderLoader::ReadAsDataURL, 0);
- loader.setDataType(blob->type());
- startLoading(scriptExecutionContext, loader, blob, ec);
- return loader.stringResult();
+ loader.setDataType(blob.type());
+ return startLoadingString(scriptExecutionContext, loader, blob);
+}
+
+ExceptionOr<void> FileReaderSync::startLoading(ScriptExecutionContext& scriptExecutionContext, FileReaderLoader& loader, Blob& blob)
+{
+ loader.start(&scriptExecutionContext, blob);
+ if (ExceptionCode code = FileException::ErrorCodeToExceptionCode(loader.errorCode()))
+ return Exception { code };
+ return { };
}
-void FileReaderSync::startLoading(ScriptExecutionContext* scriptExecutionContext, FileReaderLoader& loader, Blob* blob, ExceptionCode& ec)
+ExceptionOr<String> FileReaderSync::startLoadingString(ScriptExecutionContext& scriptExecutionContext, FileReaderLoader& loader, Blob& blob)
{
- loader.start(scriptExecutionContext, blob);
- ec = FileException::ErrorCodeToExceptionCode(loader.errorCode());
+ auto result = startLoading(scriptExecutionContext, loader, blob);
+ if (result.hasException())
+ return result.releaseException();
+ return loader.stringResult();
}
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
diff --git a/Source/WebCore/fileapi/FileReaderSync.h b/Source/WebCore/fileapi/FileReaderSync.h
index 50140efcd..9e25cda8b 100644
--- a/Source/WebCore/fileapi/FileReaderSync.h
+++ b/Source/WebCore/fileapi/FileReaderSync.h
@@ -28,14 +28,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FileReaderSync_h
-#define FileReaderSync_h
+#pragma once
-#if ENABLE(BLOB)
-
-#include <wtf/Forward.h>
-#include <wtf/RefCounted.h>
-#include <wtf/text/WTFString.h>
+#include "ExceptionOr.h"
namespace JSC {
class ArrayBuffer;
@@ -47,34 +42,23 @@ class Blob;
class FileReaderLoader;
class ScriptExecutionContext;
-typedef int ExceptionCode;
-
class FileReaderSync : public RefCounted<FileReaderSync> {
public:
- static PassRefPtr<FileReaderSync> create()
+ static Ref<FileReaderSync> create()
{
- return adoptRef(new FileReaderSync());
+ return adoptRef(*new FileReaderSync);
}
- virtual ~FileReaderSync() { }
-
- PassRefPtr<JSC::ArrayBuffer> readAsArrayBuffer(ScriptExecutionContext*, Blob*, ExceptionCode&);
- String readAsBinaryString(ScriptExecutionContext*, Blob*, ExceptionCode&);
- String readAsText(ScriptExecutionContext* scriptExecutionContext, Blob* blob, ExceptionCode& ec)
- {
- return readAsText(scriptExecutionContext, blob, "", ec);
- }
- String readAsText(ScriptExecutionContext*, Blob*, const String& encoding, ExceptionCode&);
- String readAsDataURL(ScriptExecutionContext*, Blob*, ExceptionCode&);
+ ExceptionOr<RefPtr<JSC::ArrayBuffer>> readAsArrayBuffer(ScriptExecutionContext&, Blob&);
+ ExceptionOr<String> readAsBinaryString(ScriptExecutionContext&, Blob&);
+ ExceptionOr<String> readAsText(ScriptExecutionContext&, Blob&, const String& encoding);
+ ExceptionOr<String> readAsDataURL(ScriptExecutionContext&, Blob&);
private:
FileReaderSync();
- void startLoading(ScriptExecutionContext*, FileReaderLoader&, Blob*, ExceptionCode&);
+ ExceptionOr<void> startLoading(ScriptExecutionContext&, FileReaderLoader&, Blob&);
+ ExceptionOr<String> startLoadingString(ScriptExecutionContext&, FileReaderLoader&, Blob&);
};
} // namespace WebCore
-
-#endif // ENABLE(BLOB)
-
-#endif // FileReaderSync_h
diff --git a/Source/WebCore/fileapi/FileReaderSync.idl b/Source/WebCore/fileapi/FileReaderSync.idl
index 184f32200..664be3ac9 100644
--- a/Source/WebCore/fileapi/FileReaderSync.idl
+++ b/Source/WebCore/fileapi/FileReaderSync.idl
@@ -29,13 +29,12 @@
*/
[
- GlobalContext=WorkerGlobalScope,
- Conditional=BLOB,
Constructor,
- JSNoStaticTables,
+ Exposed=Worker,
+ ImplementationLacksVTable,
] interface FileReaderSync {
- [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);
+ [CallWith=ScriptExecutionContext, MayThrowException] ArrayBuffer readAsArrayBuffer(Blob blob);
+ [CallWith=ScriptExecutionContext, MayThrowException] DOMString readAsBinaryString(Blob blob);
+ [CallWith=ScriptExecutionContext, MayThrowException] DOMString readAsText(Blob blob, optional DOMString encoding = "");
+ [CallWith=ScriptExecutionContext, MayThrowException] DOMString readAsDataURL(Blob blob);
};
diff --git a/Source/WebCore/fileapi/FileThread.cpp b/Source/WebCore/fileapi/FileThread.cpp
deleted file mode 100644
index e43f0e72d..000000000
--- a/Source/WebCore/fileapi/FileThread.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR 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.
- */
-
-#include "config.h"
-
-#if ENABLE(BLOB)
-
-#include "FileThread.h"
-
-#include "Logging.h"
-#include <wtf/AutodrainedPool.h>
-
-namespace WebCore {
-
-FileThread::FileThread()
- : m_threadID(0)
-{
- m_selfRef = this;
-}
-
-FileThread::~FileThread()
-{
- ASSERT(m_queue.killed());
-}
-
-bool FileThread::start()
-{
- MutexLocker lock(m_threadCreationMutex);
- if (m_threadID)
- return true;
- m_threadID = createThread(FileThread::fileThreadStart, this, "WebCore: File");
- return m_threadID;
-}
-
-void FileThread::stop()
-{
- m_queue.kill();
-}
-
-void FileThread::postTask(std::unique_ptr<Task> task)
-{
- m_queue.append(std::move(task));
-}
-
-class SameInstancePredicate {
-public:
- SameInstancePredicate(const void* instance) : m_instance(instance) { }
- bool operator()(FileThread::Task& task) const { return task.instance() == m_instance; }
-private:
- const void* m_instance;
-};
-
-void FileThread::unscheduleTasks(const void* instance)
-{
- SameInstancePredicate predicate(instance);
- m_queue.removeIf(predicate);
-}
-
-void FileThread::fileThreadStart(void* arg)
-{
- FileThread* fileThread = static_cast<FileThread*>(arg);
- fileThread->runLoop();
-}
-
-void FileThread::runLoop()
-{
- {
- // Wait for FileThread::start() to complete to have m_threadID
- // established before starting the main loop.
- MutexLocker lock(m_threadCreationMutex);
- LOG(FileAPI, "Started FileThread %p", this);
- }
-
- while (auto task = m_queue.waitForMessage()) {
- AutodrainedPool pool;
-
- task->performTask();
- }
-
- LOG(FileAPI, "About to detach thread %i and clear the ref to FileThread %p, which currently has %i ref(s)", m_threadID, this, refCount());
-
- detachThread(m_threadID);
-
- // Clear the self refptr, possibly resulting in deletion
- m_selfRef = 0;
-}
-
-} // namespace WebCore
-
-#endif // ENABLE(BLOB)
diff --git a/Source/WebCore/fileapi/FileThreadTask.h b/Source/WebCore/fileapi/FileThreadTask.h
deleted file mode 100644
index a0541dff9..000000000
--- a/Source/WebCore/fileapi/FileThreadTask.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR 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.
- */
-
-#ifndef FileThreadTask_h
-#define FileThreadTask_h
-
-#include "CrossThreadCopier.h"
-#include "CrossThreadTask.h"
-#include "FileThread.h"
-#include <wtf/PassRefPtr.h>
-
-namespace WebCore {
-
-template<typename T>
-class FileThreadTask0 : public FileThread::Task {
-public:
- typedef void (T::*Method)();
- typedef FileThreadTask0<T> FileThreadTaskImpl;
-
- FileThreadTask0(T* instance, Method method)
- : FileThread::Task(instance)
- , m_method(method)
- {
- }
-
-private:
- virtual void performTask() override
- {
- (*static_cast<T*>(instance()).*m_method)();
- }
-
-private:
- Method m_method;
-};
-
-template<typename T, typename P1, typename MP1>
-class FileThreadTask1 : public FileThread::Task {
-public:
- typedef void (T::*Method)(MP1);
- typedef FileThreadTask1<T, P1, MP1> FileThreadTaskImpl;
- typedef typename CrossThreadTaskTraits<P1>::ParamType Param1;
-
- FileThreadTask1(T* instance, Method method, Param1 parameter1)
- : FileThread::Task(instance)
- , m_method(method)
- , m_parameter1(parameter1)
- {
- }
-
-private:
- virtual void performTask() override
- {
- (*static_cast<T*>(instance()).*m_method)(m_parameter1);
- }
-
-private:
- Method m_method;
- P1 m_parameter1;
-};
-
-template<typename T, typename P1, typename MP1, typename P2, typename MP2>
-class FileThreadTask2 : public FileThread::Task {
-public:
- typedef void (T::*Method)(MP1, MP2);
- typedef FileThreadTask2<T, P1, MP1, P2, MP2> FileThreadTaskImpl;
- typedef typename CrossThreadTaskTraits<P1>::ParamType Param1;
- typedef typename CrossThreadTaskTraits<P2>::ParamType Param2;
-
- FileThreadTask2(T* instance, Method method, Param1 parameter1, Param2 parameter2)
- : FileThread::Task(instance)
- , m_method(method)
- , m_parameter1(parameter1)
- , m_parameter2(parameter2)
- {
- }
-
-private:
- virtual void performTask() override
- {
- (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2);
- }
-
-private:
- Method m_method;
- P1 m_parameter1;
- P2 m_parameter2;
-};
-
-template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3>
-class FileThreadTask3 : public FileThread::Task {
-public:
- typedef void (T::*Method)(MP1, MP2, MP3);
- typedef FileThreadTask3<T, P1, MP1, P2, MP2, P3, MP3> FileThreadTaskImpl;
- typedef typename CrossThreadTaskTraits<P1>::ParamType Param1;
- typedef typename CrossThreadTaskTraits<P2>::ParamType Param2;
- typedef typename CrossThreadTaskTraits<P3>::ParamType Param3;
-
- FileThreadTask3(T* instance, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3)
- : FileThread::Task(instance)
- , m_method(method)
- , m_parameter1(parameter1)
- , m_parameter2(parameter2)
- , m_parameter3(parameter3)
- {
- }
-
-private:
- virtual void performTask() override
- {
- (*static_cast<T*>(instance()).*m_method)(m_parameter1, m_parameter2, m_parameter3);
- }
-
-private:
- Method m_method;
- P1 m_parameter1;
- P2 m_parameter2;
- P3 m_parameter3;
-};
-
-template<typename T>
-std::unique_ptr<FileThread::Task> createFileThreadTask(
- T* const callee,
- void (T::*method)());
-
-template<typename T>
-std::unique_ptr<FileThread::Task> createFileThreadTask(
- T* const callee,
- void (T::*method)())
-{
- return std::make_unique<FileThreadTask0<T>>(
- callee,
- method);
-}
-
-template<typename T, typename P1, typename MP1>
-std::unique_ptr<FileThread::Task> createFileThreadTask(
- T* const callee,
- void (T::*method)(MP1),
- const P1& parameter1)
-{
- return std::make_unique<FileThreadTask1<T, typename CrossThreadCopier<P1>::Type, MP1>>(
- callee,
- method,
- CrossThreadCopier<P1>::copy(parameter1));
-}
-
-template<typename T, typename P1, typename MP1, typename P2, typename MP2>
-std::unique_ptr<FileThread::Task> createFileThreadTask(
- T* const callee,
- void (T::*method)(MP1, MP2),
- const P1& parameter1,
- const P2& parameter2)
-{
- return std::make_unique<FileThreadTask2<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2>>(
- callee,
- method,
- CrossThreadCopier<P1>::copy(parameter1),
- CrossThreadCopier<P2>::copy(parameter2));
-}
-
-template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3>
-std::unique_ptr<FileThread::Task> createFileThreadTask(
- T* const callee,
- void (T::*method)(MP1, MP2, MP3),
- const P1& parameter1,
- const P2& parameter2,
- const P3& parameter3)
-{
- return std::make_unique<FileThreadTask3<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3>>(
- callee,
- method,
- CrossThreadCopier<P1>::copy(parameter1),
- CrossThreadCopier<P2>::copy(parameter2),
- CrossThreadCopier<P3>::copy(parameter3));
-}
-
-} // namespace WebCore
-
-#endif // FileThreadTask_h
diff --git a/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp b/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp
index 19844412e..b6c57a31d 100644
--- a/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp
+++ b/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2013, 2014, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -31,49 +32,25 @@
#include "config.h"
#include "ThreadableBlobRegistry.h"
-#include "BlobData.h"
+#include "BlobDataFileReference.h"
+#include "BlobPart.h"
#include "BlobRegistry.h"
#include "BlobURL.h"
#include "SecurityOrigin.h"
#include <mutex>
+#include <wtf/CrossThreadQueue.h>
+#include <wtf/CrossThreadTask.h>
#include <wtf/HashMap.h>
#include <wtf/MainThread.h>
#include <wtf/RefPtr.h>
#include <wtf/ThreadSpecific.h>
#include <wtf/text/StringHash.h>
+#include <wtf/threads/BinarySemaphore.h>
using WTF::ThreadSpecific;
namespace WebCore {
-struct BlobRegistryContext {
- WTF_MAKE_FAST_ALLOCATED;
-public:
- BlobRegistryContext(const URL& url, std::unique_ptr<BlobData> blobData)
- : url(url.copy())
- , blobData(std::move(blobData))
- {
- this->blobData->detachFromCurrentThread();
- }
-
- BlobRegistryContext(const URL& url, const URL& srcURL)
- : url(url.copy())
- , srcURL(srcURL.copy())
- {
- }
-
- BlobRegistryContext(const URL& url)
- : url(url.copy())
- {
- }
-
- URL url;
- URL srcURL;
- std::unique_ptr<BlobData> blobData;
-};
-
-#if ENABLE(BLOB)
-
typedef HashMap<String, RefPtr<SecurityOrigin>> BlobUrlOriginMap;
static ThreadSpecific<BlobUrlOriginMap>& originMap()
@@ -87,24 +64,45 @@ static ThreadSpecific<BlobUrlOriginMap>& originMap()
return *map;
}
-static void registerBlobURLTask(void* context)
+static void postToMainThread(CrossThreadTask&& task)
{
- std::unique_ptr<BlobRegistryContext> blobRegistryContext(static_cast<BlobRegistryContext*>(context));
- blobRegistry().registerBlobURL(blobRegistryContext->url, std::move(blobRegistryContext->blobData));
+ static std::once_flag onceFlag;
+ static CrossThreadQueue<CrossThreadTask>* queue;
+ std::call_once(onceFlag, [] {
+ queue = new CrossThreadQueue<CrossThreadTask>;
+ });
+
+ queue->append(WTFMove(task));
+
+ callOnMainThread([] {
+ auto task = queue->tryGetMessage();
+ ASSERT(task);
+ task->performTask();
+ });
}
-void ThreadableBlobRegistry::registerBlobURL(const URL& url, std::unique_ptr<BlobData> blobData)
+void ThreadableBlobRegistry::registerFileBlobURL(const URL& url, const String& path, const String& contentType)
{
if (isMainThread())
- blobRegistry().registerBlobURL(url, std::move(blobData));
- else
- callOnMainThread(&registerBlobURLTask, new BlobRegistryContext(url, std::move(blobData)));
+ blobRegistry().registerFileBlobURL(url, BlobDataFileReference::create(path), contentType);
+ else {
+ callOnMainThread([url = url.isolatedCopy(), path = path.isolatedCopy(), contentType = contentType.isolatedCopy()] {
+ blobRegistry().registerFileBlobURL(url, BlobDataFileReference::create(path), contentType);
+ });
+ }
}
-static void registerBlobURLFromTask(void* context)
+void ThreadableBlobRegistry::registerBlobURL(const URL& url, Vector<BlobPart>&& blobParts, const String& contentType)
{
- std::unique_ptr<BlobRegistryContext> blobRegistryContext(static_cast<BlobRegistryContext*>(context));
- blobRegistry().registerBlobURL(blobRegistryContext->url, blobRegistryContext->srcURL);
+ if (isMainThread())
+ blobRegistry().registerBlobURL(url, WTFMove(blobParts), contentType);
+ else {
+ for (auto& part : blobParts)
+ part.detachFromCurrentThread();
+ callOnMainThread([url = url.isolatedCopy(), blobParts = WTFMove(blobParts), contentType = contentType.isolatedCopy()]() mutable {
+ blobRegistry().registerBlobURL(url, WTFMove(blobParts), contentType);
+ });
+ }
}
void ThreadableBlobRegistry::registerBlobURL(SecurityOrigin* origin, const URL& url, const URL& srcURL)
@@ -115,51 +113,65 @@ void ThreadableBlobRegistry::registerBlobURL(SecurityOrigin* origin, const URL&
if (isMainThread())
blobRegistry().registerBlobURL(url, srcURL);
- else
- callOnMainThread(&registerBlobURLFromTask, new BlobRegistryContext(url, srcURL));
+ else {
+ callOnMainThread([url = url.isolatedCopy(), srcURL = srcURL.isolatedCopy()] {
+ blobRegistry().registerBlobURL(url, srcURL);
+ });
+ }
}
-static void unregisterBlobURLTask(void* context)
+void ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked(const URL& url, const URL& srcURL, const String& fileBackedPath, const String& contentType)
{
- std::unique_ptr<BlobRegistryContext> blobRegistryContext(static_cast<BlobRegistryContext*>(context));
- blobRegistry().unregisterBlobURL(blobRegistryContext->url);
-}
-
-void ThreadableBlobRegistry::unregisterBlobURL(const URL& url)
-{
- if (BlobURL::getOrigin(url) == "null")
- originMap()->remove(url.string());
-
if (isMainThread())
- blobRegistry().unregisterBlobURL(url);
+ blobRegistry().registerBlobURLOptionallyFileBacked(url, srcURL, BlobDataFileReference::create(fileBackedPath), contentType);
else
- callOnMainThread(&unregisterBlobURLTask, new BlobRegistryContext(url));
+ postToMainThread(createCrossThreadTask(ThreadableBlobRegistry::registerBlobURLOptionallyFileBacked, url, srcURL, fileBackedPath, contentType));
}
-PassRefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const URL& url)
+void ThreadableBlobRegistry::registerBlobURLForSlice(const URL& newURL, const URL& srcURL, long long start, long long end)
{
- return originMap()->get(url.string());
+ if (isMainThread())
+ blobRegistry().registerBlobURLForSlice(newURL, srcURL, start, end);
+ else {
+ callOnMainThread([newURL = newURL.isolatedCopy(), srcURL = srcURL.isolatedCopy(), start, end] {
+ blobRegistry().registerBlobURLForSlice(newURL, srcURL, start, end);
+ });
+ }
}
-#else
-
-void ThreadableBlobRegistry::registerBlobURL(const URL&, std::unique_ptr<BlobData>)
+unsigned long long ThreadableBlobRegistry::blobSize(const URL& url)
{
+ unsigned long long resultSize;
+ if (isMainThread())
+ resultSize = blobRegistry().blobSize(url);
+ else {
+ BinarySemaphore semaphore;
+ callOnMainThread([url = url.isolatedCopy(), &semaphore, &resultSize] {
+ resultSize = blobRegistry().blobSize(url);
+ semaphore.signal();
+ });
+ semaphore.wait(WallTime::infinity());
+ }
+ return resultSize;
}
-void ThreadableBlobRegistry::registerBlobURL(SecurityOrigin*, const URL&, const URL&)
+void ThreadableBlobRegistry::unregisterBlobURL(const URL& url)
{
-}
+ if (BlobURL::getOrigin(url) == "null")
+ originMap()->remove(url.string());
-void ThreadableBlobRegistry::unregisterBlobURL(const URL&)
-{
+ if (isMainThread())
+ blobRegistry().unregisterBlobURL(url);
+ else {
+ callOnMainThread([url = url.isolatedCopy()] {
+ blobRegistry().unregisterBlobURL(url);
+ });
+ }
}
-PassRefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const URL&)
+RefPtr<SecurityOrigin> ThreadableBlobRegistry::getCachedOrigin(const URL& url)
{
- return 0;
+ return originMap()->get(url.string());
}
-#endif // ENABL(BLOB)
-
} // namespace WebCore
diff --git a/Source/WebCore/fileapi/ThreadableBlobRegistry.h b/Source/WebCore/fileapi/ThreadableBlobRegistry.h
index e2e5c694b..552a5d9b3 100644
--- a/Source/WebCore/fileapi/ThreadableBlobRegistry.h
+++ b/Source/WebCore/fileapi/ThreadableBlobRegistry.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2013, 2014, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -28,28 +29,31 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ThreadableBlobRegistry_h
-#define ThreadableBlobRegistry_h
+#pragma once
-#include <wtf/PassRefPtr.h>
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
namespace WebCore {
-class BlobData;
+class BlobPart;
class URL;
class SecurityOrigin;
class ThreadableBlobRegistry {
public:
- static void registerBlobURL(const URL&, std::unique_ptr<BlobData>);
+ static void registerFileBlobURL(const URL&, const String& path, const String& contentType);
+ static void registerBlobURL(const URL&, Vector<BlobPart>&& blobParts, const String& contentType);
static void registerBlobURL(SecurityOrigin*, const URL&, const URL& srcURL);
+ static void registerBlobURLOptionallyFileBacked(const URL&, const URL& srcURL, const String& fileBackedPath, const String& contentType);
+ static void registerBlobURLForSlice(const URL& newURL, const URL& srcURL, long long start, long long end);
static void unregisterBlobURL(const URL&);
+ static unsigned long long blobSize(const URL&);
+
// Returns the origin for the given blob URL. This is because we are not able to embed the unique security origin or the origin of file URL
// in the blob URL.
- static PassRefPtr<SecurityOrigin> getCachedOrigin(const URL&);
+ static RefPtr<SecurityOrigin> getCachedOrigin(const URL&);
};
} // namespace WebCore
-
-#endif // ThreadableBlobRegistry_h
diff --git a/Source/WebCore/fileapi/WebKitBlobBuilder.cpp b/Source/WebCore/fileapi/WebKitBlobBuilder.cpp
deleted file mode 100644
index c47eb1f51..000000000
--- a/Source/WebCore/fileapi/WebKitBlobBuilder.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR 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.
- */
-
-#include "config.h"
-
-#include "WebKitBlobBuilder.h"
-
-#include "Blob.h"
-#include "Document.h"
-#include "ExceptionCode.h"
-#include "File.h"
-#include "HistogramSupport.h"
-#include "LineEnding.h"
-#include "ScriptCallStack.h"
-#include "TextEncoding.h"
-#include <runtime/ArrayBuffer.h>
-#include <runtime/ArrayBufferView.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/Vector.h>
-#include <wtf/text/AtomicString.h>
-#include <wtf/text/CString.h>
-
-namespace WebCore {
-
-// FIXME: Move this file to BlobBuilder.cpp
-
-enum BlobConstructorArrayBufferOrView {
- BlobConstructorArrayBuffer,
- BlobConstructorArrayBufferView,
- BlobConstructorArrayBufferOrViewMax,
-};
-
-BlobBuilder::BlobBuilder()
- : m_size(0)
-{
-}
-
-Vector<char>& BlobBuilder::getBuffer()
-{
- // If the last item is not a data item, create one. Otherwise, we simply append the new string to the last data item.
- if (m_items.isEmpty() || m_items[m_items.size() - 1].type != BlobDataItem::Data)
- m_items.append(BlobDataItem(RawData::create()));
-
- return *m_items[m_items.size() - 1].data->mutableData();
-}
-
-void BlobBuilder::append(const String& text, const String& endingType)
-{
- CString utf8Text = UTF8Encoding().encode(text.deprecatedCharacters(), text.length(), EntitiesForUnencodables);
-
- Vector<char>& buffer = getBuffer();
- size_t oldSize = buffer.size();
-
- if (endingType == "native")
- normalizeLineEndingsToNative(utf8Text, buffer);
- else {
- ASSERT(endingType == "transparent");
- buffer.append(utf8Text.data(), utf8Text.length());
- }
- m_size += buffer.size() - oldSize;
-}
-
-#if ENABLE(BLOB)
-void BlobBuilder::append(ArrayBuffer* arrayBuffer)
-{
- HistogramSupport::histogramEnumeration("WebCore.Blob.constructor.ArrayBufferOrView", BlobConstructorArrayBuffer, BlobConstructorArrayBufferOrViewMax);
-
- if (!arrayBuffer)
- return;
-
- appendBytesData(arrayBuffer->data(), arrayBuffer->byteLength());
-}
-
-void BlobBuilder::append(PassRefPtr<ArrayBufferView> arrayBufferView)
-{
- HistogramSupport::histogramEnumeration("WebCore.Blob.constructor.ArrayBufferOrView", BlobConstructorArrayBufferView, BlobConstructorArrayBufferOrViewMax);
-
- if (!arrayBufferView)
- return;
-
- appendBytesData(arrayBufferView->baseAddress(), arrayBufferView->byteLength());
-}
-#endif
-
-void BlobBuilder::append(Blob* blob)
-{
- if (!blob)
- return;
- if (blob->isFile()) {
- File* file = toFile(blob);
- // If the blob is file that is not snapshoted, capture the snapshot now.
- // FIXME: This involves synchronous file operation. We need to figure out how to make it asynchronous.
- long long snapshotSize;
- double snapshotModificationTime;
- file->captureSnapshot(snapshotSize, snapshotModificationTime);
-
- m_size += snapshotSize;
- m_items.append(BlobDataItem(file->path(), 0, snapshotSize, snapshotModificationTime));
- } else {
- long long blobSize = static_cast<long long>(blob->size());
- m_size += blobSize;
- m_items.append(BlobDataItem(blob->url(), 0, blobSize));
- }
-}
-
-void BlobBuilder::appendBytesData(const void* data, size_t length)
-{
- Vector<char>& buffer = getBuffer();
- size_t oldSize = buffer.size();
- buffer.append(static_cast<const char*>(data), length);
- m_size += buffer.size() - oldSize;
-}
-
-PassRefPtr<Blob> BlobBuilder::getBlob(const String& contentType)
-{
- auto blobData = std::make_unique<BlobData>();
- blobData->setContentType(Blob::normalizedContentType(contentType));
- blobData->swapItems(m_items);
-
- RefPtr<Blob> blob = Blob::create(std::move(blobData), m_size);
-
- // After creating a blob from the current blob data, we do not need to keep the data around any more. Instead, we only
- // need to keep a reference to the URL of the blob just created.
- m_items.append(BlobDataItem(blob->url(), 0, m_size));
-
- return blob;
-}
-
-} // namespace WebCore