diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-17 05:14:15 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-17 05:14:15 +0000 |
commit | 1631f7c651fbc7f4460a852126f545afc5513531 (patch) | |
tree | 7176f3052f69c0c0debf48172d533f9acc4c83d3 | |
parent | 42a17153ee389574560b91b185bcec6c4db5b5c3 (diff) | |
download | chromium_src-1631f7c651fbc7f4460a852126f545afc5513531.zip chromium_src-1631f7c651fbc7f4460a852126f545afc5513531.tar.gz chromium_src-1631f7c651fbc7f4460a852126f545afc5513531.tar.bz2 |
Implement web app definition parsing.
This required moving some code from webkit/glue to
chrome/common/web_apps.cc so that it could rely on
chrome/common/json_schema_validator.h.
BUG=49233
TEST=Convered by unit tests.
Review URL: http://codereview.chromium.org/4979003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66386 0039d316-1c4b-4281-b951-d872f2087c98
33 files changed, 783 insertions, 291 deletions
diff --git a/chrome/browser/gears_integration.cc b/chrome/browser/gears_integration.cc index d1f13cf..1ab162a 100644 --- a/chrome/browser/gears_integration.cc +++ b/chrome/browser/gears_integration.cc @@ -15,10 +15,10 @@ #include "chrome/browser/chrome_plugin_host.h" #include "chrome/common/chrome_plugin_util.h" #include "chrome/common/gears_api.h" +#include "chrome/common/web_apps.h" #include "gfx/codec/png_codec.h" #include "googleurl/src/gurl.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "webkit/glue/dom_operations.h" // The following 2 helpers are borrowed from the Gears codebase. @@ -139,7 +139,7 @@ class CreateShortcutCommand : public CPCommandInterface { CreateShortcutCommand( const std::string& name, const std::string& orig_name, const std::string& url, const std::string& description, - const std::vector<webkit_glue::WebApplicationInfo::IconInfo> &icons, + const std::vector<WebApplicationInfo::IconInfo> &icons, const SkBitmap& fallback_icon, GearsCreateShortcutCallback* callback) : name_(name), url_(url), description_(description), @@ -157,7 +157,7 @@ class CreateShortcutCommand : public CPCommandInterface { bool has_icon = false; for (size_t i = 0; i < icons.size(); ++i) { - const webkit_glue::WebApplicationInfo::IconInfo& icon = icons[i]; + const WebApplicationInfo::IconInfo& icon = icons[i]; if (icon.width == 16 && icon.height == 16) { has_icon = true; InitIcon(SIZE_16x16, icon.url, 16, 16); @@ -232,7 +232,7 @@ class CreateShortcutCommand : public CPCommandInterface { DISABLE_RUNNABLE_METHOD_REFCOUNT(CreateShortcutCommand); void GearsCreateShortcut( - const webkit_glue::WebApplicationInfo& app_info, + const WebApplicationInfo& app_info, const string16& fallback_name, const GURL& fallback_url, const SkBitmap& fallback_icon, diff --git a/chrome/browser/gears_integration.h b/chrome/browser/gears_integration.h index 4723c9b..6461377 100644 --- a/chrome/browser/gears_integration.h +++ b/chrome/browser/gears_integration.h @@ -18,9 +18,7 @@ class CPCommandInterface; class GURL; class SkBitmap; -namespace webkit_glue { struct WebApplicationInfo; -} // We use this in place of GearsShortcutData so we can keep browser-specific // data on the structure. @@ -40,12 +38,11 @@ void GearsSettingsPressed(gfx::NativeWindow parent_wnd); typedef Callback2<const GearsShortcutData2&, bool>::Type GearsCreateShortcutCallback; -void GearsCreateShortcut( - const webkit_glue::WebApplicationInfo& app_info, - const string16& fallback_name, - const GURL& fallback_url, - const SkBitmap& fallback_icon, - GearsCreateShortcutCallback* callback); +void GearsCreateShortcut(const WebApplicationInfo& app_info, + const string16& fallback_name, + const GURL& fallback_url, + const SkBitmap& fallback_icon, + GearsCreateShortcutCallback* callback); // Call into Gears to query the list of shortcuts. Results will be returned // asynchronously via the callback. The callback's arguments will be NULL diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 8e04211..7c9c154 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -45,12 +45,12 @@ #include "chrome/common/thumbnail_score.h" #include "chrome/common/translate_errors.h" #include "chrome/common/url_constants.h" +#include "chrome/common/web_apps.h" #include "gfx/native_widget_types.h" #include "net/base/net_util.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/WebKit/WebKit/chromium/public/WebFindOptions.h" #include "webkit/glue/context_menu.h" -#include "webkit/glue/dom_operations.h" #include "webkit/glue/form_data.h" #include "webkit/glue/form_field.h" #include "webkit/glue/password_form_dom_manager.h" @@ -62,7 +62,6 @@ using webkit_glue::FormData; using webkit_glue::PasswordForm; using webkit_glue::PasswordFormDomManager; using webkit_glue::PasswordFormFillData; -using webkit_glue::WebApplicationInfo; using WebKit::WebConsoleMessage; using WebKit::WebDragOperation; using WebKit::WebDragOperationNone; diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index 03b1cfd..45d0b557 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -44,6 +44,7 @@ struct ViewHostMsg_PageHasOSDD_Type; struct ViewHostMsg_RunFileChooser_Params; struct ViewHostMsg_ShowNotification_Params; struct ViewMsg_Navigate_Params; +struct WebApplicationInfo; struct WebDropData; struct WebPreferences; struct UserMetricsAction; @@ -58,7 +59,6 @@ class FormField; struct PasswordForm; struct PasswordFormFillData; struct WebAccessibility; -struct WebApplicationInfo; } // namespace webkit_glue namespace WebKit { @@ -667,8 +667,7 @@ class RenderViewHost : public RenderWidgetHost { const std::string& data, int32 status); - void OnDidGetApplicationInfo(int32 page_id, - const webkit_glue::WebApplicationInfo& info); + void OnDidGetApplicationInfo(int32 page_id, const WebApplicationInfo& info); void OnMsgShouldCloseACK(bool proceed); void OnQueryFormFieldAutoFill(int request_id, bool form_autofilled, diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h index 27c63ec..2a6f745 100644 --- a/chrome/browser/renderer_host/render_view_host_delegate.h +++ b/chrome/browser/renderer_host/render_view_host_delegate.h @@ -50,6 +50,7 @@ struct ViewHostMsg_DomMessage_Params; struct ViewHostMsg_FrameNavigate_Params; struct ViewHostMsg_PageHasOSDD_Type; struct ViewHostMsg_RunFileChooser_Params; +struct WebApplicationInfo; struct WebDropData; struct WebMenuItem; class WebKeyboardEvent; @@ -73,7 +74,6 @@ namespace webkit_glue { struct FormData; class FormField; struct PasswordForm; -struct WebApplicationInfo; } // @@ -280,10 +280,11 @@ class RenderViewHostDelegate { virtual void OnDisabledOutdatedPlugin(const string16& name, const GURL& update_url) = 0; - // Notification that a request for install info has completed. + // Notification that a user's request to install an application has + // completed. virtual void OnDidGetApplicationInfo( int32 page_id, - const webkit_glue::WebApplicationInfo& app_info) = 0; + const WebApplicationInfo& app_info) = 0; // Notification that the contents of the page has been loaded. virtual void OnPageContents(const GURL& url, diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc index 165f23a..9b117ce 100644 --- a/chrome/browser/tab_contents/tab_contents.cc +++ b/chrome/browser/tab_contents/tab_contents.cc @@ -2059,9 +2059,8 @@ void TabContents::OnCrashedWorker() { NULL, true)); } -void TabContents::OnDidGetApplicationInfo( - int32 page_id, - const webkit_glue::WebApplicationInfo& info) { +void TabContents::OnDidGetApplicationInfo(int32 page_id, + const WebApplicationInfo& info) { web_app_info_ = info; if (delegate()) diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h index ec3a77a..f8bad82 100644 --- a/chrome/browser/tab_contents/tab_contents.h +++ b/chrome/browser/tab_contents/tab_contents.h @@ -38,9 +38,9 @@ #include "chrome/common/property_bag.h" #include "chrome/common/renderer_preferences.h" #include "chrome/common/translate_errors.h" +#include "chrome/common/web_apps.h" #include "gfx/native_widget_types.h" #include "net/base/load_states.h" -#include "webkit/glue/dom_operations.h" namespace gfx { class Rect; @@ -285,7 +285,7 @@ class TabContents : public PageNavigator, encoding_.clear(); } - const webkit_glue::WebApplicationInfo& web_app_info() const { + const WebApplicationInfo& web_app_info() const { return web_app_info_; } @@ -868,9 +868,8 @@ class TabContents : public PageNavigator, virtual void OnMissingPluginStatus(int status); virtual void OnCrashedPlugin(const FilePath& plugin_path); virtual void OnCrashedWorker(); - virtual void OnDidGetApplicationInfo( - int32 page_id, - const webkit_glue::WebApplicationInfo& info); + virtual void OnDidGetApplicationInfo(int32 page_id, + const WebApplicationInfo& info); virtual void OnDisabledOutdatedPlugin(const string16& name, const GURL& update_url); virtual void OnPageContents(const GURL& url, @@ -1115,7 +1114,7 @@ class TabContents : public PageNavigator, FavIconHelper fav_icon_helper_; // Cached web app info data. - webkit_glue::WebApplicationInfo web_app_info_; + WebApplicationInfo web_app_info_; // Cached web app icon. SkBitmap app_icon_; diff --git a/chrome/browser/tab_contents/tab_contents_delegate.h b/chrome/browser/tab_contents/tab_contents_delegate.h index 58497d5..7dfafe6 100644 --- a/chrome/browser/tab_contents/tab_contents_delegate.h +++ b/chrome/browser/tab_contents/tab_contents_delegate.h @@ -28,6 +28,7 @@ namespace history { class HistoryAddPageArgs; } +struct ContextMenuParams; class DownloadItem; class ExtensionFunctionDispatcher; class GURL; @@ -38,7 +39,6 @@ class RenderViewHost; class TabContents; class TemplateURL; class TemplateURLModel; -struct ContextMenuParams; // Objects implement this interface to get notified about changes in the // TabContents and to provide necessary functionality. @@ -277,7 +277,7 @@ class TabContentsDelegate : public AutomationResourceRoutingDelegate { const history::HistoryAddPageArgs& add_page_args, NavigationType::Type navigation_type); - // Notification when web app info data is available + // Notification that a user's request to install an application has completed. virtual void OnDidGetApplicationInfo(TabContents* tab_contents, int32 page_id); diff --git a/chrome/browser/ui/views/create_application_shortcut_view.cc b/chrome/browser/ui/views/create_application_shortcut_view.cc index 77e2ea6..f0ec8ee 100644 --- a/chrome/browser/ui/views/create_application_shortcut_view.cc +++ b/chrome/browser/ui/views/create_application_shortcut_view.cc @@ -236,8 +236,7 @@ void CreateApplicationShortcutView::Init() { // Prepare data web_app::GetShortcutInfoForTab(tab_contents_, &shortcut_info_); - const webkit_glue::WebApplicationInfo& app_info = - tab_contents_->web_app_info(); + const WebApplicationInfo& app_info = tab_contents_->web_app_info(); if (!app_info.icons.empty()) { web_app::GetIconsInfo(app_info, &unprocessed_icons_); FetchIcon(); diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index fc385a6..79fb3f7 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc @@ -32,7 +32,7 @@ #include "chrome/common/notification_registrar.h" #include "chrome/common/notification_service.h" #include "chrome/common/url_constants.h" -#include "webkit/glue/dom_operations.h" +#include "chrome/common/web_apps.h" #if defined(OS_LINUX) #include "base/environment.h" @@ -114,9 +114,8 @@ FilePath GetWebAppDataDirectory(const FilePath& root_dir, #if defined(TOOLKIT_VIEWS) // Predicator for sorting images from largest to smallest. -bool IconPrecedes( - const webkit_glue::WebApplicationInfo::IconInfo& left, - const webkit_glue::WebApplicationInfo::IconInfo& right) { +bool IconPrecedes(const WebApplicationInfo::IconInfo& left, + const WebApplicationInfo::IconInfo& right) { return left.width < right.width; } #endif @@ -723,7 +722,7 @@ FilePath GetDataDir(const FilePath& profile_path) { } #if defined(TOOLKIT_VIEWS) -void GetIconsInfo(const webkit_glue::WebApplicationInfo& app_info, +void GetIconsInfo(const WebApplicationInfo& app_info, IconInfoList* icons) { DCHECK(icons); @@ -743,8 +742,7 @@ void GetShortcutInfoForTab(TabContents* tab_contents, ShellIntegration::ShortcutInfo* info) { DCHECK(info); // Must provide a valid info. - const webkit_glue::WebApplicationInfo& app_info = - tab_contents->web_app_info(); + const WebApplicationInfo& app_info = tab_contents->web_app_info(); info->url = app_info.app_url.is_empty() ? tab_contents->GetURL() : app_info.app_url; diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h index c451e85..4734b7e 100644 --- a/chrome/browser/web_applications/web_app.h +++ b/chrome/browser/web_applications/web_app.h @@ -11,7 +11,7 @@ #include "base/callback.h" #include "build/build_config.h" #include "chrome/browser/shell_integration.h" -#include "webkit/glue/dom_operations.h" +#include "chrome/common/web_apps.h" class FilePath; class Profile; @@ -47,8 +47,8 @@ FilePath GetDataDir(const FilePath& profile_path); #if defined(TOOLKIT_VIEWS) // Extracts icons info from web app data. Take only square shaped icons and // sort them from smallest to largest. -typedef std::vector<webkit_glue::WebApplicationInfo::IconInfo> IconInfoList; -void GetIconsInfo(const webkit_glue::WebApplicationInfo& app_info, +typedef std::vector<WebApplicationInfo::IconInfo> IconInfoList; +void GetIconsInfo(const WebApplicationInfo& app_info, IconInfoList* icons); #endif diff --git a/chrome/browser/web_applications/web_app_unittest.cc b/chrome/browser/web_applications/web_app_unittest.cc index a8fc395..a999f33 100644 --- a/chrome/browser/web_applications/web_app_unittest.cc +++ b/chrome/browser/web_applications/web_app_unittest.cc @@ -43,7 +43,7 @@ TEST_F(WebApplicationTest, GetShortcutInfoForTab) { const string16 title = ASCIIToUTF16("TEST_TITLE"); const string16 description = ASCIIToUTF16("TEST_DESCRIPTION"); const GURL url("http://www.foo.com/bar"); - webkit_glue::WebApplicationInfo web_app_info; + WebApplicationInfo web_app_info; web_app_info.title = title; web_app_info.description = description; web_app_info.app_url = url; diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index f7f44fc..5f64873 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -327,6 +327,8 @@ 'common/view_types.h', 'common/visitedlink_common.cc', 'common/visitedlink_common.h', + 'common/web_apps.cc', + 'common/web_apps.h', 'common/web_database_observer_impl.cc', 'common/web_database_observer_impl.h', 'common/webkit_param_traits.cc', @@ -549,8 +551,10 @@ # We usually get these skia directories by adding a dependency on # skia, bu we don't need it for NaCl's 64-bit Windows support. The # directories are required for resolving the includes in any case. + '../third_party/skia/include/config', '../third_party/skia/include/core', '../skia/config', + '../skia/config/win', ], 'defines': [ 'EXCLUDE_SKIA_DEPENDENCIES', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 354e1ca..ae66fe9 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1591,6 +1591,7 @@ 'common/switch_utils_unittest.cc', 'common/thumbnail_score_unittest.cc', 'common/time_format_unittest.cc', + 'common/web_apps_unittest.cc', 'common/worker_thread_ticker_unittest.cc', 'common/zip_unittest.cc', 'gpu/gpu_idirect3d9_mock_win.h', diff --git a/chrome/common/common_param_traits.cc b/chrome/common/common_param_traits.cc index 2fd8bdd..ca5e90b 100644 --- a/chrome/common/common_param_traits.cc +++ b/chrome/common/common_param_traits.cc @@ -9,6 +9,7 @@ #include "chrome/common/content_settings.h" #include "chrome/common/geoposition.h" #include "chrome/common/thumbnail_score.h" +#include "chrome/common/web_apps.h" #include "gfx/rect.h" #include "googleurl/src/gurl.h" #include "net/base/upload_data.h" @@ -18,7 +19,6 @@ #ifndef EXCLUDE_SKIA_DEPENDENCIES #include "third_party/skia/include/core/SkBitmap.h" #endif -#include "webkit/glue/dom_operations.h" #include "webkit/glue/password_form.h" namespace IPC { @@ -227,8 +227,8 @@ void ParamTraits<ContentSettings>::Log( l->append("<ContentSettings>"); } -void ParamTraits<webkit_glue::WebApplicationInfo>::Write( - Message* m, const webkit_glue::WebApplicationInfo& p) { +void ParamTraits<WebApplicationInfo>::Write(Message* m, + const WebApplicationInfo& p) { WriteParam(m, p.title); WriteParam(m, p.description); WriteParam(m, p.app_url); @@ -240,8 +240,8 @@ void ParamTraits<webkit_glue::WebApplicationInfo>::Write( } } -bool ParamTraits<webkit_glue::WebApplicationInfo>::Read( - const Message* m, void** iter, webkit_glue::WebApplicationInfo* r) { +bool ParamTraits<WebApplicationInfo>::Read( + const Message* m, void** iter, WebApplicationInfo* r) { size_t icon_count; bool result = ReadParam(m, iter, &r->title) && @@ -263,8 +263,8 @@ bool ParamTraits<webkit_glue::WebApplicationInfo>::Read( return true; } -void ParamTraits<webkit_glue::WebApplicationInfo>::Log( - const webkit_glue::WebApplicationInfo& p, std::string* l) { +void ParamTraits<WebApplicationInfo>::Log(const WebApplicationInfo& p, + std::string* l) { l->append("<WebApplicationInfo>"); } diff --git a/chrome/common/common_param_traits.h b/chrome/common/common_param_traits.h index d8796d6..6862482 100644 --- a/chrome/common/common_param_traits.h +++ b/chrome/common/common_param_traits.h @@ -40,6 +40,7 @@ class DictionaryValue; class ListValue; struct ThumbnailScore; class URLRequestStatus; +struct WebApplicationInfo; class WebCursor; namespace gfx { @@ -58,7 +59,6 @@ struct PageRange; namespace webkit_glue { struct PasswordForm; -struct WebApplicationInfo; } // namespace webkit_glue namespace IPC { @@ -231,8 +231,8 @@ struct ParamTraits<WebCursor> { template <> -struct ParamTraits<webkit_glue::WebApplicationInfo> { - typedef webkit_glue::WebApplicationInfo param_type; +struct ParamTraits<WebApplicationInfo> { + typedef WebApplicationInfo param_type; static void Write(Message* m, const param_type& p); static bool Read(const Message* m, void** iter, param_type* r); static void Log(const param_type& p, std::string* l); diff --git a/chrome/common/common_resources.grd b/chrome/common/common_resources.grd index ea1b784..fb7d8f9 100644 --- a/chrome/common/common_resources.grd +++ b/chrome/common/common_resources.grd @@ -12,6 +12,7 @@ <include name="IDR_EXTENSION_API_JSON" file="extensions\api\extension_api.json" type="BINDATA" /> <include name="IDR_I18N_TEMPLATE_JS" file="..\browser\resources\shared\js\i18n_template.js" type="BINDATA" /> <include name="IDR_JSTEMPLATE_JS" file="..\third_party\jstemplate\jstemplate_compiled.js" type="BINDATA" /> + <include name="IDR_WEB_APP_SCHEMA" file="web_app_schema.json" type="BINDATA" /> </includes> </release> </grit> diff --git a/chrome/common/render_messages.cc b/chrome/common/render_messages.cc index 2a42c6c..e6d3126 100644 --- a/chrome/common/render_messages.cc +++ b/chrome/common/render_messages.cc @@ -16,6 +16,7 @@ #include "chrome/common/serialized_script_value.h" #include "chrome/common/speech_input_result.h" #include "chrome/common/thumbnail_score.h" +#include "chrome/common/web_apps.h" #include "gfx/rect.h" #include "ipc/ipc_channel_handle.h" #include "media/audio/audio_buffers_state.h" @@ -29,7 +30,6 @@ #include "webkit/appcache/appcache_interfaces.h" #include "webkit/blob/blob_data.h" #include "webkit/glue/context_menu.h" -#include "webkit/glue/dom_operations.h" #include "webkit/glue/form_data.h" #include "webkit/glue/form_field.h" #include "webkit/glue/password_form.h" diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index dd6bff4..6f6b6cd 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1903,7 +1903,7 @@ IPC_BEGIN_MESSAGES(ViewHost) IPC_MESSAGE_ROUTED2(ViewHostMsg_DidGetApplicationInfo, int32 /* page_id */, - webkit_glue::WebApplicationInfo) + WebApplicationInfo) // Provides the result from running OnMsgShouldClose. |proceed| matches the // return value of the the frame's shouldClose method (which includes the diff --git a/chrome/common/web_app_schema.json b/chrome/common/web_app_schema.json new file mode 100644 index 0000000..fe23966 --- /dev/null +++ b/chrome/common/web_app_schema.json @@ -0,0 +1,58 @@ +// Copyright (c) 2010 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. + +// This file contains the schema for web app defintion files. + +{ + "type": "object", + "properties": { + // TODO(aa): Need to figure out what max length the store is using for name + // and description. + "name": { + "type": "string", + "minLength": 1, + "maxLength": 45 + }, + "description": { + "type": "string", + "maxLength": 132, + "optional": true + }, + "launch_url": { + "type": "string", + "minLength": 1 + }, + "launch_container": { + "enum": ["tab", "panel"], + "optional": true + }, + // TODO(aa): We had problems with a simple array of strings in extensions. + // Consider something else. + "permissions": { + "type": "array", + "optional": true, + "items": { + "type": "string", + "minLength": 1 + } + }, + "urls": { + "type": "array", + "optional": true, + "items": { + "type": "string", + "minLength": 1 + } + }, + "icons": { + "type": "object", + "optional": true, + "properties": { + "16": { "optional": true, "type": "string", "minLength": 1 }, + "48": { "optional": true, "type": "string", "minLength": 1 }, + "128": { "optional": true, "type": "string", "minLength": 1 } + } + } + } +} diff --git a/chrome/common/web_apps.cc b/chrome/common/web_apps.cc new file mode 100644 index 0000000..1d706c4 --- /dev/null +++ b/chrome/common/web_apps.cc @@ -0,0 +1,323 @@ +// Copyright (c) 2010 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 "chrome/common/web_apps.h" + +#include <string> +#include <vector> + +#include "app/l10n_util.h" +#include "app/resource_bundle.h" +#include "base/json/json_reader.h" +#include "base/string16.h" +#include "base/string_number_conversions.h" +#include "base/string_split.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/common/json_schema_validator.h" +#include "gfx/size.h" +#include "googleurl/src/gurl.h" +#include "grit/common_resources.h" +#include "grit/generated_resources.h" +#include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" +#include "third_party/WebKit/WebKit/chromium/public/WebElement.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/WebKit/chromium/public/WebNode.h" +#include "third_party/WebKit/WebKit/chromium/public/WebNodeList.h" +#include "third_party/WebKit/WebKit/chromium/public/WebString.h" +#include "third_party/WebKit/WebKit/chromium/public/WebURL.h" +#include "webkit/glue/dom_operations.h" + +using WebKit::WebDocument; +using WebKit::WebElement; +using WebKit::WebFrame; +using WebKit::WebNode; +using WebKit::WebNodeList; +using WebKit::WebString; + +namespace { + +// Sizes a single size (the width or height) from a 'sizes' attribute. A size +// matches must match the following regex: [1-9][0-9]*. +static int ParseSingleIconSize(const string16& text) { + // Size must not start with 0, and be between 0 and 9. + if (text.empty() || !(text[0] >= L'1' && text[0] <= L'9')) + return 0; + + // Make sure all chars are from 0-9. + for (size_t i = 1; i < text.length(); ++i) { + if (!(text[i] >= L'0' && text[i] <= L'9')) + return 0; + } + int output; + if (!base::StringToInt(text, &output)) + return 0; + return output; +} + +void AddInstallIcon(const WebElement& link, + std::vector<WebApplicationInfo::IconInfo>* icons) { + WebString href = link.getAttribute("href"); + if (href.isNull() || href.isEmpty()) + return; + + // Get complete url. + GURL url = link.document().completeURL(href); + if (!url.is_valid()) + return; + + if (!link.hasAttribute("sizes")) + return; + + bool is_any = false; + std::vector<gfx::Size> icon_sizes; + if (!web_apps::ParseIconSizes(link.getAttribute("sizes"), &icon_sizes, + &is_any) || + is_any || + icon_sizes.size() != 1) { + return; + } + WebApplicationInfo::IconInfo icon_info; + icon_info.width = icon_sizes[0].width(); + icon_info.height = icon_sizes[0].height(); + icon_info.url = url; + icons->push_back(icon_info); +} + +} + +const char WebApplicationInfo::kInvalidDefinitionURL[] = + "Invalid application definition URL. Must be a valid relative URL or " + "an absolute URL with the same origin as the document."; +const char WebApplicationInfo::kInvalidLaunchURL[] = + "Invalid value for property 'launch_url'. Must be a valid relative URL or " + "an absolute URL with the same origin as the application definition."; +const char WebApplicationInfo::kInvalidURL[] = + "Invalid value for property 'urls[*]'. Must be a valid relative URL or " + "an absolute URL with the same origin as the application definition."; +const char WebApplicationInfo::kInvalidIconURL[] = + "Invalid value for property 'icons.*'. Must be a valid relative URL or " + "an absolute URL with the same origin as the application definition."; + +WebApplicationInfo::WebApplicationInfo() { +} + +WebApplicationInfo::~WebApplicationInfo() { +} + + +namespace web_apps { + +gfx::Size ParseIconSize(const string16& text) { + std::vector<string16> sizes; + base::SplitStringDontTrim(text, L'x', &sizes); + if (sizes.size() != 2) + return gfx::Size(); + + return gfx::Size(ParseSingleIconSize(sizes[0]), + ParseSingleIconSize(sizes[1])); +} + +bool ParseIconSizes(const string16& text, + std::vector<gfx::Size>* sizes, + bool* is_any) { + *is_any = false; + std::vector<string16> size_strings; + SplitStringAlongWhitespace(text, &size_strings); + for (size_t i = 0; i < size_strings.size(); ++i) { + if (EqualsASCII(size_strings[i], "any")) { + *is_any = true; + } else { + gfx::Size size = ParseIconSize(size_strings[i]); + if (size.width() <= 0 || size.height() <= 0) + return false; // Bogus size. + sizes->push_back(size); + } + } + if (*is_any && !sizes->empty()) { + // If is_any is true, it must occur by itself. + return false; + } + return (*is_any || !sizes->empty()); +} + +bool ParseWebAppFromWebDocument(WebFrame* frame, + WebApplicationInfo* app_info, + string16* error) { + WebDocument document = frame->document(); + if (document.isNull()) + return true; + + WebElement head = document.head(); + if (head.isNull()) + return true; + + GURL frame_url = frame->url(); + WebNodeList children = head.childNodes(); + for (unsigned i = 0; i < children.length(); ++i) { + WebNode child = children.item(i); + if (!child.isElementNode()) + continue; + WebElement elem = child.to<WebElement>(); + + if (elem.hasTagName("link")) { + std::string rel = elem.getAttribute("rel").utf8(); + // "rel" attribute may use either "icon" or "shortcut icon". + // see also + // <http://en.wikipedia.org/wiki/Favicon> + // <http://dev.w3.org/html5/spec/Overview.html#rel-icon> + if (LowerCaseEqualsASCII(rel, "icon") || + LowerCaseEqualsASCII(rel, "shortcut icon")) { + AddInstallIcon(elem, &app_info->icons); + } else if (LowerCaseEqualsASCII(rel, "chrome-application-definition")) { + std::string definition_url_string(elem.getAttribute("href").utf8()); + GURL definition_url; + if (!(definition_url = + frame_url.Resolve(definition_url_string)).is_valid() || + definition_url.GetOrigin() != frame_url.GetOrigin()) { + *error = UTF8ToUTF16(WebApplicationInfo::kInvalidDefinitionURL); + return false; + } + + // If there is a definition file, all attributes come from it. + *app_info = WebApplicationInfo(); + app_info->manifest_url = definition_url; + return true; + } + } else if (elem.hasTagName("meta") && elem.hasAttribute("name")) { + std::string name = elem.getAttribute("name").utf8(); + WebString content = elem.getAttribute("content"); + if (name == "application-name") { + app_info->title = content; + } else if (name == "description") { + app_info->description = content; + } else if (name == "application-url") { + std::string url = content.utf8(); + app_info->app_url = frame_url.is_valid() ? + frame_url.Resolve(url) : GURL(url); + if (!app_info->app_url.is_valid()) + app_info->app_url = GURL(); + } + } + } + + return true; +} + +bool ParseWebAppFromDefinitionFile(const DictionaryValue& definition, + WebApplicationInfo* web_app, + string16* error) { + CHECK(web_app->manifest_url.is_valid()); + + int error_code = 0; + std::string error_message; + scoped_ptr<Value> schema( + base::JSONReader::ReadAndReturnError( + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_WEB_APP_SCHEMA).as_string(), + false, // disallow trailing comma + &error_code, + &error_message)); + CHECK(schema.get()) + << "Error parsing JSON schema: " << error_code << ": " << error_message; + CHECK(schema->IsType(Value::TYPE_DICTIONARY)) + << "schema root must be dictionary."; + + JSONSchemaValidator validator(static_cast<DictionaryValue*>(schema.get())); + + // We allow extra properties in the schema for easy compat with other systems, + // and for forward compat with ourselves. + validator.set_default_allow_additional_properties(true); + + if (!validator.Validate(const_cast<DictionaryValue*>(&definition))) { + *error = UTF8ToUTF16( + validator.errors()[0].path + ": " + validator.errors()[0].message); + return false; + } + + // Parse launch URL. It must be a valid URL in the same origin as the + // manifest. + std::string app_url_string; + GURL app_url; + CHECK(definition.GetString("launch_url", &app_url_string)); + if (!(app_url = web_app->manifest_url.Resolve(app_url_string)).is_valid() || + app_url.GetOrigin() != web_app->manifest_url.GetOrigin()) { + *error = UTF8ToUTF16(WebApplicationInfo::kInvalidLaunchURL); + return false; + } + + // Parse out the permissions if present. + std::vector<std::string> permissions; + ListValue* permissions_value = NULL; + if (definition.GetList("permissions", &permissions_value)) { + for (size_t i = 0; i < permissions_value->GetSize(); ++i) { + std::string permission; + CHECK(permissions_value->GetString(i, &permission)); + permissions.push_back(permission); + } + } + + // Parse out the URLs if present. + std::vector<GURL> urls; + ListValue* urls_value = NULL; + if (definition.GetList("urls", &urls_value)) { + for (size_t i = 0; i < urls_value->GetSize(); ++i) { + std::string url_string; + GURL url; + CHECK(urls_value->GetString(i, &url_string)); + if (!(url = web_app->manifest_url.Resolve(url_string)).is_valid() || + url.GetOrigin() != web_app->manifest_url.GetOrigin()) { + *error = UTF8ToUTF16( + JSONSchemaValidator::FormatErrorMessage( + WebApplicationInfo::kInvalidURL, base::Uint64ToString(i))); + return false; + } + urls.push_back(url); + } + } + + // Parse out the icons if present. + std::vector<WebApplicationInfo::IconInfo> icons; + DictionaryValue* icons_value = NULL; + if (definition.GetDictionary("icons", &icons_value)) { + for (DictionaryValue::key_iterator iter = icons_value->begin_keys(); + iter != icons_value->end_keys(); ++iter) { + // Ignore unknown properties. Better for forward compat. + int size = 0; + if (!base::StringToInt(*iter, &size) || size < 0 || size > 128) + continue; + + std::string icon_url_string; + GURL icon_url; + if (!icons_value->GetString(*iter, &icon_url_string) || + !(icon_url = web_app->manifest_url.Resolve( + icon_url_string)).is_valid()) { + *error = UTF8ToUTF16( + JSONSchemaValidator::FormatErrorMessage( + WebApplicationInfo::kInvalidIconURL, base::IntToString(size))); + return false; + } + + WebApplicationInfo::IconInfo icon; + icon.url = icon_url; + icon.width = size; + icon.height = size; + + icons.push_back(icon); + } + } + + CHECK(definition.GetString("name", &web_app->title)); + definition.GetString("description", &web_app->description); + definition.GetString("launch_container", &web_app->launch_container); + web_app->app_url = app_url; + web_app->urls = urls; + web_app->permissions = permissions; + web_app->icons = icons; + + return true; + +} + +} // namespace web_apps diff --git a/chrome/common/web_apps.h b/chrome/common/web_apps.h new file mode 100644 index 0000000..6d40883 --- /dev/null +++ b/chrome/common/web_apps.h @@ -0,0 +1,109 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_COMMON_WEB_APPS_H_ +#define CHROME_COMMON_WEB_APPS_H_ +#pragma once + +#include <string> +#include <vector> + +#include "base/string16.h" +#include "googleurl/src/gurl.h" +#include "gfx/size.h" +#include "third_party/skia/include/core/SkBitmap.h" + +namespace WebKit { +class WebDocument; +class WebFrame; +} + +class DictionaryValue; + +// Structure used when installing a web page as an app. +struct WebApplicationInfo { + struct IconInfo { + GURL url; + int width; + int height; + SkBitmap data; + }; + + static const char kInvalidDefinitionURL[]; + static const char kInvalidLaunchURL[]; + static const char kInvalidURL[]; + static const char kInvalidIconSize[]; + static const char kInvalidIconURL[]; + + WebApplicationInfo(); + ~WebApplicationInfo(); + + // URL to a manifest that defines the application. If specified, all other + // attributes are derived from this manifest, and the manifest is the unique + // ID of the application. + GURL manifest_url; + + // Title of the application. + string16 title; + + // Description of the application. + string16 description; + + // The launch URL for the app. + GURL app_url; + + // Set of available icons. + std::vector<IconInfo> icons; + + // The permissions the app requests. Only supported with manifest-based apps. + std::vector<std::string> permissions; + + // Set of URLs that comprise the app. Only supported with manifest-based apps. + // All these must be of the same origin as manifest_url. + std::vector<GURL> urls; + + // The type of launch container to use with the app. Currently supported + // values are 'tab' and 'panel'. Only supported with manifest-based apps. + std::string launch_container; +}; + + +namespace web_apps { + +// Parses an icon size. An icon size must match the following regex: +// [1-9][0-9]*x[1-9][0-9]*. +// If the input couldn't be parsed, a size with a width/height == 0 is returned. +gfx::Size ParseIconSize(const string16& text); + +// Parses the icon's size attribute as defined in the HTML 5 spec. Returns true +// on success, false on errors. On success either all the sizes specified in +// the attribute are added to sizes, or is_any is set to true. +// +// You shouldn't have a need to invoke this directly, it's public for testing. +bool ParseIconSizes(const string16& text, std::vector<gfx::Size>* sizes, + bool* is_any); + +// Parses |web_app| information out of the document in frame. Returns true on +// success, or false and |error| on failure. Note that the document may contain +// no web application information, in which case |web_app| is unchanged and the +// function returns true. +// +// Documents can also contain a link to a application 'definition'. In this case +// web_app will have manifest_url set and nothing else. The caller must fetch +// this URL and pass the result to ParseWebAppFromDefinitionFile() for further +// processing. +bool ParseWebAppFromWebDocument(WebKit::WebFrame* frame, + WebApplicationInfo* web_app, + string16* error); + +// Parses |web_app| information out of |definition|. Returns true on success, or +// false and |error| on failure. This function assumes that |web_app| has a +// valid manifest_url. +bool ParseWebAppFromDefinitionFile(const DictionaryValue& definition, + WebApplicationInfo* web_app, + string16* error); + +} // namespace web_apps + +#endif // CHROME_COMMON_WEB_APPS_H_ diff --git a/chrome/common/web_apps_unittest.cc b/chrome/common/web_apps_unittest.cc new file mode 100644 index 0000000..3a6980e --- /dev/null +++ b/chrome/common/web_apps_unittest.cc @@ -0,0 +1,190 @@ +// Copyright (c) 2010 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 "chrome/common/web_apps.h" + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/scoped_ptr.h" +#include "base/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/json_schema_validator.h" +#include "chrome/common/json_value_serializer.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +DictionaryValue* LoadDefinitionFile(const std::string& name) { + FilePath path; + if (!PathService::Get(chrome::DIR_TEST_DATA, &path)) { + ADD_FAILURE() << "Could not get test data dir."; + return NULL; + } + + path = path.AppendASCII("web_app_info").AppendASCII(name.c_str()); + if (!file_util::PathExists(path)) { + ADD_FAILURE() << "Path does not exist: " << path.value(); + return NULL; + } + + std::string error; + JSONFileValueSerializer serializer(path); + DictionaryValue* result = static_cast<DictionaryValue*>( + serializer.Deserialize(NULL, &error)); + if (!result) { + ADD_FAILURE() << "Error parsing " << name << ": " << error; + return NULL; + } + + return result; +} + +WebApplicationInfo* ParseFromDefinitionAndExpectSuccess( + const std::string& name) { + scoped_ptr<DictionaryValue> defintion(LoadDefinitionFile(name)); + if (!defintion.get()) + return NULL; + + scoped_ptr<WebApplicationInfo> web_app(new WebApplicationInfo()); + web_app->manifest_url = GURL("http://example.com/"); + + string16 error; + if (!web_apps::ParseWebAppFromDefinitionFile(*defintion, web_app.get(), + &error)) { + ADD_FAILURE() << "Error parsing " << name << ": " << UTF16ToUTF8(error); + return NULL; + } + + return web_app.release(); +} + +void ParseFromDefinitionAndExpectFailure(const std::string& name, + const string16& expected_error) { + scoped_ptr<DictionaryValue> definition(LoadDefinitionFile(name)); + if (!definition.get()) + return; + + WebApplicationInfo web_app; + web_app.manifest_url = GURL("http://example.com/"); + + string16 error; + if (web_apps::ParseWebAppFromDefinitionFile(*definition, &web_app, &error)) { + ADD_FAILURE() << "Expected error parsing " << name + << " but parse succeeded."; + return; + } + + EXPECT_EQ(UTF16ToUTF8(expected_error), UTF16ToUTF8(error)) << name; +} + +} + +TEST(WebAppInfo, ParseFromDefinitionFileErrors) { + // Test one definition file with a JSON schema error, just to make sure we're + // correctly propagating those. We don't extensively test all the properties + // covered by the schema, since we assume JSON schema is working correctly. + ParseFromDefinitionAndExpectFailure( + "missing_name.json", + UTF8ToUTF16(std::string("name: ") + + JSONSchemaValidator::kObjectPropertyIsRequired)); + + ParseFromDefinitionAndExpectFailure( + "invalid_launch_url.json", + UTF8ToUTF16(WebApplicationInfo::kInvalidLaunchURL)); + + ParseFromDefinitionAndExpectFailure( + "invalid_urls.json", + UTF8ToUTF16( + JSONSchemaValidator::FormatErrorMessage( + WebApplicationInfo::kInvalidURL, "2"))); +} + +TEST(WebAppInfo, Minimal) { + scoped_ptr<WebApplicationInfo> web_app( + ParseFromDefinitionAndExpectSuccess("minimal.json")); + + EXPECT_EQ(UTF8ToUTF16("hello"), web_app->title); + EXPECT_EQ(UTF8ToUTF16(""), web_app->description); + EXPECT_EQ(GURL("http://example.com/launch_url"), web_app->app_url); + EXPECT_EQ(0u, web_app->icons.size()); + EXPECT_EQ(0u, web_app->urls.size()); + EXPECT_EQ(0u, web_app->permissions.size()); + EXPECT_EQ("", web_app->launch_container); +} + +TEST(WebAppInfo, Full) { + scoped_ptr<WebApplicationInfo> web_app( + ParseFromDefinitionAndExpectSuccess("full.json")); + + EXPECT_EQ(UTF8ToUTF16("hello"), web_app->title); + EXPECT_EQ(UTF8ToUTF16("This app is super awesome"), web_app->description); + EXPECT_EQ(GURL("http://example.com/launch_url"), web_app->app_url); + ASSERT_EQ(1u, web_app->icons.size()); + EXPECT_EQ("http://example.com/16.png", web_app->icons[0].url.spec()); + EXPECT_EQ(16, web_app->icons[0].width); + EXPECT_EQ(16, web_app->icons[0].height); + ASSERT_EQ(2u, web_app->urls.size()); + EXPECT_EQ("http://example.com/foobar", web_app->urls[0].spec()); + EXPECT_EQ("http://example.com/baz", web_app->urls[1].spec()); + ASSERT_EQ(2u, web_app->permissions.size()); + EXPECT_EQ("geolocation", web_app->permissions[0]); + EXPECT_EQ("notifications", web_app->permissions[1]); + EXPECT_EQ("panel", web_app->launch_container); +} + +// Tests ParseIconSizes with various input. +TEST(WebAppInfo, ParseIconSizes) { + struct TestData { + const char* input; + const bool expected_result; + const bool is_any; + const size_t expected_size_count; + const int width1; + const int height1; + const int width2; + const int height2; + } data[] = { + // Bogus input cases. + { "10", false, false, 0, 0, 0, 0, 0 }, + { "10 10", false, false, 0, 0, 0, 0, 0 }, + { "010", false, false, 0, 0, 0, 0, 0 }, + { " 010 ", false, false, 0, 0, 0, 0, 0 }, + { " 10x ", false, false, 0, 0, 0, 0, 0 }, + { " x10 ", false, false, 0, 0, 0, 0, 0 }, + { "any 10x10", false, false, 0, 0, 0, 0, 0 }, + { "", false, false, 0, 0, 0, 0, 0 }, + { "10ax11", false, false, 0, 0, 0, 0, 0 }, + + // Any. + { "any", true, true, 0, 0, 0, 0, 0 }, + { " any", true, true, 0, 0, 0, 0, 0 }, + { " any ", true, true, 0, 0, 0, 0, 0 }, + + // Sizes. + { "10x11", true, false, 1, 10, 11, 0, 0 }, + { " 10x11 ", true, false, 1, 10, 11, 0, 0 }, + { " 10x11 1x2", true, false, 2, 10, 11, 1, 2 }, + }; + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { + bool is_any; + std::vector<gfx::Size> sizes; + bool result = web_apps::ParseIconSizes(ASCIIToUTF16(data[i].input), &sizes, + &is_any); + ASSERT_EQ(result, data[i].expected_result); + if (result) { + ASSERT_EQ(data[i].is_any, is_any); + ASSERT_EQ(data[i].expected_size_count, sizes.size()); + if (sizes.size() > 0) { + ASSERT_EQ(data[i].width1, sizes[0].width()); + ASSERT_EQ(data[i].height1, sizes[0].height()); + } + if (sizes.size() > 1) { + ASSERT_EQ(data[i].width2, sizes[1].width()); + ASSERT_EQ(data[i].height2, sizes[1].height()); + } + } + } +} diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 8dff551..394f779 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -42,6 +42,7 @@ #include "chrome/common/renderer_preferences.h" #include "chrome/common/thumbnail_score.h" #include "chrome/common/url_constants.h" +#include "chrome/common/web_apps.h" #include "chrome/common/window_container_type.h" #include "chrome/renderer/about_handler.h" #include "chrome/renderer/audio_message_filter.h" @@ -3913,9 +3914,12 @@ SkBitmap RenderView::ImageFromDataUrl(const GURL& url) const { } void RenderView::OnGetApplicationInfo(int page_id) { - webkit_glue::WebApplicationInfo app_info; - if (page_id == page_id_) - webkit_glue::GetApplicationInfo(webview(), &app_info); + WebApplicationInfo app_info; + if (page_id == page_id_) { + string16 error; + web_apps::ParseWebAppFromWebDocument(webview()->mainFrame(), &app_info, + &error); + } // Prune out any data URLs in the set of icons. The browser process expects // any icon with a data URL to have originated from a favicon. We don't want diff --git a/chrome/test/data/web_app_info/full.json b/chrome/test/data/web_app_info/full.json new file mode 100644 index 0000000..ef38f53 --- /dev/null +++ b/chrome/test/data/web_app_info/full.json @@ -0,0 +1,14 @@ +{ + "name": "hello", + "description": "This app is super awesome", + "launch_url": "launch_url", + "launch_container": "panel", + "permissions": [ "geolocation", "notifications" ], + "urls": [ "foobar", "baz" ], + "icons": { + "ignored": "ignored.png", + "16": "16.png", + // We also ignore this because it is larger than 128. + "500": "500.png" + } +} diff --git a/chrome/test/data/web_app_info/invalid_icon_url.json b/chrome/test/data/web_app_info/invalid_icon_url.json new file mode 100644 index 0000000..3389d26 --- /dev/null +++ b/chrome/test/data/web_app_info/invalid_icon_url.json @@ -0,0 +1,8 @@ +{ + "name": "hello", + "launch_url": "launch_url", + "icons": { + "16", "16.png", + "32": "http://someotherdomain.com/32" + ] +} diff --git a/chrome/test/data/web_app_info/invalid_launch_url.json b/chrome/test/data/web_app_info/invalid_launch_url.json new file mode 100644 index 0000000..3c9c81e --- /dev/null +++ b/chrome/test/data/web_app_info/invalid_launch_url.json @@ -0,0 +1,4 @@ +{ + "name": "hello", + "launch_url": "http://someotherdomain.com/monkey" +} diff --git a/chrome/test/data/web_app_info/invalid_urls.json b/chrome/test/data/web_app_info/invalid_urls.json new file mode 100644 index 0000000..f347073 --- /dev/null +++ b/chrome/test/data/web_app_info/invalid_urls.json @@ -0,0 +1,9 @@ +{ + "name": "hello", + "launch_url": "launch_url", + "urls": [ + "relative", + "http://example.com/valid_absolute", + "http://someotherdomain.com/invalid_absolute" + ] +} diff --git a/chrome/test/data/web_app_info/minimal.json b/chrome/test/data/web_app_info/minimal.json new file mode 100644 index 0000000..e5b6a6a --- /dev/null +++ b/chrome/test/data/web_app_info/minimal.json @@ -0,0 +1,4 @@ +{ + "name": "hello", + "launch_url": "launch_url" +} diff --git a/chrome/test/data/web_app_info/missing_name.json b/chrome/test/data/web_app_info/missing_name.json new file mode 100644 index 0000000..d1833e5 --- /dev/null +++ b/chrome/test/data/web_app_info/missing_name.json @@ -0,0 +1,3 @@ +{ + "launch_url": "monkey" +} diff --git a/webkit/glue/dom_operations.cc b/webkit/glue/dom_operations.cc index bc546e2..07c43b2 100644 --- a/webkit/glue/dom_operations.cc +++ b/webkit/glue/dom_operations.cc @@ -7,8 +7,7 @@ #include <set> #include "base/compiler_specific.h" -#include "base/string_number_conversions.h" -#include "base/string_split.h" +#include "base/logging.h" #include "base/string_util.h" #include "third_party/WebKit/WebKit/chromium/public/WebAnimationController.h" #include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" @@ -239,139 +238,6 @@ bool GetAllSavableResourceLinksForCurrentPage(WebView* view, return true; } -// Sizes a single size (the width or height) from a 'sizes' attribute. A size -// matches must match the following regex: [1-9][0-9]*. -static int ParseSingleIconSize(const string16& text) { - // Size must not start with 0, and be between 0 and 9. - if (text.empty() || !(text[0] >= L'1' && text[0] <= L'9')) - return 0; - // Make sure all chars are from 0-9. - for (size_t i = 1; i < text.length(); ++i) { - if (!(text[i] >= L'0' && text[i] <= L'9')) - return 0; - } - int output; - if (!base::StringToInt(text, &output)) - return 0; - return output; -} - -// Parses an icon size. An icon size must match the following regex: -// [1-9][0-9]*x[1-9][0-9]*. -// If the input couldn't be parsed, a size with a width/height < 0 is returned. -static gfx::Size ParseIconSize(const string16& text) { - std::vector<string16> sizes; - base::SplitStringDontTrim(text, L'x', &sizes); - if (sizes.size() != 2) - return gfx::Size(); - - return gfx::Size(ParseSingleIconSize(sizes[0]), - ParseSingleIconSize(sizes[1])); -} - -WebApplicationInfo::WebApplicationInfo() {} - -WebApplicationInfo::~WebApplicationInfo() {} - -bool ParseIconSizes(const string16& text, - std::vector<gfx::Size>* sizes, - bool* is_any) { - *is_any = false; - std::vector<string16> size_strings; - base::SplitStringAlongWhitespace(text, &size_strings); - for (size_t i = 0; i < size_strings.size(); ++i) { - if (EqualsASCII(size_strings[i], "any")) { - *is_any = true; - } else { - gfx::Size size = ParseIconSize(size_strings[i]); - if (size.width() <= 0 || size.height() <= 0) - return false; // Bogus size. - sizes->push_back(size); - } - } - if (*is_any && !sizes->empty()) { - // If is_any is true, it must occur by itself. - return false; - } - return (*is_any || !sizes->empty()); -} - -static void AddInstallIcon(const WebElement& link, - std::vector<WebApplicationInfo::IconInfo>* icons) { - WebString href = link.getAttribute("href"); - if (href.isNull() || href.isEmpty()) - return; - - // Get complete url. - GURL url = link.document().completeURL(href); - if (!url.is_valid()) - return; - - if (!link.hasAttribute("sizes")) - return; - - bool is_any = false; - std::vector<gfx::Size> icon_sizes; - if (!ParseIconSizes(link.getAttribute("sizes"), &icon_sizes, &is_any) || - is_any || - icon_sizes.size() != 1) { - return; - } - WebApplicationInfo::IconInfo icon_info; - icon_info.width = icon_sizes[0].width(); - icon_info.height = icon_sizes[0].height(); - icon_info.url = url; - icons->push_back(icon_info); -} - -void GetApplicationInfo(WebView* view, WebApplicationInfo* app_info) { - WebFrame* main_frame = view->mainFrame(); - if (!main_frame) - return; - - WebDocument doc = main_frame->document(); - if (doc.isNull()) - return; - - WebElement head = main_frame->document().head(); - if (head.isNull()) - return; - - WebNodeList children = head.childNodes(); - for (unsigned i = 0; i < children.length(); ++i) { - WebNode child = children.item(i); - if (!child.isElementNode()) - continue; - WebElement elem = child.to<WebElement>(); - - if (elem.hasTagName("link")) { - std::string rel = elem.getAttribute("rel").utf8(); - // "rel" attribute may use either "icon" or "shortcut icon". - // see also - // <http://en.wikipedia.org/wiki/Favicon> - // <http://dev.w3.org/html5/spec/Overview.html#rel-icon> - if (LowerCaseEqualsASCII(rel, "icon") || - LowerCaseEqualsASCII(rel, "shortcut icon")) - AddInstallIcon(elem, &app_info->icons); - } else if (elem.hasTagName("meta") && elem.hasAttribute("name")) { - std::string name = elem.getAttribute("name").utf8(); - WebString content = elem.getAttribute("content"); - if (name == "application-name") { - app_info->title = content; - } else if (name == "description") { - app_info->description = content; - } else if (name == "application-url") { - std::string url = content.utf8(); - GURL main_url = main_frame->url(); - app_info->app_url = main_url.is_valid() ? - main_url.Resolve(url) : GURL(url); - if (!app_info->app_url.is_valid()) - app_info->app_url = GURL(); - } - } - } -} - bool PauseAnimationAtTimeOnElementWithId(WebView* view, const std::string& animation_name, double time, diff --git a/webkit/glue/dom_operations.h b/webkit/glue/dom_operations.h index 951eb0f..924878f 100644 --- a/webkit/glue/dom_operations.h +++ b/webkit/glue/dom_operations.h @@ -8,7 +8,6 @@ #include <string> #include <vector> -#include "gfx/size.h" #include "googleurl/src/gurl.h" namespace WebKit { @@ -54,48 +53,6 @@ bool GetAllSavableResourceLinksForCurrentPage(WebKit::WebView* view, const GURL& page_url, SavableResourcesResult* savable_resources_result, const char** savable_schemes); -// Structure used when installing a web page as an app. Populated via -// GetApplicationInfo. -struct WebApplicationInfo { - WebApplicationInfo(); - ~WebApplicationInfo(); - - struct IconInfo { - GURL url; - int width; - int height; - }; - - // Title of the application. This is set from the meta tag whose name is - // 'application-name'. - string16 title; - - // Description of the application. This is set from the meta tag whose name - // is 'description'. - string16 description; - - // URL for the app. This is set from the meta tag whose name is - // 'application-url'. - GURL app_url; - - // Set of available icons. This is set for all link tags whose rel=icon. Only - // icons that have a non-zero (width and/or height) are added. - std::vector<IconInfo> icons; -}; - -// Parses the icon's size attribute as defined in the HTML 5 spec. Returns true -// on success, false on errors. On success either all the sizes specified in -// the attribute are added to sizes, or is_any is set to true. -// -// You shouldn't have a need to invoke this directly, it's public for testing. -bool ParseIconSizes(const string16& text, - std::vector<gfx::Size>* sizes, - bool* is_any); - -// Gets the application info for the specified page. See the description of -// WebApplicationInfo for details as to where each field comes from. -void GetApplicationInfo(WebKit::WebView* view, WebApplicationInfo* app_info); - // Invokes pauseAnimationAtTime on the AnimationController associated with the // |view|s main frame. // This is used by test shell. diff --git a/webkit/glue/dom_operations_unittest.cc b/webkit/glue/dom_operations_unittest.cc index c57e943..fac49c6 100644 --- a/webkit/glue/dom_operations_unittest.cc +++ b/webkit/glue/dom_operations_unittest.cc @@ -128,58 +128,4 @@ TEST_F(DomOperationsTests, GetSavableResourceLinksWithPageHasInvalidLinks) { GetSavableResourceLinksForPage(page_file_path, expected_resources_set); } -// Tests ParseIconSizes with various input. -TEST_F(DomOperationsTests, ParseIconSizes) { - struct TestData { - const char* input; - const bool expected_result; - const bool is_any; - const size_t expected_size_count; - const int width1; - const int height1; - const int width2; - const int height2; - } data[] = { - // Bogus input cases. - { "10", false, false, 0, 0, 0, 0, 0 }, - { "10 10", false, false, 0, 0, 0, 0, 0 }, - { "010", false, false, 0, 0, 0, 0, 0 }, - { " 010 ", false, false, 0, 0, 0, 0, 0 }, - { " 10x ", false, false, 0, 0, 0, 0, 0 }, - { " x10 ", false, false, 0, 0, 0, 0, 0 }, - { "any 10x10", false, false, 0, 0, 0, 0, 0 }, - { "", false, false, 0, 0, 0, 0, 0 }, - { "10ax11", false, false, 0, 0, 0, 0, 0 }, - - // Any. - { "any", true, true, 0, 0, 0, 0, 0 }, - { " any", true, true, 0, 0, 0, 0, 0 }, - { " any ", true, true, 0, 0, 0, 0, 0 }, - - // Sizes. - { "10x11", true, false, 1, 10, 11, 0, 0 }, - { " 10x11 ", true, false, 1, 10, 11, 0, 0 }, - { " 10x11 1x2", true, false, 2, 10, 11, 1, 2 }, - }; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(data); ++i) { - bool is_any; - std::vector<gfx::Size> sizes; - bool result = webkit_glue::ParseIconSizes( - ASCIIToUTF16(data[i].input), &sizes, &is_any); - ASSERT_EQ(result, data[i].expected_result); - if (result) { - ASSERT_EQ(data[i].is_any, is_any); - ASSERT_EQ(data[i].expected_size_count, sizes.size()); - if (sizes.size() > 0) { - ASSERT_EQ(data[i].width1, sizes[0].width()); - ASSERT_EQ(data[i].height1, sizes[0].height()); - } - if (sizes.size() > 1) { - ASSERT_EQ(data[i].width2, sizes[1].width()); - ASSERT_EQ(data[i].height2, sizes[1].height()); - } - } - } -} - } // namespace |