Commit 3633063d authored by hirono@chromium.org's avatar hirono@chromium.org

Pass the selected non-native file information from the browser to FileInputType.

Previously the blink accepts only native files as a result value of the file
chooser. The information is conveyed to the FileInputType. Then FileInputType
generates the File class instances from the information, and the instances are
used to compose the form request.

Thic CL adds non-native file support to the above code path.

* Adds noo-native file information (file system URL and metadata) to structures
  representing selected file (FileChooserFileInfo, SelectedFileInfo).

* When FileInputType generates the File class instances, let the class refer the
  non-native file information.

* When FileInputType checks the change of selected files, let the class refer
  the non-native file information.

BUG=126902
TEST=None

Review URL: https://codereview.chromium.org/640723006

git-svn-id: svn://svn.chromium.org/blink/trunk@183960 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 51315a84
...@@ -3594,6 +3594,7 @@ ...@@ -3594,6 +3594,7 @@
'html/HTMLTextFormControlElementTest.cpp', 'html/HTMLTextFormControlElementTest.cpp',
'html/LinkRelAttributeTest.cpp', 'html/LinkRelAttributeTest.cpp',
'html/TimeRangesTest.cpp', 'html/TimeRangesTest.cpp',
'html/forms/FileInputTypeTest.cpp',
'html/parser/HTMLParserThreadTest.cpp', 'html/parser/HTMLParserThreadTest.cpp',
'html/parser/HTMLSrcsetParserTest.cpp', 'html/parser/HTMLSrcsetParserTest.cpp',
'html/track/vtt/BufferedLineReaderTest.cpp', 'html/track/vtt/BufferedLineReaderTest.cpp',
......
...@@ -296,4 +296,21 @@ void File::appendTo(BlobData& blobData) const ...@@ -296,4 +296,21 @@ void File::appendTo(BlobData& blobData) const
blobData.appendFile(m_path, 0, size, modificationTime); blobData.appendFile(m_path, 0, size, modificationTime);
} }
bool File::hasSameSource(const File& other) const
{
if (m_hasBackingFile != other.m_hasBackingFile)
return false;
if (m_hasBackingFile)
return m_path == other.m_path;
if (m_fileSystemURL.isEmpty() != other.m_fileSystemURL.isEmpty())
return false;
if (!m_fileSystemURL.isEmpty())
return m_fileSystemURL == other.m_fileSystemURL;
return uuid() == other.uuid();
}
} // namespace blink } // namespace blink
...@@ -135,6 +135,9 @@ public: ...@@ -135,6 +135,9 @@ public:
// Returns true if this has a valid snapshot metadata (i.e. m_snapshotSize >= 0). // Returns true if this has a valid snapshot metadata (i.e. m_snapshotSize >= 0).
bool hasValidSnapshotMetadata() const { return m_snapshotSize >= 0; } bool hasValidSnapshotMetadata() const { return m_snapshotSize >= 0; }
// Returns true if the sources (file path, file system URL, or blob handler) of the file objects are same or not.
bool hasSameSource(const File& other) const;
private: private:
File(const String& path, ContentTypeLookupPolicy, UserVisibility); File(const String& path, ContentTypeLookupPolicy, UserVisibility);
File(const String& path, const String& name, ContentTypeLookupPolicy, UserVisibility); File(const String& path, const String& name, ContentTypeLookupPolicy, UserVisibility);
......
...@@ -46,4 +46,40 @@ TEST(FileTest, fileSystemFileWithoutNativeSnapshot) ...@@ -46,4 +46,40 @@ TEST(FileTest, fileSystemFileWithoutNativeSnapshot)
EXPECT_EQ(url, file->fileSystemURL()); EXPECT_EQ(url, file->fileSystemURL());
} }
TEST(FileTest, hsaSameSource)
{
File* const nativeFileA1 = File::create("/native/pathA");
File* const nativeFileA2 = File::create("/native/pathA");
File* const nativeFileB = File::create("/native/pathB");
const RefPtr<BlobDataHandle> blobDataA = BlobDataHandle::create();
const RefPtr<BlobDataHandle> blobDataB = BlobDataHandle::create();
File* const blobFileA1 = File::create("name", 0.0, blobDataA);
File* const blobFileA2 = File::create("name", 0.0, blobDataA);
File* const blobFileB = File::create("name", 0.0, blobDataB);
KURL urlA(ParsedURLStringTag(), "filesystem:http://example.com/isolated/hash/non-native-file-A");
KURL urlB(ParsedURLStringTag(), "filesystem:http://example.com/isolated/hash/non-native-file-B");
FileMetadata metadata;
File* const fileSystemFileA1 = File::createForFileSystemFile(urlA, metadata);
File* const fileSystemFileA2 = File::createForFileSystemFile(urlA, metadata);
File* const fileSystemFileB = File::createForFileSystemFile(urlB, metadata);
EXPECT_FALSE(nativeFileA1->hasSameSource(*blobFileA1));
EXPECT_FALSE(blobFileA1->hasSameSource(*fileSystemFileA1));
EXPECT_FALSE(fileSystemFileA1->hasSameSource(*nativeFileA1));
EXPECT_TRUE(nativeFileA1->hasSameSource(*nativeFileA1));
EXPECT_TRUE(nativeFileA1->hasSameSource(*nativeFileA2));
EXPECT_FALSE(nativeFileA1->hasSameSource(*nativeFileB));
EXPECT_TRUE(blobFileA1->hasSameSource(*blobFileA1));
EXPECT_TRUE(blobFileA1->hasSameSource(*blobFileA2));
EXPECT_FALSE(blobFileA1->hasSameSource(*blobFileB));
EXPECT_TRUE(fileSystemFileA1->hasSameSource(*fileSystemFileA1));
EXPECT_TRUE(fileSystemFileA1->hasSameSource(*fileSystemFileA2));
EXPECT_FALSE(fileSystemFileA1->hasSameSource(*fileSystemFileB));
}
} // namespace blink } // namespace blink
...@@ -217,7 +217,7 @@ void FileInputType::setValue(const String&, bool valueChanged, TextFieldEventBeh ...@@ -217,7 +217,7 @@ void FileInputType::setValue(const String&, bool valueChanged, TextFieldEventBeh
element().setNeedsValidityCheck(); element().setNeedsValidityCheck();
} }
FileList* FileInputType::createFileList(const Vector<FileChooserFileInfo>& files) const FileList* FileInputType::createFileList(const Vector<FileChooserFileInfo>& files, bool hasWebkitDirectoryAttr)
{ {
FileList* fileList(FileList::create()); FileList* fileList(FileList::create());
size_t size = files.size(); size_t size = files.size();
...@@ -225,10 +225,10 @@ FileList* FileInputType::createFileList(const Vector<FileChooserFileInfo>& files ...@@ -225,10 +225,10 @@ FileList* FileInputType::createFileList(const Vector<FileChooserFileInfo>& files
// If a directory is being selected, the UI allows a directory to be chosen // If a directory is being selected, the UI allows a directory to be chosen
// and the paths provided here share a root directory somewhere up the tree; // and the paths provided here share a root directory somewhere up the tree;
// we want to store only the relative paths from that point. // we want to store only the relative paths from that point.
if (size && element().fastHasAttribute(webkitdirectoryAttr)) { if (size && hasWebkitDirectoryAttr) {
// Find the common root path. // Find the common root path.
String rootPath = directoryName(files[0].path); String rootPath = directoryName(files[0].path);
for (size_t i = 1; i < size; i++) { for (size_t i = 1; i < size; ++i) {
while (!files[i].path.startsWith(rootPath)) while (!files[i].path.startsWith(rootPath))
rootPath = directoryName(rootPath); rootPath = directoryName(rootPath);
} }
...@@ -237,7 +237,7 @@ FileList* FileInputType::createFileList(const Vector<FileChooserFileInfo>& files ...@@ -237,7 +237,7 @@ FileList* FileInputType::createFileList(const Vector<FileChooserFileInfo>& files
int rootLength = rootPath.length(); int rootLength = rootPath.length();
if (rootPath[rootLength - 1] != '\\' && rootPath[rootLength - 1] != '/') if (rootPath[rootLength - 1] != '\\' && rootPath[rootLength - 1] != '/')
rootLength += 1; rootLength += 1;
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; ++i) {
// Normalize backslashes to slashes before exposing the relative path to script. // Normalize backslashes to slashes before exposing the relative path to script.
String relativePath = files[i].path.substring(rootLength).replace('\\', '/'); String relativePath = files[i].path.substring(rootLength).replace('\\', '/');
fileList->append(File::createWithRelativePath(files[i].path, relativePath)); fileList->append(File::createWithRelativePath(files[i].path, relativePath));
...@@ -245,8 +245,13 @@ FileList* FileInputType::createFileList(const Vector<FileChooserFileInfo>& files ...@@ -245,8 +245,13 @@ FileList* FileInputType::createFileList(const Vector<FileChooserFileInfo>& files
return fileList; return fileList;
} }
for (size_t i = 0; i < size; i++) for (size_t i = 0; i < size; ++i) {
if (files[i].fileSystemURL.isEmpty()) {
fileList->append(File::createForUserProvidedFile(files[i].path, files[i].displayName)); fileList->append(File::createForUserProvidedFile(files[i].path, files[i].displayName));
} else {
fileList->append(File::createForFileSystemFile(files[i].fileSystemURL, files[i].metadata));
}
}
return fileList; return fileList;
} }
...@@ -281,13 +286,13 @@ void FileInputType::setFiles(FileList* files) ...@@ -281,13 +286,13 @@ void FileInputType::setFiles(FileList* files)
RefPtrWillBeRawPtr<HTMLInputElement> input(element()); RefPtrWillBeRawPtr<HTMLInputElement> input(element());
bool pathsChanged = false; bool filesChanged = false;
if (files->length() != m_fileList->length()) { if (files->length() != m_fileList->length()) {
pathsChanged = true; filesChanged = true;
} else { } else {
for (unsigned i = 0; i < files->length(); ++i) { for (unsigned i = 0; i < files->length(); ++i) {
if (files->item(i)->path() != m_fileList->item(i)->path()) { if (!files->item(i)->hasSameSource(*m_fileList->item(i))) {
pathsChanged = true; filesChanged = true;
break; break;
} }
} }
...@@ -301,7 +306,7 @@ void FileInputType::setFiles(FileList* files) ...@@ -301,7 +306,7 @@ void FileInputType::setFiles(FileList* files)
if (input->renderer()) if (input->renderer())
input->renderer()->setShouldDoFullPaintInvalidation(); input->renderer()->setShouldDoFullPaintInvalidation();
if (pathsChanged) { if (filesChanged) {
// This call may cause destruction of this instance. // This call may cause destruction of this instance.
// input instance is safe since it is ref-counted. // input instance is safe since it is ref-counted.
input->dispatchChangeEvent(); input->dispatchChangeEvent();
...@@ -311,7 +316,7 @@ void FileInputType::setFiles(FileList* files) ...@@ -311,7 +316,7 @@ void FileInputType::setFiles(FileList* files)
void FileInputType::filesChosen(const Vector<FileChooserFileInfo>& files) void FileInputType::filesChosen(const Vector<FileChooserFileInfo>& files)
{ {
setFiles(createFileList(files)); setFiles(createFileList(files, element().fastHasAttribute(webkitdirectoryAttr)));
} }
void FileInputType::receiveDropForDirectoryUpload(const Vector<String>& paths) void FileInputType::receiveDropForDirectoryUpload(const Vector<String>& paths)
......
...@@ -47,6 +47,7 @@ public: ...@@ -47,6 +47,7 @@ public:
static PassRefPtrWillBeRawPtr<InputType> create(HTMLInputElement&); static PassRefPtrWillBeRawPtr<InputType> create(HTMLInputElement&);
virtual void trace(Visitor*) override; virtual void trace(Visitor*) override;
static Vector<FileChooserFileInfo> filesFromFormControlState(const FormControlState&); static Vector<FileChooserFileInfo> filesFromFormControlState(const FormControlState&);
static FileList* createFileList(const Vector<FileChooserFileInfo>& files, bool hasWebkitDirectoryAttr);
private: private:
FileInputType(HTMLInputElement&); FileInputType(HTMLInputElement&);
...@@ -74,7 +75,6 @@ private: ...@@ -74,7 +75,6 @@ private:
// FileChooserClient implementation. // FileChooserClient implementation.
virtual void filesChosen(const Vector<FileChooserFileInfo>&) override; virtual void filesChosen(const Vector<FileChooserFileInfo>&) override;
FileList* createFileList(const Vector<FileChooserFileInfo>& files) const;
void receiveDropForDirectoryUpload(const Vector<String>&); void receiveDropForDirectoryUpload(const Vector<String>&);
PersistentWillBeMember<FileList> m_fileList; PersistentWillBeMember<FileList> m_fileList;
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "config.h"
#include "FileInputType.h"
#include "core/fileapi/FileList.h"
#include <gtest/gtest.h>
namespace blink {
TEST(FileInputTypeTest, createFileList)
{
Vector<FileChooserFileInfo> files;
// Natvie file.
files.append(FileChooserFileInfo(
"/native/path/native-file",
"display-name"));
// Non-native file.
KURL url(ParsedURLStringTag(), "filesystem:http://example.com/isolated/hash/non-native-file");
FileMetadata metadata;
metadata.length = 64;
metadata.modificationTime = 24 * 60 * 60 /* sec */;
files.append(FileChooserFileInfo(url, metadata));
FileList* list = FileInputType::createFileList(files, false);
ASSERT_TRUE(list);
ASSERT_EQ(2u, list->length());
EXPECT_EQ("/native/path/native-file", list->item(0)->path());
EXPECT_EQ("display-name", list->item(0)->name());
EXPECT_TRUE(list->item(0)->fileSystemURL().isEmpty());
EXPECT_TRUE(list->item(1)->path().isEmpty());
EXPECT_EQ("non-native-file", list->item(1)->name());
EXPECT_EQ(url, list->item(1)->fileSystemURL());
EXPECT_EQ(64u, list->item(1)->size());
EXPECT_EQ(24 * 60 * 60 * 1000 /* ms */, list->item(1)->lastModified());
}
} // namespace blink
...@@ -30,7 +30,9 @@ ...@@ -30,7 +30,9 @@
#ifndef FileChooser_h #ifndef FileChooser_h
#define FileChooser_h #define FileChooser_h
#include "platform/FileMetadata.h"
#include "platform/PlatformExport.h" #include "platform/PlatformExport.h"
#include "platform/weborigin/KURL.h"
#include "wtf/RefCounted.h" #include "wtf/RefCounted.h"
#include "wtf/Vector.h" #include "wtf/Vector.h"
#include "wtf/text/WTFString.h" #include "wtf/text/WTFString.h"
...@@ -46,8 +48,17 @@ struct FileChooserFileInfo { ...@@ -46,8 +48,17 @@ struct FileChooserFileInfo {
{ {
} }
FileChooserFileInfo(const KURL& fileSystemURL, const FileMetadata metadata) : fileSystemURL(fileSystemURL), metadata(metadata)
{
}
// Members for native files.
const String path; const String path;
const String displayName; const String displayName;
// Members for file system API files.
const KURL fileSystemURL;
const FileMetadata metadata;
}; };
struct FileChooserSettings { struct FileChooserSettings {
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "config.h" #include "config.h"
#include "web/WebFileChooserCompletionImpl.h" #include "web/WebFileChooserCompletionImpl.h"
#include "platform/FileMetadata.h"
namespace blink { namespace blink {
...@@ -55,8 +56,17 @@ void WebFileChooserCompletionImpl::didChooseFile(const WebVector<WebString>& fil ...@@ -55,8 +56,17 @@ void WebFileChooserCompletionImpl::didChooseFile(const WebVector<WebString>& fil
void WebFileChooserCompletionImpl::didChooseFile(const WebVector<SelectedFileInfo>& files) void WebFileChooserCompletionImpl::didChooseFile(const WebVector<SelectedFileInfo>& files)
{ {
Vector<FileChooserFileInfo> fileInfo; Vector<FileChooserFileInfo> fileInfo;
for (size_t i = 0; i < files.size(); ++i) for (size_t i = 0; i < files.size(); ++i) {
if (files[i].fileSystemURL.isEmpty()) {
fileInfo.append(FileChooserFileInfo(files[i].path, files[i].displayName)); fileInfo.append(FileChooserFileInfo(files[i].path, files[i].displayName));
} else {
FileMetadata metadata;
metadata.modificationTime = files[i].modificationTime;
metadata.length = files[i].length;
metadata.type = files[i].isDirectory ? FileMetadata::TypeDirectory : FileMetadata::TypeFile;
fileInfo.append(FileChooserFileInfo(files[i].fileSystemURL, metadata));
}
}
m_fileChooser->chooseFiles(fileInfo); m_fileChooser->chooseFiles(fileInfo);
// This object is no longer needed. // This object is no longer needed.
delete this; delete this;
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#define WebFileChooserCompletion_h #define WebFileChooserCompletion_h
#include "../platform/WebString.h" #include "../platform/WebString.h"
#include "../platform/WebURL.h"
namespace blink { namespace blink {
...@@ -47,6 +48,22 @@ public: ...@@ -47,6 +48,22 @@ public:
// The display name of the file that is to be exposed as File.name in // The display name of the file that is to be exposed as File.name in
// the DOM layer. If it is empty the base part of the |path| is used. // the DOM layer. If it is empty the base part of the |path| is used.
WebString displayName; WebString displayName;
// File system URL.
WebURL fileSystemURL;
// Metadata of non-native file.
// 0 is Unix epoch, unit is sec.
double modificationTime;
long long length;
bool isDirectory;
SelectedFileInfo()
: modificationTime(0)
, length(0)
, isDirectory(false)
{
}
}; };
// Called with zero or more file names. Zero-lengthed vector means that // Called with zero or more file names. Zero-lengthed vector means that
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment