summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-17 05:14:15 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-17 05:14:15 +0000
commit1631f7c651fbc7f4460a852126f545afc5513531 (patch)
tree7176f3052f69c0c0debf48172d533f9acc4c83d3
parent42a17153ee389574560b91b185bcec6c4db5b5c3 (diff)
downloadchromium_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
-rw-r--r--chrome/browser/gears_integration.cc8
-rw-r--r--chrome/browser/gears_integration.h13
-rw-r--r--chrome/browser/renderer_host/render_view_host.cc3
-rw-r--r--chrome/browser/renderer_host/render_view_host.h5
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.h7
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc5
-rw-r--r--chrome/browser/tab_contents/tab_contents.h11
-rw-r--r--chrome/browser/tab_contents/tab_contents_delegate.h4
-rw-r--r--chrome/browser/ui/views/create_application_shortcut_view.cc3
-rw-r--r--chrome/browser/web_applications/web_app.cc12
-rw-r--r--chrome/browser/web_applications/web_app.h6
-rw-r--r--chrome/browser/web_applications/web_app_unittest.cc2
-rw-r--r--chrome/chrome_common.gypi4
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/common_param_traits.cc14
-rw-r--r--chrome/common/common_param_traits.h6
-rw-r--r--chrome/common/common_resources.grd1
-rw-r--r--chrome/common/render_messages.cc2
-rw-r--r--chrome/common/render_messages_internal.h2
-rw-r--r--chrome/common/web_app_schema.json58
-rw-r--r--chrome/common/web_apps.cc323
-rw-r--r--chrome/common/web_apps.h109
-rw-r--r--chrome/common/web_apps_unittest.cc190
-rw-r--r--chrome/renderer/render_view.cc10
-rw-r--r--chrome/test/data/web_app_info/full.json14
-rw-r--r--chrome/test/data/web_app_info/invalid_icon_url.json8
-rw-r--r--chrome/test/data/web_app_info/invalid_launch_url.json4
-rw-r--r--chrome/test/data/web_app_info/invalid_urls.json9
-rw-r--r--chrome/test/data/web_app_info/minimal.json4
-rw-r--r--chrome/test/data/web_app_info/missing_name.json3
-rw-r--r--webkit/glue/dom_operations.cc136
-rw-r--r--webkit/glue/dom_operations.h43
-rw-r--r--webkit/glue/dom_operations_unittest.cc54
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