diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 13 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_file_select_helper.cc | 77 | ||||
-rw-r--r-- | chrome/browser/tab_contents/tab_contents_file_select_helper.h | 6 | ||||
-rw-r--r-- | chrome/common/render_messages_params.cc | 6 | ||||
-rw-r--r-- | chrome/common/render_messages_params.h | 4 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 1 | ||||
-rw-r--r-- | net/base/mime_util.cc | 176 | ||||
-rw-r--r-- | net/base/mime_util.h | 23 |
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 ¶ms) { 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__ |