[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

jianli at chromium.org jianli at chromium.org
Wed Dec 22 12:49:22 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 42e36c710d9870747c738ba941c6dba87c90b3d1
Author: jianli at chromium.org <jianli at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Tue Aug 31 04:45:21 2010 +0000

    Switch the Blob implementation to using the blob data registration model
    https://bugs.webkit.org/show_bug.cgi?id=44389
    
    Reviewed by Darin Fisher.
    
    WebCore:
    
    Tests: fast/files/read-blob-async.html
           fast/files/read-file-async.html
    
    With this switch, File/Blob/BlobBuilder are changed to register the blob
    data. FileReader is changed to route through loading the blob resource.
    FormData is also updated to take BlobData. The WebKit mac implementation
    is updated to resolve the blob references in the BlobData.
    
    * CMakeLists.txt: Update the project file to remove BlobItem.*.
    * GNUmakefile.am: Update the project file to remove BlobItem.*.
    * WebCore.gypi: Update the project file to remove BlobItem.*.
    * WebCore.pro: Update the project file to remove BlobItem.*.
    * WebCore.vcproj/WebCore.vcproj: Update the project file to remove BlobItem.*.
    * WebCore.xcodeproj/project.pbxproj: Update the project file to remove BlobItem.*.
    * fileapi/Blob.cpp: Switch to using BlobData.
    (WebCore::Blob::Blob):
    (WebCore::Blob::slice):
    * fileapi/Blob.h: Switch to using BlobData.
    (WebCore::Blob::create):
    (WebCore::Blob::size):
    (WebCore::Blob::isFile):
    * fileapi/BlobBuilder.cpp: Switch to using BlobData.
    (WebCore::BlobBuilder::BlobBuilder):
    (WebCore::BlobBuilder::append):
    (WebCore::BlobBuilder::getBlob):
    * fileapi/BlobBuilder.h: Switch to using BlobData.
    * fileapi/BlobURL.cpp: Add a new helper method used in FormData.
    (WebCore::BlobURL::getIdentifier):
    * fileapi/BlobURL.h:
    * fileapi/File.cpp: Switch to using BlobData.
    (WebCore::createBlobDataForFile):
    (WebCore::File::File):
    (WebCore::File::size):
    (WebCore::File::captureSnapshot):
    * fileapi/File.h: Switch to using BlobData.
    (WebCore::File::create):
    (WebCore::File::path):
    (WebCore::File::name):
    (WebCore::File::webkitRelativePath):
    * fileapi/FileReader.cpp: Change the reading to route through blob resource loading.
    (WebCore::FileReader::FileReader):
    (WebCore::FileReader::readAsBinaryString):
    (WebCore::FileReader::readAsText):
    (WebCore::FileReader::readAsDataURL):
    (WebCore::delayedStart):
    (WebCore::FileReader::readInternal):
    (WebCore::FileReader::terminate):
    (WebCore::FileReader::start):
    (WebCore::FileReader::didReceiveResponse):
    (WebCore::FileReader::didReceiveData):
    (WebCore::FileReader::didFinishLoading):
    (WebCore::FileReader::didFail):
    (WebCore::FileReader::failed):
    (WebCore::FileReader::httpStatusCodeToExceptionCode):
    (WebCore::FileReader::result):
    (WebCore::FileReader::convertToDataURL):
    * fileapi/FileReader.h:
    * html/FormDataList.cpp: Account to BlobData change.
    (WebCore::FormDataList::appendString):
    (WebCore::FormDataList::appendBlob):
    * html/FormDataList.h: Account to BlobData change.
    (WebCore::FormDataList::appendBlob):
    (WebCore::FormDataList::Item::Item):
    (WebCore::FormDataList::Item::data):
    (WebCore::FormDataList::Item::blob):
    (WebCore::FormDataList::items):
    * loader/FormSubmission.cpp: Account to BlobData change.
    (WebCore::FormSubmission::create):
    * platform/BlobItem.cpp: Removed.
    * platform/BlobItem.h: Removed.
    * platform/network/BlobRegistryImpl.cpp: Add the implementations for resource loading.
    (WebCore::BlobRegistryImpl::createResourceHandle):
    (WebCore::BlobRegistryImpl::loadResourceSynchronously):
    * platform/network/BlobResourceHandle.cpp: Fix a bug that the ref is not added.
    (WebCore::BlobResourceHandle::BlobResourceHandle):
    * platform/network/FormData.cpp: Account to BlobData change.
    (WebCore::FormData::create):
    (WebCore::FormData::createMultiPart):
    (WebCore::FormData::deepCopy):
    (WebCore::FormData::appendFile):
    (WebCore::FormData::appendKeyValuePairItems):
    * platform/network/FormData.h: Account to BlobData change.
    * platform/network/mac/FormDataStreamMac.mm: Resolve blob references in the form data.
    (WebCore::closeCurrentStream):
    (WebCore::advanceCurrentStream):
    (WebCore::formCreate):
    (WebCore::formRead):
    (WebCore::setHTTPBody):
    * xml/XMLHttpRequest.cpp: Account to BlobData change.
    (WebCore::XMLHttpRequest::send):
    
    WebKit/chromium:
    
    * src/WebSearchableFormData.cpp:
    (WebCore::HasSuitableTextElement):
    
    LayoutTests:
    
    Add a new test and change an existing test. Both tests are written in
    better organized utility files and modules.
    
    * fast/files/file-reader-expected.txt: Removed.
    * fast/files/file-reader.html: Removed.
    * fast/files/read-blob-async-expected.txt: Added.
    * fast/files/read-blob-async.html: Added.
    * fast/files/read-file-async-expected.txt: Added.
    * fast/files/read-file-async.html: Added.
    * fast/files/resources/UTF8-2.txt: Added.
    * fast/files/resources/UTF8-3.txt: Added.
    * fast/files/resources/read-blob-test-cases.js: Added.
    * fast/files/resources/read-common.js: Added.
    * fast/files/resources/read-file-test-cases.js: Added.
    * fast/files/resources/setup-for-read-common.js: Added.
    * platform/gtk/Skipped: Account to the test changes for gtk.
    * platform/mac-wk2/Skipped: Account to the test changes for mac-wk2.
    * platform/qt/Skipped: Account to the test changes for qt.
    * platform/win/Skipped: Account to the test changes for win.
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@66452 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 6602e71..7002ebb 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,30 @@
+2010-08-30  Jian Li  <jianli at chromium.org>
+
+        Reviewed by Darin Fisher.
+
+        Switch the Blob implementation to using the blob data registration model
+        https://bugs.webkit.org/show_bug.cgi?id=44389
+
+        Add a new test and change an existing test. Both tests are written in
+        better organized utility files and modules.
+
+        * fast/files/file-reader-expected.txt: Removed.
+        * fast/files/file-reader.html: Removed.
+        * fast/files/read-blob-async-expected.txt: Added.
+        * fast/files/read-blob-async.html: Added.
+        * fast/files/read-file-async-expected.txt: Added.
+        * fast/files/read-file-async.html: Added.
+        * fast/files/resources/UTF8-2.txt: Added.
+        * fast/files/resources/UTF8-3.txt: Added.
+        * fast/files/resources/read-blob-test-cases.js: Added.
+        * fast/files/resources/read-common.js: Added.
+        * fast/files/resources/read-file-test-cases.js: Added.
+        * fast/files/resources/setup-for-read-common.js: Added.
+        * platform/gtk/Skipped: Account to the test changes for gtk.
+        * platform/mac-wk2/Skipped: Account to the test changes for mac-wk2.
+        * platform/qt/Skipped: Account to the test changes for qt.
+        * platform/win/Skipped: Account to the test changes for win.
+
 2010-08-30  Eric Seidel  <eric at webkit.org>
 
         Unreviewed, rolling out r66418.
diff --git a/LayoutTests/fast/files/file-reader-expected.txt b/LayoutTests/fast/files/file-reader-expected.txt
deleted file mode 100644
index dae90b5..0000000
--- a/LayoutTests/fast/files/file-reader-expected.txt
+++ /dev/null
@@ -1,135 +0,0 @@
-
-Test reading a non-existent file
-readyState: 0
-Received error event
-readyState: 2
-error code: 8
-Received loadend event
-Test reading an empty file as binary string
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 0
-result: 
-Received loadend event
-Test reading an empty file as text
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 0
-result: 
-Received loadend event
-Test reading an empty file as data URL
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 5
-result: data:
-Received loadend event
-Test reading a UTF-8 file as binary string
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 5
-result: Hello
-Received loadend event
-Test reading a binary file as binary string
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 9
-result: 0x0 0x1 0x2 0x80 0x81 0x82 0xfd 0xfe 0xff
-Received loadend event
-Test reading a UTF-8 file as text
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 5
-result: Hello
-Received loadend event
-Test reading a UTF-16BE BOM file as text
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 5
-result: Hello
-Received loadend event
-Test reading a UTF-16LE BOM file as text
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 5
-result: Hello
-Received loadend event
-Test reading a UTF-8 BOM file as text
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 5
-result: Hello
-Received loadend event
-Test reading a UTF-16BE file as text with UTF-16BE encoding
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 5
-result: Hello
-Received loadend event
-Test reading a UTF-16BE BOM file as text with UTF8 encoding
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 5
-result: Hello
-Received loadend event
-Test reading a UTF-16BE BOM file as text with invalid encoding
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 5
-result: Hello
-Received loadend event
-Test reading a UTF-8 file as data URL
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 31
-result: data:text/plain;base64,SGVsbG8=
-Received loadend event
-Test calling multiple read methods and only last one is processed
-readyState: 0
-Received loadstart event
-readyState: 1
-Received load event
-readyState: 2
-result size: 31
-result: data:text/plain;base64,SGVsbG8=
-Received loadend event
-DONE
-
diff --git a/LayoutTests/fast/files/file-reader.html b/LayoutTests/fast/files/file-reader.html
deleted file mode 100644
index 7babbb1..0000000
--- a/LayoutTests/fast/files/file-reader.html
+++ /dev/null
@@ -1,257 +0,0 @@
-<!DOCTYPE html>
-<html>
-<body>
-<input type="file" name="file" id="file" onchange="onInputFileChange()" multiple>
-<pre id='console'></pre>
-
-<script>
-var testCases = [
-    "testReadingNonExistentFile",
-    "testReadingEmptyFileAsBinaryString",
-    "testReadingEmptyFileAsText",
-    "testReadingEmptyFileAsDataURL",
-    "testReadingUTF8EncodedFileAsBinaryString",
-    "testReadingBinaryFileAsBinaryString",
-    "testReadingUTF8EncodedFileAsText",
-    "testReadingUTF16BEBOMEncodedFileAsText",
-    "testReadingUTF16LEBOMEncodedFileAsText",
-    "testReadingUTF8BOMEncodedFileAsText",
-    "testReadingUTF16BEEncodedFileAsTextWithUTF16Encoding",
-    "testReadingUTF16BEBOMEncodedFileAsTextWithUTF8Encoding",
-    "testReadingUTF16BEBOMEncodedFileAsTextWithInvalidEncoding",
-    "testReadingUTF8EncodedFileAsDataURL",
-    "testMultipleReads",
-];
-var testIndex = 0;
-
-var testFileInfoList = [
-    { 'name': 'non-existent', 'path': 'resources/non-existent' },
-    { 'name': 'empty-file', 'path': 'resources/empty-file' },
-    { 'name': 'UTF8-file', 'path': 'resources/UTF8.txt' },
-    { 'name': 'UTF16BE-BOM-file', 'path': 'resources/UTF16BE-BOM.txt' },
-    { 'name': 'UTF16LE-BOM-file', 'path': 'resources/UTF16LE-BOM.txt' },
-    { 'name': 'UTF8-BOM-file', 'path': 'resources/UTF8-BOM.txt' },
-    { 'name': 'UTF16BE-file', 'path': 'resources/UTF16BE.txt' },
-    { 'name': 'binary-file', 'path': 'resources/binary-file' },
-];
-var testFiles = { };
-
-function log(message)
-{
-    document.getElementById('console').appendChild(document.createTextNode(message + "\n"));
-}
-
-function isASCIIString(str)
-{
-    for (var i = 0; i < str.length; ++i) {
-        if (str.charCodeAt(i) >= 128)
-            return false;
-    }
-    return true;
-}
-
-function toHexadecimal(str)
-{
-    var result = "";
-    for (var i = 0; i < str.length; ++i) {
-        var hex = "0x" + (str.charCodeAt(i) & 0xFF).toString(16);
-        if (i > 0)
-            result += " ";
-        result += hex;
-    }
-    return result;
-}
-
-function createFileReader()
-{
-    var reader = new FileReader();
-
-    reader.onloadstart = loadStarted;
-    reader.onload = loaded;
-    reader.onabort = logEvent;
-    reader.onloadend = loadEnded;
-    reader.onerror = loadFailed;
-
-    log("readyState: " + reader.readyState);
-    return reader;
-}
-
-function logEvent(event)
-{
-    log("Received " + event.type + " event");
-}
-
-function loadStarted(event)
-{
-    logEvent(event);
-    log("readyState: " + event.target.readyState);
-}
-
-function loaded(event)
-{
-    logEvent(event);
-    log("readyState: " + event.target.readyState);
-    log("result size: " + event.target.result.length);
-
-    var result = event.target.result;
-    var resultOutput = isASCIIString(result) ? result : toHexadecimal(result);
-    log("result: " + resultOutput);
-}
-
-function loadFailed(event)
-{
-    logEvent(event);
-    log("readyState: " + event.target.readyState);
-    log("error code: " + event.target.error.code);
-}
-
-function loadEnded(event)
-{
-    logEvent(event);
-    runNextTest();
-}
-
-function onInputFileChange()
-{
-    var files = document.getElementById("file").files;
-    for (var i = 0; i < files.length; i++)
-        testFiles[testFileInfoList[i]['name']] = files[i];
-
-    runNextTest();
-}
-
-function runNextTest()
-{
-    if (testIndex < testCases.length) {
-        testIndex++;
-        window[testCases[testIndex - 1]]();
-    } else {
-        log("DONE");
-        if (window.layoutTestController)
-            layoutTestController.notifyDone();
-    }
-}
-
-function testReadingNonExistentFile()
-{
-    log("Test reading a non-existent file");
-    var reader = createFileReader();
-    reader.readAsBinaryString(testFiles['non-existent']);
-}
-
-function testReadingEmptyFileAsBinaryString()
-{
-    log("Test reading an empty file as binary string");
-    var reader = createFileReader();
-    reader.readAsBinaryString(testFiles['empty-file']);
-}
-
-function testReadingEmptyFileAsText()
-{
-    log("Test reading an empty file as text");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['empty-file']);
-}
-
-function testReadingEmptyFileAsDataURL()
-{
-    log("Test reading an empty file as data URL");
-    var reader = createFileReader();
-    reader.readAsDataURL(testFiles['empty-file']);
-}
-
-function testReadingUTF8EncodedFileAsBinaryString()
-{
-    log("Test reading a UTF-8 file as binary string");
-    var reader = createFileReader();
-    reader.readAsBinaryString(testFiles['UTF8-file']);
-}
-
-function testReadingBinaryFileAsBinaryString()
-{
-    log("Test reading a binary file as binary string");
-    var reader = createFileReader();
-    reader.readAsBinaryString(testFiles['binary-file']);
-}
-
-function testReadingUTF8EncodedFileAsText()
-{
-    log("Test reading a UTF-8 file as text");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF8-file']);
-}
-
-function testReadingUTF16BEBOMEncodedFileAsText()
-{
-    log("Test reading a UTF-16BE BOM file as text");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF16BE-BOM-file']);
-}
-
-function testReadingUTF16LEBOMEncodedFileAsText()
-{
-    log("Test reading a UTF-16LE BOM file as text");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF16LE-BOM-file']);
-}
-
-function testReadingUTF8BOMEncodedFileAsText()
-{
-    log("Test reading a UTF-8 BOM file as text");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF8-BOM-file']);
-}
-
-function testReadingUTF16BEEncodedFileAsTextWithUTF16Encoding()
-{
-    log("Test reading a UTF-16BE file as text with UTF-16BE encoding");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF16BE-file'], "UTF-16BE");
-}
-
-function testReadingUTF16BEBOMEncodedFileAsTextWithUTF8Encoding()
-{
-    log("Test reading a UTF-16BE BOM file as text with UTF8 encoding");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF16BE-BOM-file'], "UTF-8");
-}
-
-function testReadingUTF16BEBOMEncodedFileAsTextWithInvalidEncoding()
-{
-    log("Test reading a UTF-16BE BOM file as text with invalid encoding");
-    var reader = createFileReader();
-    reader.readAsText(testFiles['UTF16BE-BOM-file'], "AnyInvalidEncoding");
-}
-
-function testReadingUTF8EncodedFileAsDataURL()
-{
-    log("Test reading a UTF-8 file as data URL");
-    var reader = createFileReader();
-    reader.readAsDataURL(testFiles['UTF8-file']);
-}
-
-function testMultipleReads()
-{
-    log("Test calling multiple read methods and only last one is processed");
-    var reader = createFileReader();
-    reader.readAsBinaryString(testFiles['UTF8-file']);
-    reader.readAsText(testFiles['UTF8-file']);
-    reader.readAsDataURL(testFiles['UTF8-file']);
-}
-
-function runTests()
-{
-    var pathsOnly = testFileInfoList.map(function(fileSpec) { return fileSpec['path']; });
-    eventSender.beginDragWithFiles(pathsOnly);
-    eventSender.mouseMoveTo(10, 10);
-    eventSender.mouseUp();
-}
-
-if (window.eventSender) {
-    layoutTestController.dumpAsText();
-    layoutTestController.waitUntilDone();
-    window.onload = runTests;
-}
-</script>
-</body>
-</html>
diff --git a/LayoutTests/fast/files/read-blob-async-expected.txt b/LayoutTests/fast/files/read-blob-async-expected.txt
new file mode 100644
index 0000000..0c10d5d
--- /dev/null
+++ b/LayoutTests/fast/files/read-blob-async-expected.txt
@@ -0,0 +1,123 @@
+
+Test reading a blob containing non-existent file
+readyState: 0
+Received error event
+readyState: 2
+error code: 8
+Received loadend event
+Test reading a blob containing existent and non-existent file
+readyState: 0
+Received error event
+readyState: 2
+error code: 8
+Received loadend event
+Test reading a blob containing empty file
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 0
+result: 
+Received loadend event
+Test reading a blob containing empty text
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 0
+result: 
+Received loadend event
+Test reading a blob containing empty files and empty texts
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 0
+result: 
+Received loadend event
+Test reading a blob containing single file
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: Hello
+Received loadend event
+Test reading a blob containing single text
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: First
+Received loadend event
+Test reading a blob containing sliced file
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: onder
+Received loadend event
+Test reading a blob containing sliced text
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 4
+result: irst
+Received loadend event
+Test reading a blob containing multiple files
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 19
+result: HelloWonderfulWorld
+Received loadend event
+Test reading a blob containing multiple texts
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 16
+result: FirstSecondThird
+Received loadend event
+Test reading a hybrid blob
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 35
+result: FirstHelloSecondWonderfulWorldThird
+Received loadend event
+Test reading a sliced hybrid blob
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 12
+result: lloSecondWon
+Received loadend event
+Test reading a triple-sliced hybrid blob
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 30
+result: ondWonderfulWorldThirdFooloSec
+Received loadend event
+DONE
+
diff --git a/LayoutTests/fast/files/read-blob-async.html b/LayoutTests/fast/files/read-blob-async.html
new file mode 100644
index 0000000..8070123
--- /dev/null
+++ b/LayoutTests/fast/files/read-blob-async.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<body>
+<input type="file" name="file" id="file" onchange="onInputFileChange(testFileInfoList)" multiple>
+<pre id='console'></pre>
+
+<script src="resources/setup-for-read-common.js"></script>
+<script src="resources/read-common.js"></script>
+<script src="resources/read-blob-test-cases.js"></script>
+<script>
+var testFileInfoList = [
+    { 'name': 'non-existent', 'path': 'resources/non-existent' },
+    { 'name': 'empty-file', 'path': 'resources/empty-file' },
+    { 'name': 'file1', 'path': 'resources/UTF8.txt' },
+    { 'name': 'file2', 'path': 'resources/UTF8-2.txt' },
+    { 'name': 'file3', 'path': 'resources/UTF8-3.txt' },
+];
+
+function startTest(testFiles)
+{
+    runNextTest(testFiles);
+}
+
+if (window.eventSender) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+    window.onload = function() { runTests(testFileInfoList); }
+}
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/files/read-file-async-expected.txt b/LayoutTests/fast/files/read-file-async-expected.txt
new file mode 100644
index 0000000..76fd55f
--- /dev/null
+++ b/LayoutTests/fast/files/read-file-async-expected.txt
@@ -0,0 +1,147 @@
+
+Test reading a non-existent file as binary string
+readyState: 0
+Received error event
+readyState: 2
+error code: 8
+Received loadend event
+Test reading a non-existent file as text
+readyState: 0
+Received error event
+readyState: 2
+error code: 8
+Received loadend event
+Test reading a non-existent file as data URL
+readyState: 0
+Received error event
+readyState: 2
+error code: 8
+Received loadend event
+Test reading an empty file as binary string
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 0
+result: 
+Received loadend event
+Test reading an empty file as text
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 0
+result: 
+Received loadend event
+Test reading an empty file as data URL
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: data:
+Received loadend event
+Test reading a UTF-8 file as binary string
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: Hello
+Received loadend event
+Test reading a binary file as binary string
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 9
+result: 0x0 0x1 0x2 0x80 0x81 0x82 0xfd 0xfe 0xff
+Received loadend event
+Test reading a UTF-8 file as text
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: Hello
+Received loadend event
+Test reading a UTF-16BE BOM file as text
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: Hello
+Received loadend event
+Test reading a UTF-16LE BOM file as text
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: Hello
+Received loadend event
+Test reading a UTF-8 BOM file as text
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: Hello
+Received loadend event
+Test reading a UTF-16BE file as text with UTF-16BE encoding
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: Hello
+Received loadend event
+Test reading a UTF-16BE BOM file as text with UTF8 encoding
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: Hello
+Received loadend event
+Test reading a UTF-16BE BOM file as text with invalid encoding
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 5
+result: Hello
+Received loadend event
+Test reading a UTF-8 file as data URL
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 31
+result: data:text/plain;base64,SGVsbG8=
+Received loadend event
+Test calling multiple read methods and only last one is processed
+readyState: 0
+Received loadstart event
+readyState: 1
+Received load event
+readyState: 2
+result size: 31
+result: data:text/plain;base64,SGVsbG8=
+Received loadend event
+DONE
+
diff --git a/LayoutTests/fast/files/read-file-async.html b/LayoutTests/fast/files/read-file-async.html
new file mode 100644
index 0000000..c614dfd
--- /dev/null
+++ b/LayoutTests/fast/files/read-file-async.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<body>
+<input type="file" name="file" id="file" onchange="onInputFileChange(testFileInfoList)" multiple>
+<pre id='console'></pre>
+
+<script src="resources/setup-for-read-common.js"></script>
+<script src="resources/read-common.js"></script>
+<script src="resources/read-file-test-cases.js"></script>
+<script>
+var testFileInfoList = [
+    { 'name': 'non-existent', 'path': 'resources/non-existent' },
+    { 'name': 'empty-file', 'path': 'resources/empty-file' },
+    { 'name': 'UTF8-file', 'path': 'resources/UTF8.txt' },
+    { 'name': 'UTF16BE-BOM-file', 'path': 'resources/UTF16BE-BOM.txt' },
+    { 'name': 'UTF16LE-BOM-file', 'path': 'resources/UTF16LE-BOM.txt' },
+    { 'name': 'UTF8-BOM-file', 'path': 'resources/UTF8-BOM.txt' },
+    { 'name': 'UTF16BE-file', 'path': 'resources/UTF16BE.txt' },
+    { 'name': 'binary-file', 'path': 'resources/binary-file' },
+];
+
+function startTest(testFiles)
+{
+    runNextTest(testFiles);
+}
+
+if (window.eventSender) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+    window.onload = function() { runTests(testFileInfoList); }
+}
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/files/resources/UTF8-2.txt b/LayoutTests/fast/files/resources/UTF8-2.txt
new file mode 100644
index 0000000..1601e9f
--- /dev/null
+++ b/LayoutTests/fast/files/resources/UTF8-2.txt
@@ -0,0 +1 @@
+Wonderful
\ No newline at end of file
diff --git a/LayoutTests/fast/files/resources/UTF8-3.txt b/LayoutTests/fast/files/resources/UTF8-3.txt
new file mode 100644
index 0000000..beef906
--- /dev/null
+++ b/LayoutTests/fast/files/resources/UTF8-3.txt
@@ -0,0 +1 @@
+World
\ No newline at end of file
diff --git a/LayoutTests/fast/files/resources/read-blob-test-cases.js b/LayoutTests/fast/files/resources/read-blob-test-cases.js
new file mode 100644
index 0000000..c14fa4e
--- /dev/null
+++ b/LayoutTests/fast/files/resources/read-blob-test-cases.js
@@ -0,0 +1,134 @@
+var testCases = [
+    "testReadingNonExistentFileBlob",
+    "testReadingNonExistentFileBlob2",
+    "testReadingEmptyFileBlob",
+    "testReadingEmptyTextBlob",
+    "testReadingEmptyFileAndTextBlob",
+    "testReadingSingleFileBlob",
+    "testReadingSingleTextBlob",
+    "testReadingSlicedFileBlob",
+    "testReadingSlicedTextBlob",
+    "testReadingMultipleFileBlob",
+    "testReadingMultipleTextBlob",
+    "testReadingHybridBlob",
+    "testReadingSlicedHybridBlob",
+    "testReadingTripleSlicedHybridBlob",
+];
+var testIndex = 0;
+
+function runNextTest(testFiles)
+{
+    if (testIndex < testCases.length) {
+        testIndex++;
+        self[testCases[testIndex - 1]](testFiles);
+    } else {
+        log("DONE");
+        if (window && window.layoutTestController)
+            layoutTestController.notifyDone();
+    }
+}
+
+function testReadingNonExistentFileBlob(testFiles)
+{
+    log("Test reading a blob containing non-existent file");
+    var blob = buildBlob([testFiles['non-existent']]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingNonExistentFileBlob2(testFiles)
+{
+    log("Test reading a blob containing existent and non-existent file");
+    var blob = buildBlob([testFiles['file1'], testFiles['non-existent'], testFiles['empty-file']]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingEmptyFileBlob(testFiles)
+{
+    log("Test reading a blob containing empty file");
+    var blob = buildBlob([testFiles['empty-file']]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingEmptyTextBlob(testFiles)
+{
+    log("Test reading a blob containing empty text");
+    var blob = buildBlob(['']);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingEmptyFileAndTextBlob(testFiles)
+{
+    log("Test reading a blob containing empty files and empty texts");
+    var blob = buildBlob(['', testFiles['empty-file'], '', testFiles['empty-file']]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingSingleFileBlob(testFiles)
+{
+    log("Test reading a blob containing single file");
+    var blob = buildBlob([testFiles['file1']]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingSingleTextBlob(testFiles)
+{
+    log("Test reading a blob containing single text");
+    var blob = buildBlob(['First']);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingSlicedFileBlob(testFiles)
+{
+    log("Test reading a blob containing sliced file");
+    var blob = buildBlob([testFiles['file2'].slice(1, 5)]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingSlicedTextBlob(testFiles)
+{
+    log("Test reading a blob containing sliced text");
+    var blob = buildBlob(['First'])
+    blob = blob.slice(1, 10);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingMultipleFileBlob(testFiles)
+{
+    log("Test reading a blob containing multiple files");
+    var blob = buildBlob([testFiles['file1'], testFiles['file2'], testFiles['file3']]);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingMultipleTextBlob(testFiles)
+{
+    log("Test reading a blob containing multiple texts");
+    var blob = buildBlob(['First', 'Second', 'Third']);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingHybridBlob(testFiles)
+{
+    log("Test reading a hybrid blob");
+    var blob = buildBlob(['First', testFiles['file1'], 'Second', testFiles['file2'], testFiles['file3'], 'Third']);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingSlicedHybridBlob(testFiles)
+{
+    log("Test reading a sliced hybrid blob");
+    var blob = buildBlob(['First', testFiles['file1'], 'Second', testFiles['file2'], testFiles['file3'], 'Third']);
+    var blob = blob.slice(7, 12);
+    readBlobAsBinaryString(testFiles, blob);
+}
+
+function testReadingTripleSlicedHybridBlob(testFiles)
+{
+    log("Test reading a triple-sliced hybrid blob");
+    var builder = new BlobBuilder();
+    var blob = buildBlob(['First', testFiles['file1'].slice(1, 10), testFiles['empty-file'], 'Second', testFiles['file2'], testFiles['file3'], 'Third'], builder);
+    var blob = blob.slice(7, 12);
+    var blob2 = buildBlob(['Foo', blob, 'Bar'], builder);
+    var blob2 = blob2.slice(12, 30);
+    readBlobAsBinaryString(testFiles, blob2);
+}
+
diff --git a/LayoutTests/fast/files/resources/read-common.js b/LayoutTests/fast/files/resources/read-common.js
new file mode 100644
index 0000000..e5d27f3
--- /dev/null
+++ b/LayoutTests/fast/files/resources/read-common.js
@@ -0,0 +1,99 @@
+// Builds a blob from a list of items.
+// If the 'builder' argument is not provided, create a new one.
+function buildBlob(items, builder)
+{
+    if (builder === undefined)
+        builder = new BlobBuilder();
+    for (var i = 0; i < items.length; i++)
+        builder.append(items[i]);
+    return builder.getBlob();
+}
+
+function readBlobAsBinaryString(testFiles, blob)
+{
+    var reader = createReader(testFiles);
+    reader.readAsBinaryString(blob)
+}
+
+function readBlobAsText(testFiles, blob, encoding)
+{
+    var reader = createReader(testFiles);
+    reader.readAsText(blob, encoding)
+}
+
+function readBlobAsDataURL(testFiles, blob)
+{
+    var reader = createReader(testFiles);
+    reader.readAsDataURL(blob)
+}
+
+function createReader(testFiles)
+{
+    var reader = new FileReader();
+
+    reader.onloadstart = loadStarted;
+    reader.onload = loaded;
+    reader.onabort = logEvent;
+    reader.onloadend = function(event) { loadEnded(testFiles, event); }
+    reader.onerror = loadFailed;
+
+    log("readyState: " + reader.readyState);
+    return reader;
+}
+
+function logEvent(event)
+{
+    log("Received " + event.type + " event");
+}
+
+function loadStarted(event)
+{
+    logEvent(event);
+    log("readyState: " + event.target.readyState);
+}
+
+function loaded(event)
+{
+    logEvent(event);
+    log("readyState: " + event.target.readyState);
+    log("result size: " + event.target.result.length);
+
+    var result = event.target.result;
+    var resultOutput = _isASCIIString(result) ? result : _toHexadecimal(result);
+    log("result: " + resultOutput);
+}
+
+function loadFailed(event)
+{
+    logEvent(event);
+    log("readyState: " + event.target.readyState);
+    log("error code: " + event.target.error.code);
+}
+
+function loadEnded(testFiles, event)
+{
+    logEvent(event);
+    runNextTest(testFiles);
+}
+
+// Helper functions.
+function _isASCIIString(str)
+{
+    for (var i = 0; i < str.length; ++i) {
+        if (str.charCodeAt(i) >= 128)
+            return false;
+    }
+    return true;
+}
+
+function _toHexadecimal(str)
+{
+    var result = "";
+    for (var i = 0; i < str.length; ++i) {
+        var hex = "0x" + (str.charCodeAt(i) & 0xFF).toString(16);
+        if (i > 0)
+            result += " ";
+        result += hex;
+    }
+    return result;
+}
diff --git a/LayoutTests/fast/files/resources/read-file-test-cases.js b/LayoutTests/fast/files/resources/read-file-test-cases.js
new file mode 100644
index 0000000..519db41
--- /dev/null
+++ b/LayoutTests/fast/files/resources/read-file-test-cases.js
@@ -0,0 +1,137 @@
+var testCases = [
+    "testReadingNonExistentFileAsBinaryString",
+    "testReadingNonExistentFileAsText",
+    "testReadingNonExistentFileAsDataURL",
+    "testReadingEmptyFileAsBinaryString",
+    "testReadingEmptyFileAsText",
+    "testReadingEmptyFileAsDataURL",
+    "testReadingUTF8EncodedFileAsBinaryString",
+    "testReadingBinaryFileAsBinaryString",
+    "testReadingUTF8EncodedFileAsText",
+    "testReadingUTF16BEBOMEncodedFileAsText",
+    "testReadingUTF16LEBOMEncodedFileAsText",
+    "testReadingUTF8BOMEncodedFileAsText",
+    "testReadingUTF16BEEncodedFileAsTextWithUTF16Encoding",
+    "testReadingUTF16BEBOMEncodedFileAsTextWithUTF8Encoding",
+    "testReadingUTF16BEBOMEncodedFileAsTextWithInvalidEncoding",
+    "testReadingUTF8EncodedFileAsDataURL",
+    "testMultipleReads",
+];
+var testIndex = 0;
+
+function runNextTest(testFiles)
+{
+    if (testIndex < testCases.length) {
+        testIndex++;
+        self[testCases[testIndex - 1]](testFiles);
+    } else {
+        log("DONE");
+        if (window && window.layoutTestController)
+            layoutTestController.notifyDone();
+    }
+}
+
+function testReadingNonExistentFileAsBinaryString(testFiles)
+{
+    log("Test reading a non-existent file as binary string");
+    readBlobAsBinaryString(testFiles, testFiles['non-existent']);
+}
+
+function testReadingNonExistentFileAsText(testFiles)
+{
+    log("Test reading a non-existent file as text");
+    readBlobAsText(testFiles, testFiles['non-existent']);
+}
+
+function testReadingNonExistentFileAsDataURL(testFiles)
+{
+    log("Test reading a non-existent file as data URL");
+    readBlobAsDataURL(testFiles, testFiles['non-existent']);
+}
+
+function testReadingEmptyFileAsBinaryString(testFiles)
+{
+    log("Test reading an empty file as binary string");
+    readBlobAsBinaryString(testFiles, testFiles['empty-file']);
+}
+
+function testReadingEmptyFileAsText(testFiles)
+{
+    log("Test reading an empty file as text");
+    readBlobAsText(testFiles, testFiles['empty-file']);
+}
+
+function testReadingEmptyFileAsDataURL(testFiles)
+{
+    log("Test reading an empty file as data URL");
+    readBlobAsDataURL(testFiles, testFiles['empty-file']);
+}
+
+function testReadingUTF8EncodedFileAsBinaryString(testFiles)
+{
+    log("Test reading a UTF-8 file as binary string");
+    readBlobAsBinaryString(testFiles, testFiles['UTF8-file']);
+}
+
+function testReadingBinaryFileAsBinaryString(testFiles)
+{
+    log("Test reading a binary file as binary string");
+    readBlobAsBinaryString(testFiles, testFiles['binary-file']);
+}
+
+function testReadingUTF8EncodedFileAsText(testFiles)
+{
+    log("Test reading a UTF-8 file as text");
+    readBlobAsText(testFiles, testFiles['UTF8-file']);
+}
+
+function testReadingUTF16BEBOMEncodedFileAsText(testFiles)
+{
+    log("Test reading a UTF-16BE BOM file as text");
+    readBlobAsText(testFiles, testFiles['UTF16BE-BOM-file']);
+}
+
+function testReadingUTF16LEBOMEncodedFileAsText(testFiles)
+{
+    log("Test reading a UTF-16LE BOM file as text");
+    readBlobAsText(testFiles, testFiles['UTF16LE-BOM-file']);
+}
+
+function testReadingUTF8BOMEncodedFileAsText(testFiles)
+{
+    log("Test reading a UTF-8 BOM file as text");
+    readBlobAsText(testFiles, testFiles['UTF8-BOM-file']);
+}
+
+function testReadingUTF16BEEncodedFileAsTextWithUTF16Encoding(testFiles)
+{
+    log("Test reading a UTF-16BE file as text with UTF-16BE encoding");
+    readBlobAsText(testFiles, testFiles['UTF16BE-file'], "UTF-16BE");
+}
+
+function testReadingUTF16BEBOMEncodedFileAsTextWithUTF8Encoding(testFiles)
+{
+    log("Test reading a UTF-16BE BOM file as text with UTF8 encoding");
+    readBlobAsText(testFiles, testFiles['UTF16BE-BOM-file'], "UTF-8");
+}
+
+function testReadingUTF16BEBOMEncodedFileAsTextWithInvalidEncoding(testFiles)
+{
+    log("Test reading a UTF-16BE BOM file as text with invalid encoding");
+    readBlobAsText(testFiles, testFiles['UTF16BE-BOM-file'], "AnyInvalidEncoding");
+}
+
+function testReadingUTF8EncodedFileAsDataURL(testFiles)
+{
+    log("Test reading a UTF-8 file as data URL");
+    readBlobAsDataURL(testFiles, testFiles['UTF8-file']);
+}
+
+function testMultipleReads(testFiles)
+{
+    log("Test calling multiple read methods and only last one is processed");
+    var reader = createReader();
+    reader.readAsBinaryString(testFiles['UTF8-file']);
+    reader.readAsText(testFiles['UTF8-file']);
+    reader.readAsDataURL(testFiles['UTF8-file']);
+}
diff --git a/LayoutTests/fast/files/resources/setup-for-read-common.js b/LayoutTests/fast/files/resources/setup-for-read-common.js
new file mode 100644
index 0000000..6398a7c
--- /dev/null
+++ b/LayoutTests/fast/files/resources/setup-for-read-common.js
@@ -0,0 +1,22 @@
+function log(message)
+{
+    document.getElementById('console').appendChild(document.createTextNode(message + "\n"));
+}
+
+function onInputFileChange(testFileInfoList)
+{
+    var files = document.getElementById("file").files;
+    var testFiles = { };
+    for (var i = 0; i < files.length; i++)
+        testFiles[testFileInfoList[i]['name']] = files[i];
+
+    startTest(testFiles);
+}
+
+function runTests(testFileInfoList)
+{
+    var pathsOnly = testFileInfoList.map(function(fileSpec) { return fileSpec['path']; });
+    eventSender.beginDragWithFiles(pathsOnly);
+    eventSender.mouseMoveTo(10, 10);
+    eventSender.mouseUp();
+}
diff --git a/LayoutTests/platform/gtk/Skipped b/LayoutTests/platform/gtk/Skipped
index c0b2a58..f25dddc 100644
--- a/LayoutTests/platform/gtk/Skipped
+++ b/LayoutTests/platform/gtk/Skipped
@@ -3146,7 +3146,8 @@ http/tests/local/blob/send-sliced-data-blob.html
 http/tests/local/formdata/send-form-data.html
 http/tests/local/formdata/send-form-data-with-sliced-file.html
 http/tests/local/formdata/upload-events.html
-fast/files/file-reader.html
+fast/files/read-blob-async.html
+fast/files/read-file-async.html
 http/tests/media/video-play-stall-seek.html
 http/tests/media/video-play-stall.html
 http/tests/media/video-seekable-stall.html
diff --git a/LayoutTests/platform/mac-wk2/Skipped b/LayoutTests/platform/mac-wk2/Skipped
index 00c5958..732b33a 100644
--- a/LayoutTests/platform/mac-wk2/Skipped
+++ b/LayoutTests/platform/mac-wk2/Skipped
@@ -364,7 +364,8 @@ fast/events/window-events-bubble.html
 fast/events/window-events-bubble2.html
 fast/events/window-events-capture.html
 fast/events/zoom-dblclick.html
-fast/files/file-reader.html
+fast/files/read-blob-async.html
+fast/files/read-file-async.html
 fast/forms/25153.html
 fast/forms/access-key.html
 fast/forms/button-enter-click.html
diff --git a/LayoutTests/platform/qt/Skipped b/LayoutTests/platform/qt/Skipped
index 85a351e..c058372 100644
--- a/LayoutTests/platform/qt/Skipped
+++ b/LayoutTests/platform/qt/Skipped
@@ -781,7 +781,8 @@ http/tests/security/isolatedWorld/world-reuse.html
 
 # Missing eventSender.beginDragWithFiles()
 fast/dom/Window/window-postmessage-clone-frames.html
-fast/files/file-reader.html
+fast/files/read-blob-async.html
+fast/files/read-file-async.html
 
 # Missing layoutTestController.setAlwaysAcceptCookies()
 http/tests/plugins/third-party-cookie-accept-policy.html
diff --git a/LayoutTests/platform/win/Skipped b/LayoutTests/platform/win/Skipped
index 4d70004..da9a748 100644
--- a/LayoutTests/platform/win/Skipped
+++ b/LayoutTests/platform/win/Skipped
@@ -195,7 +195,8 @@ fast/forms/input-file-re-render.html
 http/tests/security/clipboard/clipboard-file-access.html
 fast/events/drag-file-crash.html
 fast/dom/Window/window-postmessage-clone.html
-fast/files/file-reader.html
+fast/files/read-blob-async.html
+fast/files/read-file-async.html
 
 # Need to add functionality to DumpRenderTree to test IDN <rdar://problem/5301954>
 fast/encoding/idn-security.html
diff --git a/WebCore/CMakeLists.txt b/WebCore/CMakeLists.txt
index b8b8b8e..3995ebd 100644
--- a/WebCore/CMakeLists.txt
+++ b/WebCore/CMakeLists.txt
@@ -1219,7 +1219,6 @@ SET(WebCore_SOURCES
 
     platform/Arena.cpp
     platform/AsyncFileSystem.cpp
-    platform/BlobItem.cpp
     platform/ContentType.cpp
     platform/ContextMenu.cpp
     platform/CrossThreadCopier.cpp
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index e874cd3..14c760a 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,101 @@
+2010-08-30  Jian Li  <jianli at chromium.org>
+
+        Reviewed by Darin Fisher.
+
+        Switch the Blob implementation to using the blob data registration model
+        https://bugs.webkit.org/show_bug.cgi?id=44389
+
+        Tests: fast/files/read-blob-async.html
+               fast/files/read-file-async.html
+
+        With this switch, File/Blob/BlobBuilder are changed to register the blob
+        data. FileReader is changed to route through loading the blob resource.
+        FormData is also updated to take BlobData. The WebKit mac implementation
+        is updated to resolve the blob references in the BlobData.
+
+        * CMakeLists.txt: Update the project file to remove BlobItem.*.
+        * GNUmakefile.am: Update the project file to remove BlobItem.*.
+        * WebCore.gypi: Update the project file to remove BlobItem.*.
+        * WebCore.pro: Update the project file to remove BlobItem.*.
+        * WebCore.vcproj/WebCore.vcproj: Update the project file to remove BlobItem.*.
+        * WebCore.xcodeproj/project.pbxproj: Update the project file to remove BlobItem.*.
+        * fileapi/Blob.cpp: Switch to using BlobData.
+        (WebCore::Blob::Blob):
+        (WebCore::Blob::slice):
+        * fileapi/Blob.h: Switch to using BlobData.
+        (WebCore::Blob::create):
+        (WebCore::Blob::size):
+        (WebCore::Blob::isFile):
+        * fileapi/BlobBuilder.cpp: Switch to using BlobData.
+        (WebCore::BlobBuilder::BlobBuilder):
+        (WebCore::BlobBuilder::append):
+        (WebCore::BlobBuilder::getBlob):
+        * fileapi/BlobBuilder.h: Switch to using BlobData.
+        * fileapi/BlobURL.cpp: Add a new helper method used in FormData.
+        (WebCore::BlobURL::getIdentifier):
+        * fileapi/BlobURL.h:
+        * fileapi/File.cpp: Switch to using BlobData.
+        (WebCore::createBlobDataForFile):
+        (WebCore::File::File):
+        (WebCore::File::size):
+        (WebCore::File::captureSnapshot):
+        * fileapi/File.h: Switch to using BlobData.
+        (WebCore::File::create):
+        (WebCore::File::path):
+        (WebCore::File::name):
+        (WebCore::File::webkitRelativePath):
+        * fileapi/FileReader.cpp: Change the reading to route through blob resource loading.
+        (WebCore::FileReader::FileReader):
+        (WebCore::FileReader::readAsBinaryString):
+        (WebCore::FileReader::readAsText):
+        (WebCore::FileReader::readAsDataURL):
+        (WebCore::delayedStart):
+        (WebCore::FileReader::readInternal):
+        (WebCore::FileReader::terminate):
+        (WebCore::FileReader::start):
+        (WebCore::FileReader::didReceiveResponse):
+        (WebCore::FileReader::didReceiveData):
+        (WebCore::FileReader::didFinishLoading):
+        (WebCore::FileReader::didFail):
+        (WebCore::FileReader::failed):
+        (WebCore::FileReader::httpStatusCodeToExceptionCode):
+        (WebCore::FileReader::result):
+        (WebCore::FileReader::convertToDataURL):
+        * fileapi/FileReader.h:
+        * html/FormDataList.cpp: Account to BlobData change.
+        (WebCore::FormDataList::appendString):
+        (WebCore::FormDataList::appendBlob):
+        * html/FormDataList.h: Account to BlobData change.
+        (WebCore::FormDataList::appendBlob):
+        (WebCore::FormDataList::Item::Item):
+        (WebCore::FormDataList::Item::data):
+        (WebCore::FormDataList::Item::blob):
+        (WebCore::FormDataList::items):
+        * loader/FormSubmission.cpp: Account to BlobData change.
+        (WebCore::FormSubmission::create):
+        * platform/BlobItem.cpp: Removed.
+        * platform/BlobItem.h: Removed.
+        * platform/network/BlobRegistryImpl.cpp: Add the implementations for resource loading.
+        (WebCore::BlobRegistryImpl::createResourceHandle):
+        (WebCore::BlobRegistryImpl::loadResourceSynchronously):
+        * platform/network/BlobResourceHandle.cpp: Fix a bug that the ref is not added.
+        (WebCore::BlobResourceHandle::BlobResourceHandle):
+        * platform/network/FormData.cpp: Account to BlobData change.
+        (WebCore::FormData::create):
+        (WebCore::FormData::createMultiPart):
+        (WebCore::FormData::deepCopy):
+        (WebCore::FormData::appendFile):
+        (WebCore::FormData::appendKeyValuePairItems):
+        * platform/network/FormData.h: Account to BlobData change.
+        * platform/network/mac/FormDataStreamMac.mm: Resolve blob references in the form data.
+        (WebCore::closeCurrentStream):
+        (WebCore::advanceCurrentStream):
+        (WebCore::formCreate):
+        (WebCore::formRead):
+        (WebCore::setHTTPBody):
+        * xml/XMLHttpRequest.cpp: Account to BlobData change.
+        (WebCore::XMLHttpRequest::send):
+
 2010-08-30  Eric Seidel  <eric at webkit.org>
 
         Unreviewed, rolling out r66418.
diff --git a/WebCore/GNUmakefile.am b/WebCore/GNUmakefile.am
index 1e1de03..43948e9 100644
--- a/WebCore/GNUmakefile.am
+++ b/WebCore/GNUmakefile.am
@@ -1878,8 +1878,6 @@ webcore_sources += \
 	WebCore/platform/Arena.h \
 	WebCore/platform/AsyncFileStream.h \
 	WebCore/platform/AutodrainedPool.h \
-	WebCore/platform/BlobItem.cpp \
-	WebCore/platform/BlobItem.h \
 	WebCore/platform/ContentType.cpp \
 	WebCore/platform/ContentType.h \
 	WebCore/platform/ContextMenu.cpp \
diff --git a/WebCore/WebCore.gypi b/WebCore/WebCore.gypi
index e5b57ba..4784689 100644
--- a/WebCore/WebCore.gypi
+++ b/WebCore/WebCore.gypi
@@ -3054,8 +3054,6 @@
             'platform/AsyncFileSystem.h',
             'platform/AsyncFileSystemCallbacks.h',
             'platform/AutodrainedPool.h',
-            'platform/BlobItem.cpp',
-            'platform/BlobItem.h',
             'platform/ContentType.cpp',
             'platform/ContentType.h',
             'platform/ContextMenu.cpp',
diff --git a/WebCore/WebCore.pro b/WebCore/WebCore.pro
index 38100a9..f14bdf5 100644
--- a/WebCore/WebCore.pro
+++ b/WebCore/WebCore.pro
@@ -877,7 +877,6 @@ SOURCES += \
     platform/animation/AnimationList.cpp \
     platform/Arena.cpp \
     platform/AsyncFileSystem.cpp \
-    platform/BlobItem.cpp \
     platform/text/Base64.cpp \
     platform/text/BidiContext.cpp \
     platform/text/Hyphenation.cpp \
@@ -1682,7 +1681,6 @@ HEADERS += \
     platform/AsyncFileStream.h \
     platform/AsyncFileSystem.h \
     platform/AsyncFileSystemCallbacks.h \
-    platform/BlobItem.h \
     platform/ContentType.h \
     platform/ContextMenu.h \
     platform/CrossThreadCopier.h \
diff --git a/WebCore/WebCore.vcproj/WebCore.vcproj b/WebCore/WebCore.vcproj/WebCore.vcproj
index 98358de..65aebb6 100644
--- a/WebCore/WebCore.vcproj/WebCore.vcproj
+++ b/WebCore/WebCore.vcproj/WebCore.vcproj
@@ -23997,14 +23997,6 @@
 				>
 			</File>
 			<File
-				RelativePath="..\platform\BlobItem.cpp"
-				>
-			</File>
-			<File
-				RelativePath="..\platform\BlobItem.h"
-				>
-			</File>
-			<File
 				RelativePath="..\platform\ContentType.cpp"
 				>
 			</File>
diff --git a/WebCore/WebCore.xcodeproj/project.pbxproj b/WebCore/WebCore.xcodeproj/project.pbxproj
index 91bf44e..f741dbd 100644
--- a/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -2388,8 +2388,6 @@
 		89686CA0122244A00076EAA4 /* DOMFilePath.h in Headers */ = {isa = PBXBuildFile; fileRef = 89686C9E122244A00076EAA4 /* DOMFilePath.h */; };
 		898783D312232A13003AABDA /* LocalFileSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 898783D112232A13003AABDA /* LocalFileSystem.cpp */; };
 		898783D412232A13003AABDA /* LocalFileSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = 898783D212232A13003AABDA /* LocalFileSystem.h */; };
-		8988E10E11A3508B00DB732E /* BlobItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8988E10C11A3508B00DB732E /* BlobItem.cpp */; };
-		8988E10F11A3508B00DB732E /* BlobItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 8988E10D11A3508B00DB732E /* BlobItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		899ABC261215E4A300F9F219 /* DirectoryEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 899ABC201215E4A300F9F219 /* DirectoryEntry.cpp */; };
 		899ABC271215E4A300F9F219 /* DirectoryEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 899ABC211215E4A300F9F219 /* DirectoryEntry.h */; };
 		899ABC291215E4A300F9F219 /* DirectoryReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 899ABC231215E4A300F9F219 /* DirectoryReader.cpp */; };
@@ -8289,8 +8287,6 @@
 		897A2D92120003760082740C /* JSFlags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSFlags.h; sourceTree = "<group>"; };
 		898783D112232A13003AABDA /* LocalFileSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LocalFileSystem.cpp; sourceTree = "<group>"; };
 		898783D212232A13003AABDA /* LocalFileSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocalFileSystem.h; sourceTree = "<group>"; };
-		8988E10C11A3508B00DB732E /* BlobItem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlobItem.cpp; sourceTree = "<group>"; };
-		8988E10D11A3508B00DB732E /* BlobItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlobItem.h; sourceTree = "<group>"; };
 		899ABC201215E4A300F9F219 /* DirectoryEntry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DirectoryEntry.cpp; sourceTree = "<group>"; };
 		899ABC211215E4A300F9F219 /* DirectoryEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryEntry.h; sourceTree = "<group>"; };
 		899ABC221215E4A300F9F219 /* DirectoryEntry.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DirectoryEntry.idl; sourceTree = "<group>"; };
@@ -16656,8 +16652,6 @@
 				89D08D9D12228451001241DF /* AsyncFileSystem.h */,
 				89D08D9E12228451001241DF /* AsyncFileSystemCallbacks.h */,
 				51E1ECB10C91C55600DC255B /* AutodrainedPool.h */,
-				8988E10C11A3508B00DB732E /* BlobItem.cpp */,
-				8988E10D11A3508B00DB732E /* BlobItem.h */,
 				BCC8CFCA0986CD2400140BF2 /* ColorData.gperf */,
 				41D015C90F4B5C71004A662F /* ContentType.cpp */,
 				41D015C80F4B5C71004A662F /* ContentType.h */,
@@ -17771,7 +17765,6 @@
 				BCE789861120E7A60060ECE5 /* BidiRun.h in Headers */,
 				938192050F87E1EC00D5352A /* BinaryPropertyList.h in Headers */,
 				A89943280B42338800D7C802 /* BitmapImage.h in Headers */,
-				8988E10F11A3508B00DB732E /* BlobItem.h in Headers */,
 				93F199BE08245E59001E9ABC /* BlockExceptions.h in Headers */,
 				BC5EB5E10E81BE8700B25965 /* BorderData.h in Headers */,
 				BC5EB5DB0E81B7EA00B25965 /* BorderValue.h in Headers */,
@@ -20795,7 +20788,6 @@
 				BCE7898B1120E8020060ECE5 /* BidiRun.cpp in Sources */,
 				938192030F87E1E600D5352A /* BinaryPropertyList.cpp in Sources */,
 				A89943290B42338800D7C802 /* BitmapImage.cpp in Sources */,
-				8988E10E11A3508B00DB732E /* BlobItem.cpp in Sources */,
 				93F19AE108245E59001E9ABC /* BlockExceptions.mm in Sources */,
 				BCEA4854097D93020094C9E4 /* break_lines.cpp in Sources */,
 				93309DDA099E64920056E581 /* BreakBlockquoteCommand.cpp in Sources */,
diff --git a/WebCore/fileapi/Blob.cpp b/WebCore/fileapi/Blob.cpp
index 3a62ab1..5fed327 100644
--- a/WebCore/fileapi/Blob.cpp
+++ b/WebCore/fileapi/Blob.cpp
@@ -31,51 +31,19 @@
 #include "config.h"
 #include "Blob.h"
 
-#include "BlobData.h"
-#include "BlobItem.h"
 #include "BlobURL.h"
-#include "FileSystem.h"
+#include "File.h"
 #include "ScriptExecutionContext.h"
 #include "ThreadableBlobRegistry.h"
 
 namespace WebCore {
 
-// FIXME: To be removed when we switch to using BlobData.
-Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const String& type, const BlobItemList& items)
-    : m_scriptExecutionContext(scriptExecutionContext)
-    , m_type(type)
-    , m_size(0)
-{
-    m_scriptExecutionContext->addBlob(this);
-    for (size_t i = 0; i < items.size(); ++i)
-        m_items.append(items[i]);
-}
-
-// FIXME: To be removed when we switch to using BlobData.
-Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const PassRefPtr<BlobItem>& item)
-    : m_scriptExecutionContext(scriptExecutionContext)
-    , m_size(0)
-{
-    m_scriptExecutionContext->addBlob(this);
-    m_items.append(item);
-}
-
-// FIXME: To be removed when we switch to using BlobData.
-Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const String& path)
-    : m_scriptExecutionContext(scriptExecutionContext)
-    , m_size(0)
-{
-    m_scriptExecutionContext->addBlob(this);
-    // Note: this doesn't initialize the type unlike File(path).
-    m_items.append(FileBlobItem::create(path));
-}
-
 Blob::Blob(ScriptExecutionContext* scriptExecutionContext, PassOwnPtr<BlobData> blobData, long long size)
     : m_scriptExecutionContext(scriptExecutionContext)
     , m_type(blobData->contentType())
     , m_size(size)
 {
-    ASSERT(blobData.get() && !blobData->items().isEmpty());
+    ASSERT(blobData);
 
     m_scriptExecutionContext->addBlob(this);
 
@@ -89,11 +57,7 @@ Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const KURL& srcURL, c
     , m_type(type)
     , m_size(size)
 {
-    m_scriptExecutionContext->addBlob(this);
-
-    // FIXME: To be removed when we switch to using BlobData.
-    if (srcURL.isEmpty())
-        return;
+   m_scriptExecutionContext->addBlob(this);
 
     // Create a new internal URL and register it with the same blob data as the source URL.
     m_url = BlobURL::createURL(scriptExecutionContext);
@@ -118,50 +82,42 @@ void Blob::contextDestroyed()
     m_scriptExecutionContext = 0;
 }
 
-unsigned long long Blob::size() const
-{
-    // 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 represetable.
-    unsigned long long size = 0;
-    for (size_t i = 0; i < m_items.size(); ++i)
-        size += m_items[i]->size();
-    return size;
-}
-
-// FIXME: To be removed when we switch to using BlobData.
-const String& Blob::path() const
-{
-    ASSERT(m_items.size() == 1 && m_items[0]->toFileBlobItem());
-    return m_items[0]->toFileBlobItem()->path();
-}
-
 #if ENABLE(BLOB)
 PassRefPtr<Blob> Blob::slice(ScriptExecutionContext* scriptExecutionContext, long long start, long long length, 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.
+        static_cast<const File*>(this)->captureSnapshot(size, modificationTime);
+    else {
+        ASSERT(m_size != -1);
+        size = m_size;
+    }
+
+    // Clamp the range if it exceeds the size limit.
     if (start < 0)
         start = 0;
     if (length < 0)
         length = 0;
 
-    // Clamp the range if it exceeds the size limit.
-    unsigned long long totalSize = size();
-    if (static_cast<unsigned long long>(start) > totalSize) {
+    if (start >= size) {
         start = 0;
         length = 0;
-    } else if (static_cast<unsigned long long>(start + length) > totalSize)
-        length = totalSize - start;
-
-    size_t i = 0;
-    BlobItemList items;
-    for (; i < m_items.size() && static_cast<unsigned long long>(start) >= m_items[i]->size(); ++i)
-        start -= m_items[i]->size();
-    for (; length > 0 && i < m_items.size(); ++i) {
-        items.append(m_items[i]->slice(start, length));
-        length -= items.last()->size();
-        start = 0;
-    }
-    return Blob::create(scriptExecutionContext, contentType, items);
+    } else if (start + length > size)
+        length = size - start;
+
+    OwnPtr<BlobData> blobData = BlobData::create();
+    blobData->setContentType(contentType);
+    if (isFile())
+        blobData->appendFile(static_cast<const File*>(this)->path(), start, length, modificationTime);
+    else
+        blobData->appendBlob(m_url, start, length);
+
+    return Blob::create(scriptExecutionContext, blobData.release(), length);
 }
-#endif // ENABLE(BLOB)
+#endif
 
 } // namespace WebCore
diff --git a/WebCore/fileapi/Blob.h b/WebCore/fileapi/Blob.h
index 374a401..0d5649c 100644
--- a/WebCore/fileapi/Blob.h
+++ b/WebCore/fileapi/Blob.h
@@ -31,7 +31,7 @@
 #ifndef Blob_h
 #define Blob_h
 
-#include "BlobItem.h"
+#include "BlobData.h"
 #include "KURL.h"
 #include "PlatformString.h"
 #include <wtf/PassOwnPtr.h>
@@ -41,15 +41,13 @@
 
 namespace WebCore {
 
-class BlobData;
 class ScriptExecutionContext;
 
 class Blob : public RefCounted<Blob> {
 public:
-    // FIXME: To be removed when we switch to using BlobData.
-    static PassRefPtr<Blob> create(ScriptExecutionContext* scriptExecutionContext, const String& type, const BlobItemList& items)
+    static PassRefPtr<Blob> create(ScriptExecutionContext* scriptExecutionContext, PassOwnPtr<BlobData> blobData, long long size)
     {
-        return adoptRef(new Blob(scriptExecutionContext, type, items));
+        return adoptRef(new Blob(scriptExecutionContext, blobData, size));
     }
 
     // For deserialization.
@@ -63,38 +61,25 @@ public:
     void contextDestroyed();
 
     const KURL& url() const { return m_url; }
-    unsigned long long size() const;
     const String& type() const { return m_type; }
-    virtual bool isFile() const { return false; }
-
-    // FIXME: To be removed when we switch to using BlobData.
-    const String& path() const;
 
-    // FIXME: To be removed when we switch to using BlobData.
-    const BlobItemList& items() const { return m_items; }
+    virtual unsigned long long size() const { return static_cast<unsigned long long>(m_size); }
+    virtual bool isFile() const { return false; }
 
 #if ENABLE(BLOB)
     PassRefPtr<Blob> slice(ScriptExecutionContext*, long long start, long long length, const String& contentType = String()) const;
 #endif
 
 protected:
-    // FIXME: To be removed when we switch to using BlobData.
-    Blob(ScriptExecutionContext*, const String& type, const BlobItemList&);
-    Blob(ScriptExecutionContext*, const PassRefPtr<BlobItem>&);
-    Blob(ScriptExecutionContext*, const String& path);
-
     Blob(ScriptExecutionContext*, PassOwnPtr<BlobData>, long long size);
 
     // For deserialization.
     Blob(ScriptExecutionContext*, const KURL& srcURL, const String& type, long long size);
 
-    // FIXME: To be removed when we switch to using BlobData.
-    BlobItemList m_items;
-
     // This is an internal URL referring to the blob data associated with this object.
     // It is only used by FileReader to read the blob data via loading from the blob URL resource.
     KURL m_url;
-
+    
     ScriptExecutionContext* m_scriptExecutionContext;
     String m_type;
     long long m_size;
diff --git a/WebCore/fileapi/BlobBuilder.cpp b/WebCore/fileapi/BlobBuilder.cpp
index 29a7595..08ded1b 100644
--- a/WebCore/fileapi/BlobBuilder.cpp
+++ b/WebCore/fileapi/BlobBuilder.cpp
@@ -34,6 +34,7 @@
 
 #include "Blob.h"
 #include "ExceptionCode.h"
+#include "File.h"
 #include "LineEnding.h"
 #include "TextEncoding.h"
 #include <wtf/text/AtomicString.h>
@@ -56,13 +57,19 @@ static CString convertToCString(const String& text, const String& endingType, Ex
     return CString();
 }
 
+BlobBuilder::BlobBuilder()
+    : m_size(0)
+{
+}
+
 bool BlobBuilder::append(const String& text, const String& endingType, ExceptionCode& ec)
 {
     CString cstr = convertToCString(text, endingType, ec);
     if (ec)
         return false;
 
-    m_items.append(StringBlobItem::create(cstr));
+    m_size += cstr.length();
+    m_items.append(BlobDataItem(cstr));
     return true;
 }
 
@@ -73,17 +80,37 @@ bool BlobBuilder::append(const String& text, ExceptionCode& ec)
 
 bool BlobBuilder::append(PassRefPtr<Blob> blob)
 {
-    if (blob) {
-        for (size_t i = 0; i < blob->items().size(); ++i)
-            m_items.append(blob->items()[i]);
-        return true;
+    if (blob->isFile()) {
+        // 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.
+        File* file = static_cast<File*>(blob.get());
+        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));
     }
-    return false;
+    return true;
 }
 
-PassRefPtr<Blob> BlobBuilder::getBlob(ScriptExecutionContext* scriptExecutionContext, const String& contentType) const
+PassRefPtr<Blob> BlobBuilder::getBlob(ScriptExecutionContext* scriptExecutionContext, const String& contentType)
 {
-    return Blob::create(scriptExecutionContext, contentType, m_items);
+    OwnPtr<BlobData> blobData = BlobData::create();
+    blobData->setContentType(contentType);
+    blobData->swapItems(m_items);
+
+    RefPtr<Blob> blob = Blob::create(scriptExecutionContext, blobData.release(), 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
diff --git a/WebCore/fileapi/BlobBuilder.h b/WebCore/fileapi/BlobBuilder.h
index 5d1700f..20e510a 100644
--- a/WebCore/fileapi/BlobBuilder.h
+++ b/WebCore/fileapi/BlobBuilder.h
@@ -31,14 +31,18 @@
 #ifndef BlobBuilder_h
 #define BlobBuilder_h
 
-#include "BlobItem.h"
+#include "BlobData.h"
+#include "PlatformString.h"
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include <wtf/text/CString.h>
 
 namespace WebCore {
 
 class Blob;
 class ScriptExecutionContext;
+class TextEncoding;
 
 typedef int ExceptionCode;
 
@@ -50,10 +54,13 @@ public:
     bool append(const String& text, ExceptionCode&);
     bool append(const String& text, const String& ending, ExceptionCode&);
 
-    PassRefPtr<Blob> getBlob(ScriptExecutionContext*, const String& contentType = String()) const;
+    PassRefPtr<Blob> getBlob(ScriptExecutionContext*, const String& contentType = String());
 
 private:
-    BlobItemList m_items;
+    BlobBuilder();
+
+    long long m_size;
+    BlobDataItemList m_items;
 };
 
 } // namespace WebCore
diff --git a/WebCore/fileapi/BlobURL.cpp b/WebCore/fileapi/BlobURL.cpp
index 610aac4..c5571a7 100644
--- a/WebCore/fileapi/BlobURL.cpp
+++ b/WebCore/fileapi/BlobURL.cpp
@@ -63,4 +63,12 @@ KURL BlobURL::getOrigin(const KURL& url)
     return KURL(ParsedURLString, decodeURLEscapeSequences(origin));
 }
 
+String BlobURL::getIdentifier(const KURL& url)
+{
+    ASSERT(url.protocolIs("blob"));
+
+    unsigned startIndex = url.pathAfterLastSlash();
+    return url.string().substring(startIndex);
+}
+
 } // namespace WebCore
diff --git a/WebCore/fileapi/BlobURL.h b/WebCore/fileapi/BlobURL.h
index 2ce2c85..e73b771 100644
--- a/WebCore/fileapi/BlobURL.h
+++ b/WebCore/fileapi/BlobURL.h
@@ -41,6 +41,7 @@ class BlobURL {
 public:
     static KURL createURL(ScriptExecutionContext*);
     static KURL getOrigin(const KURL&);
+    static String getIdentifier(const KURL& url);
 };
 
 }
diff --git a/WebCore/fileapi/File.cpp b/WebCore/fileapi/File.cpp
index 253cb4d..6cc1393 100644
--- a/WebCore/fileapi/File.cpp
+++ b/WebCore/fileapi/File.cpp
@@ -26,52 +26,69 @@
 #include "config.h"
 #include "File.h"
 
-#include "BlobData.h"
+#include "BlobRegistry.h"
 #include "FileSystem.h"
 #include "MIMETypeRegistry.h"
 
 namespace WebCore {
 
+static PassOwnPtr<BlobData> createBlobDataForFile(const String& path)
+{
+    String type;
+    int index = path.reverseFind('.');
+    if (index != -1)
+        type = MIMETypeRegistry::getMIMETypeForExtension(path.substring(index + 1));
+
+    OwnPtr<BlobData> blobData = BlobData::create();
+    blobData->setContentType(type);
+    blobData->appendFile(path);
+    return blobData.release();
+}
+
 File::File(ScriptExecutionContext* scriptExecutionContext, const String& path)
-    : Blob(scriptExecutionContext, path)
+    : Blob(scriptExecutionContext, createBlobDataForFile(path), -1)
+    , m_path(path)
+    , m_name(pathGetFileName(path))
 {
-    Init();
 }
 
 File::File(ScriptExecutionContext* scriptExecutionContext, const String& path, const KURL& url, const String& type)
-    : Blob(scriptExecutionContext, url, type, BlobDataItem::toEndOfFile)
+    : Blob(scriptExecutionContext, url, type, -1)
+    , m_path(path)
 {
-    // FIXME: To be removed when we switch to using BlobData.
-     m_items.append(FileBlobItem::create(path));
+    m_name = pathGetFileName(path);
 }
 
 #if ENABLE(DIRECTORY_UPLOAD)
-File::File(ScriptExecutionContext* scriptExecutionContext, const String& relativePath, const String& filePath)
-    : Blob(scriptExecutionContext, FileBlobItem::create(filePath, relativePath))
+File::File(ScriptExecutionContext* scriptExecutionContext, const String& relativePath, const String& path)
+    : Blob(scriptExecutionContext, createBlobDataForFile(path), -1)
+    , m_path(path)
+    , m_relativePath(relativePath)
 {
-    Init();
 }
 #endif
 
-void File::Init()
+unsigned long long File::size() const
 {
-    // We don't use MIMETypeRegistry::getMIMETypeForPath() because it returns "application/octet-stream" upon failure.
-    const String& fileName = name();
-    size_t index = fileName.reverseFind('.');
-    if (index != notFound)
-        m_type = MIMETypeRegistry::getMIMETypeForExtension(fileName.substring(index + 1));
+    // 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);
 }
 
-const String& File::name() const
+void File::captureSnapshot(long long& snapshotSize, double& snapshotModificationTime) const
 {
-    return items().at(0)->toFileBlobItem()->name();
+    // 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.
+    // FIXME: Combine getFileSize and getFileModificationTime into one file system call.
+    time_t modificationTime;
+    if (!getFileSize(m_path, snapshotSize) || !getFileModificationTime(m_path, modificationTime)) {
+        snapshotSize = 0;
+        snapshotModificationTime = 0;
+    } else
+        snapshotModificationTime = modificationTime;
 }
 
-#if ENABLE(DIRECTORY_UPLOAD)
-const String& File::webkitRelativePath() const
-{
-    return items().at(0)->toFileBlobItem()->relativePath();
-}
-#endif
-
 } // namespace WebCore
diff --git a/WebCore/fileapi/File.h b/WebCore/fileapi/File.h
index 06a73c5..d6446d3 100644
--- a/WebCore/fileapi/File.h
+++ b/WebCore/fileapi/File.h
@@ -27,11 +27,15 @@
 #define File_h
 
 #include "Blob.h"
+#include "PlatformString.h"
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
 
 namespace WebCore {
 
+class KURL;
+class ScriptExecutionContext;
+
 class File : public Blob {
 public:
     static PassRefPtr<File> create(ScriptExecutionContext* scriptExecutionContext, const String& path)
@@ -40,9 +44,9 @@ public:
     }
 
     // For deserialization.
-    static PassRefPtr<File> create(ScriptExecutionContext* scriptExecutionContext, const String& path, const KURL& url, const String& type)
+    static PassRefPtr<File> create(ScriptExecutionContext* scriptExecutionContext, const String& path, const KURL& srcURL, const String& type)
     {
-        return adoptRef(new File(scriptExecutionContext, path, url, type));
+        return adoptRef(new File(scriptExecutionContext, path, srcURL, type));
     }
 
 #if ENABLE(DIRECTORY_UPLOAD)
@@ -52,29 +56,38 @@ public:
     }
 #endif
 
+    virtual unsigned long long size() const;
     virtual bool isFile() const { return true; }
 
-    const String& name() const;
+    const String& path() const { return m_path; }
+    const String& name() const { return m_name; }
 #if ENABLE(DIRECTORY_UPLOAD)
     // Returns the relative path of this file in the context of a directory selection.
-    const String& webkitRelativePath() const;
+    const String& webkitRelativePath() const { return m_relativePath; }
 #endif
 
+    // Note that this involves synchronous file operation. Think twice before calling this function.
+    void captureSnapshot(long long& snapshotSize, double& snapshotModificationTime) const;
+
     // FIXME: obsolete attributes. To be removed.
     const String& fileName() const { return name(); }
     unsigned long long fileSize() const { return size(); }
 
 private:
     File(ScriptExecutionContext*, const String& path);
-
+    
     // For deserialization.
-    File(ScriptExecutionContext*, const String& path, const KURL&, const String& type);
+    File(ScriptExecutionContext*, const String& path, const KURL& srcURL, const String& type);
 
 #if ENABLE(DIRECTORY_UPLOAD)
     File(ScriptExecutionContext*, const String& relativePath, const String& path);
 #endif
 
-    void Init();
+    String m_path;
+    String m_name;
+#if ENABLE(DIRECTORY_UPLOAD)
+    String m_relativePath;
+#endif
 };
 
 } // namespace WebCore
diff --git a/WebCore/fileapi/FileReader.cpp b/WebCore/fileapi/FileReader.cpp
index d600d40..747b6ff 100644
--- a/WebCore/fileapi/FileReader.cpp
+++ b/WebCore/fileapi/FileReader.cpp
@@ -36,17 +36,19 @@
 
 #include "Base64.h"
 #include "Blob.h"
+#include "CrossThreadTask.h"
 #include "File.h"
-#include "FileStreamProxy.h"
 #include "Logging.h"
 #include "ProgressEvent.h"
+#include "ResourceError.h"
+#include "ResourceRequest.h"
 #include "ScriptExecutionContext.h"
 #include "TextResourceDecoder.h"
+#include "ThreadableLoader.h"
 #include <wtf/CurrentTime.h>
 
 namespace WebCore {
 
-const unsigned bufferSize = 1024;
 const double progressNotificationIntervalMS = 50;
 
 FileReader::FileReader(ScriptExecutionContext* context)
@@ -59,7 +61,6 @@ FileReader::FileReader(ScriptExecutionContext* context)
     , m_totalBytes(0)
     , m_lastProgressNotificationTimeMS(0)
 {
-    m_buffer.resize(bufferSize);
 }
 
 FileReader::~FileReader()
@@ -83,55 +84,56 @@ void FileReader::stop()
     terminate();
 }
 
-void FileReader::readAsBinaryString(Blob* fileBlob)
+void FileReader::readAsBinaryString(Blob* blob)
 {
-    if (!fileBlob)
+    if (!blob)
         return;
 
-    // FIXME: needs to handle non-file blobs.
-    LOG(FileAPI, "FileReader: reading as binary: %s\n", fileBlob->path().utf8().data());
+    LOG(FileAPI, "FileReader: reading as binary: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? static_cast<File*>(blob)->path().utf8().data() : "");
 
-    readInternal(fileBlob, ReadFileAsBinaryString);
+    readInternal(blob, ReadFileAsBinaryString);
 }
 
-void FileReader::readAsText(Blob* fileBlob, const String& encoding)
+void FileReader::readAsText(Blob* blob, const String& encoding)
 {
-    if (!fileBlob)
+    if (!blob)
         return;
 
-    // FIXME: needs to handle non-file blobs.
-    LOG(FileAPI, "FileReader: reading as text: %s\n", fileBlob->path().utf8().data());
+    LOG(FileAPI, "FileReader: reading as text: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? static_cast<File*>(blob)->path().utf8().data() : "");
 
     if (!encoding.isEmpty())
         m_encoding = TextEncoding(encoding);
-    readInternal(fileBlob, ReadFileAsText);
+    readInternal(blob, ReadFileAsText);
 }
 
-void FileReader::readAsDataURL(File* file)
+void FileReader::readAsDataURL(Blob* blob)
 {
-    if (!file)
+    if (!blob)
         return;
 
-    LOG(FileAPI, "FileReader: reading as data URL: %s\n", file->path().utf8().data());
+    LOG(FileAPI, "FileReader: reading as data URL: %s %s\n", blob->url().string().utf8().data(), blob->isFile() ? static_cast<File*>(blob)->path().utf8().data() : "");
 
-    m_fileType = file->type();
-    readInternal(file, ReadFileAsDataURL);
+    m_fileType = blob->type();
+    readInternal(blob, ReadFileAsDataURL);
 }
 
-void FileReader::readInternal(Blob* fileBlob, ReadType type)
+static void delayedStart(ScriptExecutionContext*, FileReader* reader)
+{
+    reader->start();
+}
+
+void FileReader::readInternal(Blob* blob, ReadType type)
 {
     // readAs*** methods() can be called multiple times. Only the last call before the actual reading happens is processed.
     if (m_state != None && m_state != Starting)
         return;
 
-    m_fileBlob = fileBlob;
+    if (m_state == None)
+        scriptExecutionContext()->postTask(createCallbackTask(&delayedStart, this));
+
+    m_blob = blob;
     m_readType = type;
     m_state = Starting;
-
-    // When FileStreamProxy is created, FileReader::didStart() will get notified on the File thread and we will start
-    // opening and reading the file since then.
-    if (!m_streamProxy.get())
-        m_streamProxy = FileStreamProxy::create(scriptExecutionContext(), this);
 }
 
 void FileReader::abort()
@@ -150,87 +152,66 @@ void FileReader::abort()
 
 void FileReader::terminate()
 {
-    if (m_streamProxy) {
-        m_streamProxy->stop();
-        m_streamProxy = 0;
+    if (m_loader) {
+        m_loader->cancel();
+        m_loader = 0;
     }
     m_state = Completed;
 }
 
-void FileReader::didStart()
+void FileReader::start()
 {
     m_state = Opening;
 
-    ASSERT(m_fileBlob->items().size() == 1 && m_fileBlob->items().at(0)->toFileBlobItem());
-    const FileRangeBlobItem* fileRangeItem = m_fileBlob->items().at(0)->toFileRangeBlobItem();
-    double expectedModificationTime = fileRangeItem ? fileRangeItem->snapshotModificationTime() : 0;
+    // The blob is read by routing through the request handling layer given the blob url.
+    ResourceRequest request(m_blob->url());
+    request.setHTTPMethod("GET");
+
+    ThreadableLoaderOptions options;
+    options.sendLoadCallbacks = true;
+    options.sniffContent = false;
+    options.forcePreflight = false;
+    options.allowCredentials = true;
+    options.crossOriginRequestPolicy = DenyCrossOriginRequests;
 
-    m_streamProxy->getSize(m_fileBlob->path(), expectedModificationTime);
+    m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options);
 }
 
-void FileReader::didGetSize(long long size)
+void FileReader::didReceiveResponse(const ResourceResponse& response)
 {
-    // If the size is -1, it means the file has been moved or changed. Fail now.
-    if (size == -1) {
-        didFail(NOT_FOUND_ERR);
+    if (response.httpStatusCode() != 200) {
+        failed(response.httpStatusCode());
         return;
     }
 
     m_state = Reading;
     fireEvent(eventNames().loadstartEvent);
 
-    ASSERT(m_fileBlob->items().size() == 1 && m_fileBlob->items().at(0)->toFileBlobItem());
-    const FileRangeBlobItem* fileRangeItem = m_fileBlob->items().at(0)->toFileRangeBlobItem();
-    long long start = fileRangeItem ? fileRangeItem->start() : 0;
-
-    // The size passed back is the size of the whole file. If the underlying item is a sliced file, we need to use the slice length.
-    m_totalBytes = fileRangeItem ? fileRangeItem->size() : size;
-
-    m_streamProxy->openForRead(m_fileBlob->path(), start, m_totalBytes);
+    m_totalBytes = response.expectedContentLength();
 }
 
-void FileReader::didOpen(bool success)
+void FileReader::didReceiveData(const char* data, int lengthReceived)
 {
-    if (!success) {
-        didFail(NOT_READABLE_ERR);
-        return;
-    }
-    
-    m_streamProxy->read(m_buffer.data(), m_buffer.size());
-}
+    ASSERT(data && lengthReceived);
 
-void FileReader::didRead(int bytesRead)
-{
     // Bail out if we have aborted the reading.
     if (m_state == Completed)
         return;
 
-    // If bytesRead is -1, it means an error happens.
-    if (bytesRead == -1) {
-        didFail(NOT_READABLE_ERR);
-        return;
-    }
-
-    // If bytesRead is 0, it means the reading is done.
-    if (!bytesRead) {
-        didFinish();
-        return;
-    }
-
     switch (m_readType) {
     case ReadFileAsBinaryString:
-        m_result += String(m_buffer.data(), static_cast<unsigned>(bytesRead));
+        m_result += String(data, static_cast<unsigned>(lengthReceived));
         break;
     case ReadFileAsText:
     case ReadFileAsDataURL:
-        m_rawData.append(m_buffer.data(), static_cast<unsigned>(bytesRead));
+        m_rawData.append(data, static_cast<unsigned>(lengthReceived));
         m_isRawDataConverted = false;
         break;
     default:
         ASSERT_NOT_REACHED();
     }
 
-    m_bytesLoaded += bytesRead;
+    m_bytesLoaded += lengthReceived;
 
     // Fire the progress event at least every 50ms.
     double now = WTF::currentTimeMS();
@@ -240,30 +221,45 @@ void FileReader::didRead(int bytesRead)
         fireEvent(eventNames().progressEvent);
         m_lastProgressNotificationTimeMS = now;
     }
-
-    // Continue reading.
-    m_streamProxy->read(m_buffer.data(), m_buffer.size());
 }
 
-void FileReader::didFinish()
+void FileReader::didFinishLoading(unsigned long)
 {
     m_state = Completed;
 
-    m_streamProxy->close();
-
     fireEvent(eventNames().loadEvent);
     fireEvent(eventNames().loadendEvent);
+
+    m_loader = 0;
 }
 
-void FileReader::didFail(ExceptionCode ec)
+void FileReader::didFail(const ResourceError&)
 {
-    m_state = Completed;
-    m_error = FileError::create(ec);
+    // Treat as internal error.
+    failed(500);
+}
 
-    m_streamProxy->close();
+void FileReader::failed(int httpStatusCode)
+{
+    m_state = Completed;
 
+     m_error = FileError::create(httpStatusCodeToExceptionCode(httpStatusCode));
     fireEvent(eventNames().errorEvent);
     fireEvent(eventNames().loadendEvent);
+
+    m_loader = 0;
+}
+
+ExceptionCode FileReader::httpStatusCodeToExceptionCode(int httpStatusCode)
+{
+    switch (httpStatusCode) {
+        case 403:
+            return SECURITY_ERR;
+        case 404:
+            return NOT_FOUND_ERR;
+        default:
+            return NOT_READABLE_ERR;
+    }
 }
 
 void FileReader::fireEvent(const AtomicString& type)
@@ -303,7 +299,7 @@ const ScriptString& FileReader::result()
         convertToText();
     // For data URL, we only do the coversion until we receive all the raw data.
     else if (m_readType == ReadFileAsDataURL && m_state == Completed)
-        convertToDataURL();
+        convertToDataURL(m_rawData, m_fileType, m_result);
 
     return m_result;
 }
@@ -328,22 +324,22 @@ void FileReader::convertToText()
         m_result += m_decoder->flush();
 }
 
-void FileReader::convertToDataURL()
+void FileReader::convertToDataURL(const Vector<char>& rawData, const String& fileType, ScriptString& result)
 {
-    m_result = "data:";
+    result = "data:";
 
-    if (!m_rawData.size())
+    if (!rawData.size())
         return;
 
-    m_result += m_fileType;
-    if (!m_fileType.isEmpty())
-        m_result += ";";
-    m_result += "base64,";
+    result += fileType;
+    if (!fileType.isEmpty())
+        result += ";";
+    result += "base64,";
 
     Vector<char> out;
-    base64Encode(m_rawData, out);
+    base64Encode(rawData, out);
     out.append('\0');
-    m_result += out.data();
+    result += out.data();
 }
 
 } // namespace WebCore
diff --git a/WebCore/fileapi/FileReader.h b/WebCore/fileapi/FileReader.h
index ee15968..48ce229 100644
--- a/WebCore/fileapi/FileReader.h
+++ b/WebCore/fileapi/FileReader.h
@@ -36,10 +36,10 @@
 #include "ActiveDOMObject.h"
 #include "EventTarget.h"
 #include "FileError.h"
-#include "FileStreamClient.h"
 #include "PlatformString.h"
 #include "ScriptString.h"
 #include "TextEncoding.h"
+#include "ThreadableLoaderClient.h"
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
@@ -48,12 +48,11 @@
 namespace WebCore {
 
 class Blob;
-class File;
-class FileStreamProxy;
 class ScriptExecutionContext;
 class TextResourceDecoder;
+class ThreadableLoader;
 
-class FileReader : public RefCounted<FileReader>, public ActiveDOMObject, public EventTarget, public FileStreamClient {
+class FileReader : public RefCounted<FileReader>, public ActiveDOMObject, public EventTarget, public ThreadableLoaderClient {
 public:
     static PassRefPtr<FileReader> create(ScriptExecutionContext* context)
     {
@@ -70,13 +69,19 @@ public:
 
     void readAsBinaryString(Blob*);
     void readAsText(Blob*, const String& encoding = "");
-    void readAsDataURL(File*);
+    void readAsDataURL(Blob*);
     void abort();
 
+    void start();
+
     ReadyState readyState() const;
     PassRefPtr<FileError> error() { return m_error; }
     const ScriptString& result();
 
+    // Helper methods, also used by FileReaderSync.
+    static ExceptionCode httpStatusCodeToExceptionCode(int httpStatusCode);
+    static void convertToDataURL(const Vector<char>& rawData, const String& fileType, ScriptString& result);
+
     // ActiveDOMObject
     virtual bool canSuspend() const;
     virtual void stop();
@@ -86,11 +91,11 @@ public:
     virtual FileReader* toFileReader() { return this; }
     virtual ScriptExecutionContext* scriptExecutionContext() const { return ActiveDOMObject::scriptExecutionContext(); }
 
-    // FileStreamClient
-    virtual void didStart();
-    virtual void didGetSize(long long);
-    virtual void didOpen(bool);
-    virtual void didRead(int);
+    // ThreadableLoaderClient
+    virtual void didReceiveResponse(const ResourceResponse&);
+    virtual void didReceiveData(const char*, int);
+    virtual void didFinishLoading(unsigned long identifier);
+    virtual void didFail(const ResourceError&);
 
     using RefCounted<FileReader>::ref;
     using RefCounted<FileReader>::deref;
@@ -126,16 +131,16 @@ private:
 
     void terminate();
     void readInternal(Blob*, ReadType);
+    void failed(int httpStatusCode);
+    void fireErrorEvent(int httpStatusCode);
     void fireEvent(const AtomicString& type);
     void convertToText();
     void convertToDataURL();
-    void didFinish();
-    void didFail(ExceptionCode);
 
     InternalState m_state;
     EventTargetData m_eventTargetData;
 
-    RefPtr<Blob> m_fileBlob;
+    RefPtr<Blob> m_blob;
     ReadType m_readType;
     TextEncoding m_encoding;
 
@@ -157,8 +162,7 @@ private:
     // Needed to create data URL.
     String m_fileType;
 
-    RefPtr<FileStreamProxy> m_streamProxy;
-    Vector<char> m_buffer;
+    RefPtr<ThreadableLoader> m_loader;
     RefPtr<FileError> m_error;
     long long m_bytesLoaded;
     long long m_totalBytes;
diff --git a/WebCore/html/FormDataList.cpp b/WebCore/html/FormDataList.cpp
index 94d0031..4503fd2 100644
--- a/WebCore/html/FormDataList.cpp
+++ b/WebCore/html/FormDataList.cpp
@@ -33,20 +33,17 @@ FormDataList::FormDataList(const TextEncoding& c)
 void FormDataList::appendString(const String& s)
 {
     CString cstr = m_encoding.encode(s.characters(), s.length(), EntitiesForUnencodables);
-    m_items.append(StringBlobItem::create(normalizeLineEndingsToCRLF(cstr)));
+    m_items.append(normalizeLineEndingsToCRLF(cstr));
 }
 
 void FormDataList::appendString(const CString& s)
 {
-    m_items.append(StringBlobItem::create(s));
+    m_items.append(s);
 }
 
-void FormDataList::appendBlob(const String& key, PassRefPtr<Blob> blob)
+void FormDataList::appendBlob(PassRefPtr<Blob> blob)
 {
-    appendString(key);
-    const BlobItemList& items = blob->items();
-    for (size_t i = 0; i < items.size(); ++i)
-        m_items.append(items.at(i));
+    m_items.append(blob);
 }
 
 } // namespace
diff --git a/WebCore/html/FormDataList.h b/WebCore/html/FormDataList.h
index 38b07f9..8e1a937 100644
--- a/WebCore/html/FormDataList.h
+++ b/WebCore/html/FormDataList.h
@@ -30,6 +30,20 @@ namespace WebCore {
 
 class FormDataList {
 public:
+    class Item {
+    public:
+        Item() { }
+        Item(const WTF::CString& data) : m_data(data) { }
+        Item(PassRefPtr<Blob> blob) : m_blob(blob) { }
+
+        const WTF::CString& data() const { return m_data; }
+        Blob* blob() const { return m_blob.get(); }
+
+    private:
+        WTF::CString m_data;
+        RefPtr<Blob> m_blob;
+    };
+
     FormDataList(const TextEncoding&);
 
     void appendData(const String& key, const String& value)
@@ -47,17 +61,22 @@ public:
         appendString(key);
         appendString(String::number(value));
     }
-    void appendBlob(const String& key, PassRefPtr<Blob>);
+    void appendBlob(const String& key, PassRefPtr<Blob> blob)
+    {
+        appendString(key);
+        appendBlob(blob);
+    }
 
-    const BlobItemList& items() const { return m_items; }
+    const Vector<Item>& items() const { return m_items; }
     const TextEncoding& encoding() const { return m_encoding; }
 
 private:
     void appendString(const CString&);
     void appendString(const String&);
+    void appendBlob(PassRefPtr<Blob>);
 
     TextEncoding m_encoding;
-    BlobItemList m_items;
+    Vector<Item> m_items;
 };
 
 } // namespace WebCore
diff --git a/WebCore/loader/FormSubmission.cpp b/WebCore/loader/FormSubmission.cpp
index 22e89d7..98a545e 100644
--- a/WebCore/loader/FormSubmission.cpp
+++ b/WebCore/loader/FormSubmission.cpp
@@ -162,10 +162,10 @@ PassRefPtr<FormSubmission> FormSubmission::create(HTMLFormElement* form, const A
     String boundary;
 
     if (isMultiPartForm) {
-        formData = FormData::createMultiPart(domFormData->items(), domFormData->encoding(), document);
+        formData = FormData::createMultiPart(*(static_cast<FormDataList*>(domFormData.get())), domFormData->encoding(), document);
         boundary = formData->boundary().data();
     } else {
-        formData = FormData::create(domFormData->items(), domFormData->encoding());
+        formData = FormData::create(*(static_cast<FormDataList*>(domFormData.get())), domFormData->encoding());
         if (attributes.method() == PostMethod && isMailtoForm) {
             // Convert the form data into a string that we put into the URL.
             appendMailtoPostFormDataToURL(actionURL, *formData, encodingType);
diff --git a/WebCore/platform/BlobItem.cpp b/WebCore/platform/BlobItem.cpp
deleted file mode 100644
index 591516d..0000000
--- a/WebCore/platform/BlobItem.cpp
+++ /dev/null
@@ -1,192 +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 "BlobItem.h"
-
-#include "FileSystem.h"
-#include "UUID.h"
-#include <wtf/Assertions.h>
-
-namespace WebCore {
-
-#if ENABLE(BLOB)
-static const double invalidModificationTime = 0;
-
-static double getFileSnapshotModificationTime(const String& path)
-{
-    // FIXME: synchronized file call
-    time_t modificationTime;
-    if (getFileModificationTime(path, modificationTime))
-        return static_cast<double>(modificationTime);
-    return invalidModificationTime;
-}
-#endif // ENABLE(BLOB)
-
-// DataBlobItem ----------------------------------------------------------------
-
-#if ENABLE(BLOB)
-PassRefPtr<BlobItem> DataBlobItem::slice(long long start, long long length)
-{
-    ASSERT(start >= 0 && length >= 0);
-    ASSERT(static_cast<unsigned long long>(start) < size());
-    if (!start && size() <= static_cast<unsigned long long>(length))
-        return this;
-    if (static_cast<unsigned long long>(start + length) > size())
-        length = size() - start;
-    return DataRangeBlobItem::create(this, start, length);
-}
-#endif
-
-// FileBlobItem ----------------------------------------------------------------
-
-PassRefPtr<BlobItem> FileBlobItem::create(const String& path)
-{
-    return adoptRef(static_cast<BlobItem*>(new FileBlobItem(path)));
-}
-
-FileBlobItem::FileBlobItem(const String& path)
-    : m_path(path)
-    , m_fileName(pathGetFileName(m_path))
-{
-}
-
-#if ENABLE(DIRECTORY_UPLOAD)
-PassRefPtr<BlobItem> FileBlobItem::create(const String& path, const String& relativePath)
-{
-    return adoptRef(static_cast<BlobItem*>(new FileBlobItem(path, relativePath)));
-}
-
-FileBlobItem::FileBlobItem(const String& path, const String& relativePath)
-    : m_path(path)
-    , m_fileName(pathGetFileName(m_path))
-    , m_relativePath(relativePath)
-{
-}
-#endif
-
-unsigned long long FileBlobItem::size() const
-{
-    // FIXME: synchronized file call
-    long long size;
-    if (!getFileSize(m_path, size))
-        return 0;
-    return static_cast<unsigned long long>(size);
-}
-
-#if ENABLE(BLOB)
-PassRefPtr<BlobItem> FileBlobItem::slice(long long start, long long length)
-{
-    ASSERT(start >= 0 && length >= 0);
-    long long fileSize = size();
-    ASSERT(start < fileSize);
-    if (!start && fileSize <= length)
-        return this;
-    if (start + length > fileSize)
-        length = fileSize - start;
-    const FileRangeBlobItem* fileRangeItem = toFileRangeBlobItem();
-    double modificationTime = fileRangeItem ? fileRangeItem->snapshotModificationTime() : getFileSnapshotModificationTime(path());
-    return FileRangeBlobItem::create(path(), start, length, modificationTime);
-}
-#endif // ENABLE(BLOB)
-
-// StringBlobItem --------------------------------------------------------------
-
-PassRefPtr<BlobItem> StringBlobItem::create(const CString& text)
-{
-    return adoptRef(static_cast<BlobItem*>(new StringBlobItem(text)));
-}
-
-StringBlobItem::StringBlobItem(const CString& text)
-    : m_data(text)
-{
-}
-
-// ByteArrayBlobItem ----------------------------------------------------------
-
-PassRefPtr<BlobItem> ByteArrayBlobItem::create(const char* data, size_t size)
-{
-    return adoptRef(static_cast<BlobItem*>(new ByteArrayBlobItem(data, size)));
-}
-
-ByteArrayBlobItem::ByteArrayBlobItem(const char* data, size_t size)
-{
-    m_bytesArray.append(data, size);
-}
-
-#if ENABLE(BLOB)
-
-// DataRangeBlobItem -----------------------------------------------------------
-
-PassRefPtr<BlobItem> DataRangeBlobItem::create(PassRefPtr<DataBlobItem> item, long long start, long long length)
-{
-    return adoptRef(static_cast<BlobItem*>(new DataRangeBlobItem(item, start, length)));
-}
-
-DataRangeBlobItem::DataRangeBlobItem(PassRefPtr<DataBlobItem> item, long long start, long long length)
-    : m_length(length)
-{
-    const DataRangeBlobItem* rangeItem = item->toDataRangeBlobItem();
-    if (rangeItem) {
-        m_item = rangeItem->m_item;
-        m_start = start + rangeItem->m_start;
-        ASSERT(!m_item->toDataRangeBlobItem());
-        ASSERT(static_cast<unsigned long long>(m_start + m_length) <= m_item->size());
-    } else {
-        m_item = item;
-        m_start = start;
-    }
-}
-
-const char* DataRangeBlobItem::data() const
-{
-    return m_item->data() + m_start;
-}
-
-// FileRangeBlobItem -----------------------------------------------------------
-
-PassRefPtr<BlobItem> FileRangeBlobItem::create(const String& path, long long start, long long length, double snapshotModificationTime)
-{
-    return adoptRef(static_cast<BlobItem*>(new FileRangeBlobItem(path, start, length, snapshotModificationTime)));
-}
-
-FileRangeBlobItem::FileRangeBlobItem(const String& path, long long start, long long length, double modificationTime)
-    : FileBlobItem(path)
-    , m_start(start)
-    , m_length(length)
-    , m_snapshotModificationTime(modificationTime)
-{
-    m_uniqueName = "Blob" + createCanonicalUUIDString();
-    m_uniqueName.replace("-", ""); // For safty, remove '-' from the filename snce some servers may not like it.
-}
-
-#endif // ENABLE(BLOB)
-
-} // namespace WebCore
diff --git a/WebCore/platform/BlobItem.h b/WebCore/platform/BlobItem.h
deleted file mode 100644
index 42ece92..0000000
--- a/WebCore/platform/BlobItem.h
+++ /dev/null
@@ -1,209 +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 BlobItem_h
-#define BlobItem_h
-
-#include "PlatformString.h"
-#include <wtf/OwnPtr.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/Vector.h>
-#include <wtf/text/CString.h>
-
-namespace WebCore {
-
-class ByteArrayBlobItem;
-class DataBlobItem;
-class DataRangeBlobItem;
-class FileBlobItem;
-class FileRangeBlobItem;
-class StringBlobItem;
-
-// A base interface for all arbitrary-data-object component items.
-// The BlobItem and its subclasses are structured like the following:
-//    BlobItem
-//       |
-//       +-------> DataBlobItem
-//       |              |
-//       |              +---------> StringBlobItem
-//       |              +---------> ByteArrayBlobItem
-//       |              +---------> DataRangeBlobItem
-//       |
-//       +-------> FileBlobItem
-//                      |
-//                      +---------> FileRangeBlobItem
-//
-class BlobItem : public RefCounted<BlobItem> {
-public:
-    virtual ~BlobItem() { }
-    virtual unsigned long long size() const = 0;
-
-    virtual const DataBlobItem* toDataBlobItem() const { return 0; }
-    virtual const StringBlobItem* toStringBlobItem() const { return 0; }
-    virtual const ByteArrayBlobItem* toByteArrayBlobItem() const { return 0; }
-    virtual const FileBlobItem* toFileBlobItem() const { return 0; }
-#if ENABLE(BLOB)
-    virtual const DataRangeBlobItem* toDataRangeBlobItem() const { return 0; }
-    virtual const FileRangeBlobItem* toFileRangeBlobItem() const { return 0; }
-
-    // Note: no external methods except for Blob::slice should call this.
-    virtual PassRefPtr<BlobItem> slice(long long start, long long length) = 0;
-#endif // ENABLE(BLOB)
-
-protected:
-    BlobItem() { }
-};
-
-typedef Vector<RefPtr<BlobItem> > BlobItemList;
-
-class DataBlobItem : public BlobItem {
-public:
-    virtual const char* data() const = 0;
-
-    // BlobItem methods.
-    virtual const DataBlobItem* toDataBlobItem() const { return this; }
-#if ENABLE(BLOB)
-    virtual PassRefPtr<BlobItem> slice(long long start, long long length);
-#endif // ENABLE(BLOB)
-};
-
-class FileBlobItem : public BlobItem {
-public:
-    static PassRefPtr<BlobItem> create(const String& path);
-#if ENABLE(DIRECTORY_UPLOAD)
-    static PassRefPtr<BlobItem> create(const String& path, const String& relativePath);
-#endif
-    virtual const String& name() const { return m_fileName; }
-    virtual const String& path() const { return m_path; }
-#if ENABLE(DIRECTORY_UPLOAD)
-    const String& relativePath() const { return m_relativePath; }
-#endif
-
-    // BlobItem methods.
-    virtual unsigned long long size() const;
-    virtual const FileBlobItem* toFileBlobItem() const { return this; }
-#if ENABLE(BLOB)
-    virtual PassRefPtr<BlobItem> slice(long long start, long long length);
-#endif // ENABLE(BLOB)
-
-protected:
-    FileBlobItem(const String& path);
-#if ENABLE(DIRECTORY_UPLOAD)
-    FileBlobItem(const String& path, const String& relativePath);
-#endif
-    String m_path;
-    String m_fileName;
-#if ENABLE(DIRECTORY_UPLOAD)
-    String m_relativePath;
-#endif
-};
-
-class StringBlobItem : public DataBlobItem {
-public:
-    static PassRefPtr<BlobItem> create(const CString&);
-    const CString& cstr() const { return m_data; }
-
-    // BlobItem methods.
-    virtual unsigned long long size() const { return m_data.length(); }
-    virtual const StringBlobItem* toStringBlobItem() const { return this; }
-
-    // DataBlobItem methods.
-    virtual const char* data() const { return m_data.data(); }
-
-private:
-    StringBlobItem(const CString&);
-    CString m_data;
-};
-
-class ByteArrayBlobItem : public DataBlobItem {
-public:
-    static PassRefPtr<BlobItem> create(const char* data, size_t size);
-
-    // BlobItem methods.
-    virtual unsigned long long size() const { return m_bytesArray.size(); }
-    virtual const ByteArrayBlobItem* toByteArrayBlobItem() const { return this; }
-
-    // DataBlobItem methods.
-    virtual const char* data() const { return m_bytesArray.data(); }
-
-private:
-    ByteArrayBlobItem(const char* data, size_t size);
-    Vector<char> m_bytesArray;
-};
-
-#if ENABLE(BLOB)
-
-// BlobItem class for sliced data (string or bytes-array).
-class DataRangeBlobItem : public DataBlobItem {
-public:
-    static PassRefPtr<BlobItem> create(PassRefPtr<DataBlobItem>, long long start, long long length);
-
-    // BlobItem methods.
-    virtual unsigned long long size() const { return m_length; }
-    virtual const DataRangeBlobItem* toDataRangeBlobItem() const { return this; }
-
-    // DataBlobItem methods.
-    virtual const char* data() const;
-
-private:
-    DataRangeBlobItem(PassRefPtr<DataBlobItem>, long long start, long long length);
-    RefPtr<DataBlobItem> m_item;
-    long long m_start;
-    long long m_length;
-};
-
-class FileRangeBlobItem : public FileBlobItem {
-public:
-    static PassRefPtr<BlobItem> create(const String& path, long long start, long long length, double snapshotModificationTime);
-    long long start() const { return m_start; }
-    double snapshotModificationTime() const { return m_snapshotModificationTime; }
-
-    // BlobItem methods.
-    virtual unsigned long long size() const { return m_length; }
-    virtual const FileRangeBlobItem* toFileRangeBlobItem() const { return this; }
-
-    // FileBlobItem methods.
-    virtual const String& name() const { return m_uniqueName; }
-
-private:
-    FileRangeBlobItem(const String& path, long long start, long long length, double snapshotModificationTime);
-    long long m_start;
-    long long m_length;
-    String m_uniqueName;
-
-    double m_snapshotModificationTime;
-};
-
-#endif // ENABLE(BLOB)
-
-} // namespace WebCore
-
-#endif // BlobItem_h
diff --git a/WebCore/platform/network/BlobRegistryImpl.cpp b/WebCore/platform/network/BlobRegistryImpl.cpp
index ee872e6..fe1b09f 100644
--- a/WebCore/platform/network/BlobRegistryImpl.cpp
+++ b/WebCore/platform/network/BlobRegistryImpl.cpp
@@ -32,6 +32,7 @@
 
 #include "BlobRegistryImpl.h"
 
+#include "BlobResourceHandle.h"
 #include "ResourceError.h"
 #include "ResourceHandle.h"
 #include "ResourceLoader.h"
@@ -60,22 +61,21 @@ bool BlobRegistryImpl::shouldLoadResource(const ResourceRequest& request) const
     return true;
 }
 
-PassRefPtr<ResourceHandle> BlobRegistryImpl::createResourceHandle(const ResourceRequest& request, ResourceHandleClient*)
+PassRefPtr<ResourceHandle> BlobRegistryImpl::createResourceHandle(const ResourceRequest& request, ResourceHandleClient* client)
 {
     if (!shouldLoadResource(request))
         return 0;
 
-    // FIXME: To be implemented.
-    return 0;
+    return BlobResourceHandle::create(m_blobs.get(request.url().string()), request, client);
 }
 
-bool BlobRegistryImpl::loadResourceSynchronously(const ResourceRequest& request, ResourceError&, ResourceResponse&, Vector<char>&)
+bool BlobRegistryImpl::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
 {
     if (!shouldLoadResource(request))
         return false;
 
-    // FIXME: To be implemented.
-    return false;
+    BlobResourceHandle::loadResourceSynchronously(m_blobs.get(request.url().string()), request, error, response, data);
+    return true;
 }
 
 void BlobRegistryImpl::appendStorageItems(BlobStorageData* blobStorageData, const BlobDataItemList& items)
diff --git a/WebCore/platform/network/BlobResourceHandle.cpp b/WebCore/platform/network/BlobResourceHandle.cpp
index 63335f6..8767b55 100644
--- a/WebCore/platform/network/BlobResourceHandle.cpp
+++ b/WebCore/platform/network/BlobResourceHandle.cpp
@@ -159,7 +159,8 @@ BlobResourceHandle::BlobResourceHandle(PassRefPtr<BlobStorageData> blobData, con
     , m_fileOpened(false)
 {    
     if (m_async) {
-        m_asyncStream = adoptRef(client->createAsyncFileStream(this));
+        // We need to take a ref.
+        m_asyncStream = client->createAsyncFileStream(this);
         callOnMainThread(delayedStart, this);
     } else
         m_stream = FileStream::create();
diff --git a/WebCore/platform/network/FormData.cpp b/WebCore/platform/network/FormData.cpp
index 4f2b365..786f1b6 100644
--- a/WebCore/platform/network/FormData.cpp
+++ b/WebCore/platform/network/FormData.cpp
@@ -22,23 +22,21 @@
 
 #include "FormData.h"
 
-#include "BlobItem.h"
+#include "BlobData.h"
+#include "BlobURL.h"
 #include "Chrome.h"
 #include "ChromeClient.h"
 #include "Document.h"
+#include "File.h"
 #include "FileSystem.h"
 #include "FormDataBuilder.h"
+#include "FormDataList.h"
 #include "MIMETypeRegistry.h"
 #include "Page.h"
 #include "TextEncoding.h"
 
 namespace WebCore {
 
-#if ENABLE(BLOB)
-const long long FormDataElement::toEndOfFile = -1;
-const double FormDataElement::doNotCheckFileChange = 0;
-#endif
-
 inline FormData::FormData()
     : m_identifier(0)
     , m_hasGeneratedFiles(false)
@@ -99,17 +97,17 @@ PassRefPtr<FormData> FormData::create(const Vector<char>& vector)
     return result.release();
 }
 
-PassRefPtr<FormData> FormData::create(const BlobItemList& items, const TextEncoding& encoding)
+PassRefPtr<FormData> FormData::create(const FormDataList& list, const TextEncoding& encoding)
 {
     RefPtr<FormData> result = create();
-    result->appendKeyValuePairItems(items, encoding, false, 0);
+    result->appendKeyValuePairItems(list, encoding, false, 0);
     return result.release();
 }
 
-PassRefPtr<FormData> FormData::createMultiPart(const BlobItemList& items, const TextEncoding& encoding, Document* document)
+PassRefPtr<FormData> FormData::createMultiPart(const FormDataList& list, const TextEncoding& encoding, Document* document)
 {
     RefPtr<FormData> result = create();
-    result->appendKeyValuePairItems(items, encoding, true, document);
+    result->appendKeyValuePairItems(list, encoding, true, document);
     return result.release();
 }
 
@@ -162,44 +160,12 @@ void FormData::appendData(const void* data, size_t size)
 void FormData::appendFile(const String& filename, bool shouldGenerateFile)
 {
 #if ENABLE(BLOB)
-    m_elements.append(FormDataElement(filename, 0, FormDataElement::toEndOfFile, FormDataElement::doNotCheckFileChange, shouldGenerateFile));
+    m_elements.append(FormDataElement(filename, 0, BlobDataItem::toEndOfFile, BlobDataItem::doNotCheckFileChange, shouldGenerateFile));
 #else
     m_elements.append(FormDataElement(filename, shouldGenerateFile));
 #endif
 }
 
-void FormData::appendItems(const BlobItemList& items)
-{
-    for (BlobItemList::const_iterator iter(items.begin()); iter != items.end(); ++iter)
-        appendItem(iter->get(), false);
-}
-
-void FormData::appendItem(const BlobItem* item, bool shouldGenerateFile)
-{
-    const DataBlobItem* dataItem = item->toDataBlobItem();
-    if (dataItem) {
-        appendData(dataItem->data(), static_cast<size_t>(dataItem->size()));
-        return;
-    }
-
-    const FileBlobItem* fileItem = item->toFileBlobItem();
-    ASSERT(fileItem);
-    if (fileItem->path().isEmpty()) {
-        // If the path is empty do not add the item.
-        return;
-    }
-
-#if ENABLE(BLOB)
-    const FileRangeBlobItem* fileRangeItem = item->toFileRangeBlobItem();
-    if (fileRangeItem) {
-        appendFileRange(fileItem->path(), fileRangeItem->start(), fileRangeItem->size(), fileRangeItem->snapshotModificationTime(), shouldGenerateFile);
-        return;
-    }
-#endif
-
-    appendFile(fileItem->path(), shouldGenerateFile);
-}
-
 #if ENABLE(BLOB)
 void FormData::appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile)
 {
@@ -212,80 +178,82 @@ void FormData::appendBlob(const KURL& blobURL)
 }
 #endif
 
-void FormData::appendKeyValuePairItems(const BlobItemList& items, const TextEncoding& encoding, bool isMultiPartForm, Document* document)
+void FormData::appendKeyValuePairItems(const FormDataList& list, const TextEncoding& encoding, bool isMultiPartForm, Document* document)
 {
     if (isMultiPartForm)
         m_boundary = FormDataBuilder::generateUniqueBoundaryString();
 
     Vector<char> encodedData;
 
+    const Vector<FormDataList::Item>& items = list.items();
     size_t formDataListSize = items.size();
     ASSERT(!(formDataListSize % 2));
     for (size_t i = 0; i < formDataListSize; i += 2) {
-        const StringBlobItem* key = items[i]->toStringBlobItem();
-        const BlobItem* value = items[i + 1].get();
-        ASSERT(key);
+        const FormDataList::Item& key = items[i];
+        const FormDataList::Item& value = items[i + 1];
         if (isMultiPartForm) {
             Vector<char> header;
-            FormDataBuilder::beginMultiPartHeader(header, m_boundary.data(), key->cstr());
+            FormDataBuilder::beginMultiPartHeader(header, m_boundary.data(), key.data());
 
             bool shouldGenerateFile = false;
-            // If the current type is FILE, then we also need to include the filename
-            const FileBlobItem* fileItem = value->toFileBlobItem();
-            if (fileItem) {
-                const String& path = fileItem->path();
 
-#if ENABLE(DIRECTORY_UPLOAD)
-                String fileName = !fileItem->relativePath().isEmpty() ? fileItem->relativePath() : fileItem->name();
+            // If the current type is blob, then we also need to include the filename
+            if (value.blob()) {
+                String name;
+                if (value.blob()->isFile()) {
+                    // For file blob, use the filename (or relative path if it is present) as the name.
+                    File* file = static_cast<File*>(value.blob());
+#if ENABLE(DIRECTORY_UPLOAD)                
+                    name = file->webkitRelativePath().isEmpty() ? file->name() : file->webkitRelativePath();
 #else
-                String fileName = fileItem->name();
-#endif
+                    name = file->name();
+#endif                    
 
-                // Let the application specify a filename if it's going to generate a replacement file for the upload.
-                if (!path.isEmpty()) {
+                    // Let the application specify a filename if it's going to generate a replacement file for the upload.
                     if (Page* page = document->page()) {
                         String generatedFileName;
-                        shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(path, generatedFileName);
+                        shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(file->path(), generatedFileName);
                         if (shouldGenerateFile)
-                            fileName = generatedFileName;
+                            name = generatedFileName;
                     }
+                } else {
+                    // For non-file blob, use the identifier part of the URL as the name.
+                    name = "Blob" + BlobURL::getIdentifier(value.blob()->url());
+                    name = name.replace("-", ""); // For safety, remove '-' from the filename since some servers may not like it.
                 }
 
                 // We have to include the filename=".." part in the header, even if the filename is empty
-                FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, fileName);
+                FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, name);
 
-                // If the item is sliced from a file, do not add the content type.
-#if ENABLE(BLOB)
-                if (!fileName.isEmpty() && !value->toFileRangeBlobItem()) {
-#else
-                if (!fileName.isEmpty()) {
-#endif
-                    // FIXME: The MIMETypeRegistry function's name makes it sound like it takes a path,
-                    // not just a basename. But filename is not the path. But note that it's not safe to
-                    // just use path instead since in the generated-file case it will not reflect the
-                    // MIME type of the generated file.
-                    String mimeType = MIMETypeRegistry::getMIMETypeForPath(fileName);
-                    if (!mimeType.isEmpty())
-                        FormDataBuilder::addContentTypeToMultiPartHeader(header, mimeType.latin1());
-                }
+                // Add the content type if it is available.
+                if (value.blob()->type().isEmpty())
+                    FormDataBuilder::addContentTypeToMultiPartHeader(header, value.blob()->type().latin1());
             }
 
             FormDataBuilder::finishMultiPartHeader(header);
 
             // Append body
             appendData(header.data(), header.size());
-            appendItem(value, shouldGenerateFile);
+            if (value.blob()) {
+                if (value.blob()->isFile()) {
+                    // Do not add the file if the path is empty.
+                    if (!static_cast<File*>(value.blob())->path().isEmpty())
+                        appendFile(static_cast<File*>(value.blob())->path(), shouldGenerateFile);
+                }
+#if ENABLE(BLOB)
+                else
+                    appendBlob(value.blob()->url());
+#endif
+            } else
+                appendData(value.data().data(), value.data().length());
             appendData("\r\n", 2);
         } else {
             // Omit the name "isindex" if it's the first form data element.
             // FIXME: Why is this a good rule? Is this obsolete now?
-            const StringBlobItem* stringValue = value->toStringBlobItem();
-            if (!stringValue)
-                continue;
-            if (encodedData.isEmpty() && key->cstr() == "isindex")
-                FormDataBuilder::encodeStringAsFormData(encodedData, stringValue->cstr());
+            if (encodedData.isEmpty() && key.data() == "isindex")
+                FormDataBuilder::encodeStringAsFormData(encodedData, value.data());
             else
-                FormDataBuilder::addKeyValuePairAsFormData(encodedData, key->cstr(), stringValue->cstr());
+                FormDataBuilder::addKeyValuePairAsFormData(encodedData, key.data(), value.data());
         }
     }
 
diff --git a/WebCore/platform/network/FormData.h b/WebCore/platform/network/FormData.h
index d7faa89..22ceb25 100644
--- a/WebCore/platform/network/FormData.h
+++ b/WebCore/platform/network/FormData.h
@@ -28,10 +28,9 @@
 
 namespace WebCore {
 
-class BlobItem;
 class Document;
+class FormDataList;
 class TextEncoding;
-typedef Vector<RefPtr<BlobItem> > BlobItemList;
 
 class FormDataElement {
 public:
@@ -62,11 +61,6 @@ public:
 #endif
     String m_generatedFilename;
     bool m_shouldGenerateFile;
-
-#if ENABLE(BLOB)
-    static const long long toEndOfFile;
-    static const double doNotCheckFileChange;
-#endif
 };
 
 inline bool operator==(const FormDataElement& a, const FormDataElement& b)
@@ -101,15 +95,14 @@ public:
     static PassRefPtr<FormData> create(const void*, size_t);
     static PassRefPtr<FormData> create(const CString&);
     static PassRefPtr<FormData> create(const Vector<char>&);
-    static PassRefPtr<FormData> create(const BlobItemList&, const TextEncoding&);
-    static PassRefPtr<FormData> createMultiPart(const BlobItemList&, const TextEncoding&, Document*);
+    static PassRefPtr<FormData> create(const FormDataList&, const TextEncoding&);
+    static PassRefPtr<FormData> createMultiPart(const FormDataList&, const TextEncoding&, Document*);
     PassRefPtr<FormData> copy() const;
     PassRefPtr<FormData> deepCopy() const;
     ~FormData();
 
     void appendData(const void* data, size_t);
-    void appendItems(const BlobItemList&);
-    void appendFile(const String& filename, bool shouldGenerateFile = false);
+    void appendFile(const String& filePath, bool shouldGenerateFile = false);
 #if ENABLE(BLOB)
     void appendFileRange(const String& filename, long long start, long long length, double expectedModificationTime, bool shouldGenerateFile = false);
     void appendBlob(const KURL& blobURL);
@@ -137,8 +130,7 @@ private:
     FormData();
     FormData(const FormData&);
 
-    void appendItem(const BlobItem*, bool shouldGenerateFile);
-    void appendKeyValuePairItems(const BlobItemList&, const TextEncoding&, bool isMultiPartForm, Document*);
+    void appendKeyValuePairItems(const FormDataList&, const TextEncoding&, bool isMultiPartForm, Document*);
 
     Vector<FormDataElement> m_elements;
 
diff --git a/WebCore/platform/network/mac/FormDataStreamMac.mm b/WebCore/platform/network/mac/FormDataStreamMac.mm
index c7bd2e7..ed98356 100644
--- a/WebCore/platform/network/mac/FormDataStreamMac.mm
+++ b/WebCore/platform/network/mac/FormDataStreamMac.mm
@@ -31,6 +31,7 @@
 #import "config.h"
 #import "FormDataStreamMac.h"
 
+#import "BlobRegistryImpl.h"
 #import "FileSystem.h"
 #import "FormData.h"
 #import "ResourceHandle.h"
@@ -141,7 +142,7 @@ static void closeCurrentStream(FormStreamFields *form)
         CFRelease(form->currentStream);
         form->currentStream = NULL;
 #if ENABLE(BLOB)
-        form->currentStreamRangeLength = FormDataElement::toEndOfFile;
+        form->currentStreamRangeLength = BlobDataItem::toEndOfFile;
 #endif
     }
     if (form->currentData) {
@@ -169,7 +170,7 @@ static bool advanceCurrentStream(FormStreamFields* form)
     } else {
 #if ENABLE(BLOB)
         // Check if the file has been changed or not if required.
-        if (nextInput.m_expectedFileModificationTime != FormDataElement::doNotCheckFileChange) {
+        if (nextInput.m_expectedFileModificationTime != BlobDataItem::doNotCheckFileChange) {
             time_t fileModificationTime;
             if (!getFileModificationTime(nextInput.m_filename, fileModificationTime) || fileModificationTime != static_cast<time_t>(nextInput.m_expectedFileModificationTime))
                 return false;
@@ -225,7 +226,7 @@ static void* formCreate(CFReadStreamRef stream, void* context)
     FormStreamFields* newInfo = new FormStreamFields;
     newInfo->currentStream = NULL;
 #if ENABLE(BLOB)
-    newInfo->currentStreamRangeLength = FormDataElement::toEndOfFile;
+    newInfo->currentStreamRangeLength = BlobDataItem::toEndOfFile;
 #endif
     newInfo->currentData = 0;
     newInfo->formStream = stream; // Don't retain. That would create a reference cycle.
@@ -273,7 +274,7 @@ static CFIndex formRead(CFReadStreamRef stream, UInt8* buffer, CFIndex bufferLen
     while (form->currentStream) {
         CFIndex bytesToRead = bufferLength;
 #if ENABLE(BLOB)
-        if (form->currentStreamRangeLength != FormDataElement::toEndOfFile && form->currentStreamRangeLength < bytesToRead)
+        if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile && form->currentStreamRangeLength < bytesToRead)
             bytesToRead = static_cast<CFIndex>(form->currentStreamRangeLength);
 #endif
         CFIndex bytesRead = CFReadStreamRead(form->currentStream, buffer, bytesToRead);
@@ -286,7 +287,7 @@ static CFIndex formRead(CFReadStreamRef stream, UInt8* buffer, CFIndex bufferLen
             *atEOF = FALSE;
             form->bytesSent += bytesRead;
 #if ENABLE(BLOB)
-            if (form->currentStreamRangeLength != FormDataElement::toEndOfFile)
+            if (form->currentStreamRangeLength != BlobDataItem::toEndOfFile)
                 form->currentStreamRangeLength -= bytesRead;
 #endif
 
@@ -394,6 +395,49 @@ void setHTTPBody(NSMutableURLRequest *request, PassRefPtr<FormData> formData)
         }
     }
 
+#if ENABLE(BLOB)
+    // Check if there is a blob in the form data.
+    bool hasBlob = false;
+    for (size_t i = 0; i < count; ++i) {
+        const FormDataElement& element = formData->elements()[i];
+        if (element.m_type == FormDataElement::encodedBlob) {
+            hasBlob = true;
+            break;
+        }
+    }
+
+    // If yes, we have to resolve all the blob references and regenerate the form data with only data and file types.
+    if (hasBlob) {
+        RefPtr<FormData> newFormData = FormData::create();
+        newFormData->setAlwaysStream(formData->alwaysStream());
+        newFormData->setIdentifier(formData->identifier());
+        for (size_t i = 0; i < count; ++i) {
+            const FormDataElement& element = formData->elements()[i];
+            if (element.m_type == FormDataElement::data)
+                newFormData->appendData(element.m_data.data(), element.m_data.size());
+            else if (element.m_type == FormDataElement::encodedFile)
+                newFormData->appendFile(element.m_filename, element.m_shouldGenerateFile);
+            else {
+                ASSERT(element.m_type == FormDataElement::encodedBlob);
+                RefPtr<BlobStorageData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(KURL(ParsedURLString, element.m_blobURL));
+                if (blobData) {
+                    for (size_t j = 0; j < blobData->items().size(); ++j) {
+                        const BlobDataItem& blobItem = blobData->items()[j];
+                        if (blobItem.type == BlobDataItem::Data) {
+                            newFormData->appendData(blobItem.data.data() + static_cast<int>(blobItem.offset), static_cast<int>(blobItem.length));
+                        } else {
+                            ASSERT(blobItem.type == BlobDataItem::File);
+                            newFormData->appendFileRange(blobItem.path, blobItem.offset, blobItem.length, blobItem.expectedModificationTime);
+                        }
+                    }
+                }
+            }
+        }
+        formData = newFormData;
+        count = formData->elements().size();
+    }
+#endif
+
     // Precompute the content length so NSURLConnection doesn't use chunked mode.
     long long length = 0;
     for (size_t i = 0; i < count; ++i) {
@@ -403,7 +447,7 @@ void setHTTPBody(NSMutableURLRequest *request, PassRefPtr<FormData> formData)
         else {
 #if ENABLE(BLOB)
             // If we're sending the file range, use the existing range length for now. We will detect if the file has been changed right before we read the file and abort the operation if necessary.
-            if (element.m_fileLength != FormDataElement::toEndOfFile) {
+            if (element.m_fileLength != BlobDataItem::toEndOfFile) {
                 length += element.m_fileLength;
                 continue;
             }
diff --git a/WebCore/xml/XMLHttpRequest.cpp b/WebCore/xml/XMLHttpRequest.cpp
index c12dc16..f3b8d64 100644
--- a/WebCore/xml/XMLHttpRequest.cpp
+++ b/WebCore/xml/XMLHttpRequest.cpp
@@ -522,7 +522,7 @@ void XMLHttpRequest::send(Blob* body, ExceptionCode& ec)
         // FIXME: Should we set a Content-Type if one is not set.
         // FIXME: add support for uploading bundles.
         m_requestEntityBody = FormData::create();
-        m_requestEntityBody->appendItems(body->items());
+        m_requestEntityBody->appendBlob(body->url());
     }
 
     createRequest(ec);
@@ -534,7 +534,7 @@ void XMLHttpRequest::send(DOMFormData* body, ExceptionCode& ec)
         return;
 
     if (m_method != "GET" && m_method != "HEAD" && m_url.protocolInHTTPFamily()) {
-        m_requestEntityBody = FormData::createMultiPart(body->items(), body->encoding(), document());
+        m_requestEntityBody = FormData::createMultiPart(*(static_cast<FormDataList*>(body)), body->encoding(), document());
 
         // We need to ask the client to provide the generated file names if needed. When FormData fills the element
         // for the file, it could set a flag to use the generated file name, i.e. a package file on Mac.
diff --git a/WebKit/chromium/ChangeLog b/WebKit/chromium/ChangeLog
index 21454e8..fe8935d 100644
--- a/WebKit/chromium/ChangeLog
+++ b/WebKit/chromium/ChangeLog
@@ -1,3 +1,13 @@
+2010-08-31  Jian Li  <jianli at chromium.org>
+
+        Reviewed by Darin Fisher.
+
+        Switch the Blob implementation to using the blob data registration model
+        https://bugs.webkit.org/show_bug.cgi?id=44389
+
+        * src/WebSearchableFormData.cpp:
+        (WebCore::HasSuitableTextElement):
+
 2010-08-30  Nat Duca  <nduca at chromium.org>
 
         Reviewed by Adam Barth.
diff --git a/WebKit/chromium/src/WebSearchableFormData.cpp b/WebKit/chromium/src/WebSearchableFormData.cpp
index 14ece13..1864514 100644
--- a/WebKit/chromium/src/WebSearchableFormData.cpp
+++ b/WebKit/chromium/src/WebSearchableFormData.cpp
@@ -187,7 +187,7 @@ bool HasSuitableTextElement(const HTMLFormElement* form, Vector<char>* encodedSt
       if (!formElement->appendFormData(dataList, false))
           continue;
 
-      const BlobItemList& items = dataList.items();
+      const Vector<FormDataList::Item>& items = dataList.items();
       if (isTextElement && !items.isEmpty()) {
           if (textElement) {
               // The auto-complete bar only knows how to fill in one value.
@@ -196,22 +196,20 @@ bool HasSuitableTextElement(const HTMLFormElement* form, Vector<char>* encodedSt
           }
           textElement = static_cast<HTMLInputElement*>(formElement);
       }
-      for (BlobItemList::const_iterator j(items.begin()); j != items.end(); ++j) {
-          const StringBlobItem* item = (*j)->toStringBlobItem();
-          ASSERT(item);
+      for (Vector<FormDataList::Item>::const_iterator j(items.begin()); j != items.end(); ++j) {
           // Handle ISINDEX / <input name=isindex> specially, but only if it's
           // the first entry.
-          if (!encodedString->isEmpty() || item->cstr() != "isindex") {
+          if (!encodedString->isEmpty() || j->data() != "isindex") {
               if (!encodedString->isEmpty())
                   encodedString->append('&');
-              FormDataBuilder::encodeStringAsFormData(*encodedString, item->cstr());
+              FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
               encodedString->append('=');
           }
           ++j;
           if (formElement == textElement)
               encodedString->append("{searchTerms}", 13);
           else
-              FormDataBuilder::encodeStringAsFormData(*encodedString, item->cstr());
+              FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
       }
     }
 

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list