summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/generated_resources.grd13
-rw-r--r--chrome/browser/tab_contents/tab_contents_file_select_helper.cc77
-rw-r--r--chrome/browser/tab_contents/tab_contents_file_select_helper.h6
-rw-r--r--chrome/common/render_messages_params.cc6
-rw-r--r--chrome/common/render_messages_params.h4
-rw-r--r--chrome/renderer/render_view.cc1
-rw-r--r--net/base/mime_util.cc176
-rw-r--r--net/base/mime_util.h23
8 files changed, 304 insertions, 2 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 03d52c9..5b7d022 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -9503,6 +9503,19 @@ Keep your key file in a safe place. You will need it to create new versions of y
No audio recording devices found. Please check if you have a microphone properly connected before trying again.
</message>
+ <message name="IDS_IMAGE_FILES" desc="The description of the image file extensions in the select file dialog.">
+ Image Files
+ </message>
+ <message name="IDS_AUDIO_FILES" desc="The description of the audio file extensions in the select file dialog.">
+ Audio Files
+ </message>
+ <message name="IDS_VIDEO_FILES" desc="The description of the video file extensions in the select file dialog.">
+ Video Files
+ </message>
+ <message name="IDS_CUSTOM_FILES" desc="The description of the custom file extensions in the select file dialog.">
+ Custom Files
+ </message>
+
</messages>
<structures fallback_to_english="true">
diff --git a/chrome/browser/tab_contents/tab_contents_file_select_helper.cc b/chrome/browser/tab_contents/tab_contents_file_select_helper.cc
index bd042f2..b9a2953 100644
--- a/chrome/browser/tab_contents/tab_contents_file_select_helper.cc
+++ b/chrome/browser/tab_contents/tab_contents_file_select_helper.cc
@@ -4,13 +4,19 @@
#include "chrome/browser/tab_contents/tab_contents_file_select_helper.h"
+#include "app/l10n_util.h"
#include "base/file_util.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "net/base/mime_util.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/shell_dialogs.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/render_messages_params.h"
+#include "grit/generated_resources.h"
TabContentsFileSelectHelper::TabContentsFileSelectHelper(
TabContents* tab_contents)
@@ -88,6 +94,73 @@ void TabContentsFileSelectHelper::FileSelectionCanceled(void* params) {
GetRenderViewHost()->FilesSelectedInChooser(std::vector<FilePath>());
}
+SelectFileDialog::FileTypeInfo*
+TabContentsFileSelectHelper::GetFileTypesFromAcceptType(
+ const string16& accept_types) {
+ if (accept_types.empty())
+ return NULL;
+
+ // Split the accept-type string on commas.
+ std::vector<string16> mime_types;
+ base::SplitStringUsingSubstr(accept_types, ASCIIToUTF16(","), &mime_types);
+ if (mime_types.empty())
+ return NULL;
+
+ // Create FileTypeInfo and pre-allocate for the first extension list.
+ scoped_ptr<SelectFileDialog::FileTypeInfo> file_type(
+ new SelectFileDialog::FileTypeInfo());
+ file_type->include_all_files = true;
+ file_type->extensions.resize(1);
+ std::vector<FilePath::StringType>* extensions = &file_type->extensions.back();
+
+ // Find the correspondinge extensions.
+ int valid_type_count = 0;
+ int description_id = 0;
+ for (size_t i = 0; i < mime_types.size(); ++i) {
+ string16 mime_type = mime_types[i];
+ std::string ascii_mime_type = StringToLowerASCII(UTF16ToASCII(mime_type));
+
+ TrimWhitespace(ascii_mime_type, TRIM_ALL, &ascii_mime_type);
+ if (ascii_mime_type.empty())
+ continue;
+
+ size_t old_extension_size = extensions->size();
+ if (ascii_mime_type == "image/*") {
+ description_id = IDS_IMAGE_FILES;
+ net::GetImageExtensions(extensions);
+ } else if (ascii_mime_type == "audio/*") {
+ description_id = IDS_AUDIO_FILES;
+ net::GetAudioExtensions(extensions);
+ } else if (ascii_mime_type == "video/*") {
+ description_id = IDS_VIDEO_FILES;
+ net::GetVideoExtensions(extensions);
+ } else {
+ net::GetExtensionsForMimeType(ascii_mime_type, extensions);
+ }
+
+ if (extensions->size() > old_extension_size)
+ valid_type_count++;
+ }
+
+ // Use a generic description "Custom Files" if either of the following is
+ // true:
+ // 1) There're multiple types specified, like "audio/*,video/*"
+ // 2) There're multiple extensions for a MIME type without parameter, like
+ // "ehtml,shtml,htm,html" for "text/html". On Windows, the select file
+ // dialog uses the first extension in the list to form the description,
+ // like "EHTML Files". This is not what we want.
+ if (valid_type_count > 1 ||
+ (valid_type_count == 1 && description_id == 0 && extensions->size() > 1))
+ description_id = IDS_CUSTOM_FILES;
+
+ if (description_id) {
+ file_type->extension_description_overrides.push_back(
+ l10n_util::GetStringUTF16(description_id));
+ }
+
+ return file_type.release();
+}
+
void TabContentsFileSelectHelper::RunFileChooser(
const ViewHostMsg_RunFileChooser_Params &params) {
if (!select_file_dialog_.get())
@@ -110,6 +183,8 @@ void TabContentsFileSelectHelper::RunFileChooser(
dialog_type_ = SelectFileDialog::SELECT_OPEN_FILE; // Prevent warning.
NOTREACHED();
}
+ scoped_ptr<SelectFileDialog::FileTypeInfo> file_types(
+ GetFileTypesFromAcceptType(params.accept_types));
FilePath default_file_name = params.default_file_name;
if (default_file_name.empty())
default_file_name = tab_contents_->profile()->last_selected_directory();
@@ -117,7 +192,7 @@ void TabContentsFileSelectHelper::RunFileChooser(
dialog_type_,
params.title,
default_file_name,
- NULL,
+ file_types.get(),
0,
FILE_PATH_LITERAL(""),
tab_contents_->view()->GetTopLevelNativeWindow(),
diff --git a/chrome/browser/tab_contents/tab_contents_file_select_helper.h b/chrome/browser/tab_contents/tab_contents_file_select_helper.h
index aa24e53..e8e9b43 100644
--- a/chrome/browser/tab_contents/tab_contents_file_select_helper.h
+++ b/chrome/browser/tab_contents/tab_contents_file_select_helper.h
@@ -46,6 +46,12 @@ class TabContentsFileSelectHelper
// Helper method for handling the SelectFileDialog::Listener callbacks.
void DirectorySelected(const FilePath& path);
+ // Helper method to get allowed extensions for select file dialog from
+ // the specified accept types as defined in the spec:
+ // http://whatwg.org/html/number-state.html#attr-input-accept
+ SelectFileDialog::FileTypeInfo* GetFileTypesFromAcceptType(
+ const string16& accept_types);
+
// The tab contents this class is helping. |tab_contents_| owns this object,
// so this pointer is guaranteed to be valid.
TabContents* tab_contents_;
diff --git a/chrome/common/render_messages_params.cc b/chrome/common/render_messages_params.cc
index 4459c17..734874c 100644
--- a/chrome/common/render_messages_params.cc
+++ b/chrome/common/render_messages_params.cc
@@ -1241,6 +1241,7 @@ void ParamTraits<ViewHostMsg_RunFileChooser_Params>::Write(
WriteParam(m, static_cast<int>(p.mode));
WriteParam(m, p.title);
WriteParam(m, p.default_file_name);
+ WriteParam(m, p.accept_types);
}
bool ParamTraits<ViewHostMsg_RunFileChooser_Params>::Read(
@@ -1258,7 +1259,8 @@ bool ParamTraits<ViewHostMsg_RunFileChooser_Params>::Read(
p->mode = static_cast<param_type::Mode>(mode);
return
ReadParam(m, iter, &p->title) &&
- ReadParam(m, iter, &p->default_file_name);
+ ReadParam(m, iter, &p->default_file_name) &&
+ ReadParam(m, iter, &p->accept_types);
};
void ParamTraits<ViewHostMsg_RunFileChooser_Params>::Log(
@@ -1283,6 +1285,8 @@ void ParamTraits<ViewHostMsg_RunFileChooser_Params>::Log(
LogParam(p.title, l);
l->append(", ");
LogParam(p.default_file_name, l);
+ l->append(", ");
+ LogParam(p.accept_types, l);
}
void ParamTraits<ViewMsg_ExtensionRendererInfo>::Write(Message* m,
diff --git a/chrome/common/render_messages_params.h b/chrome/common/render_messages_params.h
index 1f83458..904e094 100644
--- a/chrome/common/render_messages_params.h
+++ b/chrome/common/render_messages_params.h
@@ -775,6 +775,10 @@ struct ViewHostMsg_RunFileChooser_Params {
// Default file name to select in the dialog.
FilePath default_file_name;
+
+ // A comma-separated MIME types such as "audio/*,text/plain", that is used
+ // to restrict selectable files to such types.
+ string16 accept_types;
};
struct ViewMsg_ExtensionRendererInfo {
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index a39a63f..0f40d00 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -2007,6 +2007,7 @@ bool RenderView::runFileChooser(
ipc_params.title = params.title;
ipc_params.default_file_name =
webkit_glue::WebStringToFilePath(params.initialValue);
+ ipc_params.accept_types = params.acceptTypes;
return ScheduleFileChooser(ipc_params, chooser_completion);
}
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc
index 5863b68..629270a 100644
--- a/net/base/mime_util.cc
+++ b/net/base/mime_util.cc
@@ -11,6 +11,7 @@
#include "base/hash_tables.h"
#include "base/logging.h"
#include "base/singleton.h"
+#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -531,4 +532,179 @@ void ParseCodecString(const std::string& codecs,
GetMimeUtil()->ParseCodecString(codecs, codecs_out, strip);
}
+namespace {
+
+// From http://www.w3schools.com/media/media_mimeref.asp and
+// http://plugindoc.mozdev.org/winmime.php
+static const char* kStandardImageTypes[] = {
+ "image/bmp",
+ "image/cis-cod",
+ "image/gif",
+ "image/ief",
+ "image/jpeg",
+ "image/pict",
+ "image/pipeg",
+ "image/png",
+ "image/svg+xml",
+ "image/tiff",
+ "image/x-cmu-raster",
+ "image/x-cmx",
+ "image/x-icon",
+ "image/x-portable-anymap",
+ "image/x-portable-bitmap",
+ "image/x-portable-graymap",
+ "image/x-portable-pixmap",
+ "image/x-rgb",
+ "image/x-xbitmap",
+ "image/x-xpixmap",
+ "image/x-xwindowdump"
+};
+static const char* kStandardAudioTypes[] = {
+ "audio/aac",
+ "audio/aiff",
+ "audio/amr",
+ "audio/basic",
+ "audio/midi",
+ "audio/mp3",
+ "audio/mp4",
+ "audio/mpeg",
+ "audio/mpeg3",
+ "audio/ogg",
+ "audio/vorbis",
+ "audio/wav",
+ "audio/webm",
+ "audio/x-m4a",
+ "audio/x-ms-wma",
+ "audio/vnd.rn-realaudio",
+ "audio/vnd.wave"
+};
+static const char* kStandardVideoTypes[] = {
+ "video/avi",
+ "video/divx",
+ "video/flc",
+ "video/mp4",
+ "video/mpeg",
+ "video/ogg",
+ "video/quicktime",
+ "video/sd-video",
+ "video/webm",
+ "video/x-dv",
+ "video/x-m4v",
+ "video/x-mpeg",
+ "video/x-ms-asf",
+ "video/x-ms-wmv"
+};
+
+void GetExtensionsFromHardCodedMappings(
+ const MimeInfo* mappings,
+ size_t mappings_len,
+ const std::string& leading_mime_type,
+ base::hash_set<FilePath::StringType>* extensions) {
+ FilePath::StringType extension;
+ for (size_t i = 0; i < mappings_len; ++i) {
+ if (StartsWithASCII(mappings[i].mime_type, leading_mime_type, false)) {
+ std::vector<string> this_extensions;
+ base::SplitStringUsingSubstr(mappings[i].extensions,
+ ",",
+ &this_extensions);
+ for (size_t j = 0; j < this_extensions.size(); ++j) {
+#if defined(OS_WIN)
+ FilePath::StringType extension(UTF8ToWide(this_extensions[j]));
+#else
+ FilePath::StringType extension(this_extensions[j]);
+#endif
+ extensions->insert(extension);
+ }
+ }
+ }
+}
+
+void GetExtensionsHelper(
+ const char** standard_types,
+ size_t standard_types_len,
+ const std::string& leading_mime_type,
+ base::hash_set<FilePath::StringType>* extensions) {
+ FilePath::StringType extension;
+ for (size_t i = 0; i < standard_types_len; ++i) {
+ if (net::GetPreferredExtensionForMimeType(standard_types[i], &extension))
+ extensions->insert(extension);
+ }
+
+ // Also look up the extensions from hard-coded mappings in case that some
+ // supported extensions are not registered in the system registry, like ogg.
+ GetExtensionsFromHardCodedMappings(primary_mappings,
+ arraysize(primary_mappings),
+ leading_mime_type,
+ extensions);
+
+ GetExtensionsFromHardCodedMappings(secondary_mappings,
+ arraysize(secondary_mappings),
+ leading_mime_type,
+ extensions);
+}
+
+// Note that the elements in the source set will be appended to the target
+// vector.
+template<class T>
+void HashSetToVector(base::hash_set<T>* source, std::vector<T>* target) {
+ size_t old_target_size = target->size();
+ target->resize(old_target_size + source->size());
+ size_t i = 0;
+ for (typename base::hash_set<T>::iterator iter = source->begin();
+ iter != source->end(); ++iter, ++i) {
+ target->at(old_target_size + i) = *iter;
+ }
+}
+
+}
+
+void GetImageExtensions(std::vector<FilePath::StringType>* extensions) {
+ base::hash_set<FilePath::StringType> unique_extensions;
+ GetExtensionsHelper(kStandardImageTypes,
+ arraysize(kStandardImageTypes),
+ "image/",
+ &unique_extensions);
+ HashSetToVector(&unique_extensions, extensions);
+}
+
+void GetAudioExtensions(std::vector<FilePath::StringType>* extensions) {
+ base::hash_set<FilePath::StringType> unique_extensions;
+ GetExtensionsHelper(kStandardAudioTypes,
+ arraysize(kStandardAudioTypes),
+ "audio/",
+ &unique_extensions);
+ HashSetToVector(&unique_extensions, extensions);
+}
+
+void GetVideoExtensions(std::vector<FilePath::StringType>* extensions) {
+ base::hash_set<FilePath::StringType> unique_extensions;
+ GetExtensionsHelper(kStandardVideoTypes,
+ arraysize(kStandardVideoTypes),
+ "video/",
+ &unique_extensions);
+ HashSetToVector(&unique_extensions, extensions);
+}
+
+void GetExtensionsForMimeType(const std::string& mime_type,
+ std::vector<FilePath::StringType>* extensions) {
+ base::hash_set<FilePath::StringType> unique_extensions;
+ FilePath::StringType extension;
+ if (net::GetPreferredExtensionForMimeType(mime_type, &extension))
+ unique_extensions.insert(extension);
+
+ // Also look up the extensions from hard-coded mappings in case that some
+ // supported extensions are not registered in the system registry, like ogg.
+ GetExtensionsFromHardCodedMappings(primary_mappings,
+ arraysize(primary_mappings),
+ mime_type,
+ &unique_extensions);
+
+ GetExtensionsFromHardCodedMappings(secondary_mappings,
+ arraysize(secondary_mappings),
+ mime_type,
+ &unique_extensions);
+
+ HashSetToVector(&unique_extensions, extensions);
+}
+
} // namespace net
diff --git a/net/base/mime_util.h b/net/base/mime_util.h
index fbbe478..249a25b 100644
--- a/net/base/mime_util.h
+++ b/net/base/mime_util.h
@@ -71,6 +71,29 @@ bool IsStrictMediaMimeType(const std::string& mime_type);
bool IsSupportedStrictMediaMimeType(const std::string& mime_type,
const std::vector<std::string>& codecs);
+// Get the extensions for images files.
+// Note that we do not erase the existing elements in the the provided vector.
+// Instead, we append the result to it.
+void GetImageExtensions(std::vector<FilePath::StringType>* extensions);
+
+// Get the extensions for audio files.
+// Note that we do not erase the existing elements in the the provided vector.
+// Instead, we append the result to it.
+void GetAudioExtensions(std::vector<FilePath::StringType>* extensions);
+
+// Get the extensions for video files.
+// Note that we do not erase the existing elements in the the provided vector.
+// Instead, we append the result to it.
+void GetVideoExtensions(std::vector<FilePath::StringType>* extensions);
+
+// Get the extensions associated with the given mime type.
+// There could be multiple extensions for a given mime type, like "html,htm"
+// for "text/html".
+// Note that we do not erase the existing elements in the the provided vector.
+// Instead, we append the result to it.
+void GetExtensionsForMimeType(const std::string& mime_type,
+ std::vector<FilePath::StringType>* extensions);
+
} // namespace net
#endif // NET_BASE_MIME_UTIL_H__