diff options
author | mihaip@chromium.org <mihaip@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-03 00:43:33 +0000 |
---|---|---|
committer | mihaip@chromium.org <mihaip@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-03 00:43:33 +0000 |
commit | 8df666b5d0c0ff82ebcfeba28da4bcb1d364002e (patch) | |
tree | 4af2e4069efb2e39e54260668257a396a95a8903 | |
parent | 93321cb3d5ee92edef64ba8b93f8cc2869dd0344 (diff) | |
download | chromium_src-8df666b5d0c0ff82ebcfeba28da4bcb1d364002e.zip chromium_src-8df666b5d0c0ff82ebcfeba28da4bcb1d364002e.tar.gz chromium_src-8df666b5d0c0ff82ebcfeba28da4bcb1d364002e.tar.bz2 |
Shim that simulates a <browser> tag via Mutation Observers.
The actual tag is implemented via the browser plugin. The internals of this
are hidden via Shadow DOM.
Also fixes a bug with Shadow DOM not being enabled for all extensions views.
BUG=133379
Review URL: https://chromiumcodereview.appspot.com/10598006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@145229 0039d316-1c4b-4281-b951-d872f2087c98
21 files changed, 278 insertions, 23 deletions
diff --git a/chrome/browser/extensions/platform_app_browsertest.cc b/chrome/browser/extensions/platform_app_browsertest.cc index 49f83f1..4aee2bf 100644 --- a/chrome/browser/extensions/platform_app_browsertest.cc +++ b/chrome/browser/extensions/platform_app_browsertest.cc @@ -278,3 +278,7 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OpenLink) { observer.Wait(); ASSERT_EQ(2, browser()->tab_count()); } + +IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, BrowserTag) { + ASSERT_TRUE(RunPlatformAppTest("platform_apps/browser_tag")) << message_; +} diff --git a/chrome/browser/extensions/shadow_dom_apitest.cc b/chrome/browser/extensions/shadow_dom_apitest.cc new file mode 100644 index 0000000..f53d5d4 --- /dev/null +++ b/chrome/browser/extensions/shadow_dom_apitest.cc @@ -0,0 +1,15 @@ +// Copyright (c) 2012 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 "base/command_line.h" +#include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/common/chrome_switches.h" + +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ShadowDom) { + // Shadow DOM is exposed to extensions with the experimental permission only. + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableExperimentalExtensionApis); + + ASSERT_TRUE(RunExtensionTest("shadow_dom")) << message_; +} diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index 1ca5ff2..1171d28 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -148,6 +148,7 @@ 'renderer/resources/extensions/apitest.js', 'renderer/resources/extensions/app_custom_bindings.js', 'renderer/resources/extensions/browser_action_custom_bindings.js', + 'renderer/resources/extensions/browser_tag.js', 'renderer/resources/extensions/context_menus_custom_bindings.js', 'renderer/resources/extensions/declarative_webrequest_custom_bindings.js', 'renderer/resources/extensions/devtools_custom_bindings.js', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 167ad85..b41ecfa 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -2832,6 +2832,7 @@ 'browser/extensions/plugin_apitest.cc', 'browser/extensions/process_management_browsertest.cc', 'browser/extensions/sandboxed_pages_apitest.cc', + 'browser/extensions/shadow_dom_apitest.cc', 'browser/extensions/settings/settings_apitest.cc', 'browser/extensions/stubs_apitest.cc', 'browser/extensions/subscribe_page_action_browsertest.cc', diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json index 8888066..34aefe3 100644 --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json @@ -35,6 +35,10 @@ "channel": "stable", "extension_types": ["extension", "packaged_app"] }, + "browserTag": { + "channel": "dev", + "extension_types": ["extension", "platform_app"] + }, "browsingData": { "channel": "stable", "extension_types": ["extension", "packaged_app"] diff --git a/chrome/common/extensions/permissions/api_permission.cc b/chrome/common/extensions/permissions/api_permission.cc index 753b356..8d1b8ee 100644 --- a/chrome/common/extensions/permissions/api_permission.cc +++ b/chrome/common/extensions/permissions/api_permission.cc @@ -79,6 +79,7 @@ void APIPermission::RegisterAllPermissions( { kBookmark, "bookmarks", kFlagNone, IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS, PermissionMessage::kBookmarks }, + { kBrowserTag, "browserTag", kFlagCannotBeOptional }, { kBrowsingData, "browsingData" }, { kContentSettings, "contentSettings", kFlagNone, IDS_EXTENSION_PROMPT_WARNING_CONTENT_SETTINGS, diff --git a/chrome/common/extensions/permissions/api_permission.h b/chrome/common/extensions/permissions/api_permission.h index 917833a..c3132b7 100644 --- a/chrome/common/extensions/permissions/api_permission.h +++ b/chrome/common/extensions/permissions/api_permission.h @@ -31,6 +31,7 @@ class APIPermission { kAudioCapture, kBackground, kBookmark, + kBrowserTag, kBrowsingData, kChromeAuthPrivate, kChromeosInfoPrivate, diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc index a4ec251..2f0a1c7 100644 --- a/chrome/common/extensions/permissions/permission_set_unittest.cc +++ b/chrome/common/extensions/permissions/permission_set_unittest.cc @@ -578,6 +578,7 @@ TEST(PermissionsTest, PermissionMessages) { skip.insert(APIPermission::kAlarms); skip.insert(APIPermission::kAppNotifications); skip.insert(APIPermission::kAppWindow); + skip.insert(APIPermission::kBrowserTag); skip.insert(APIPermission::kBrowsingData); skip.insert(APIPermission::kContextMenus); skip.insert(APIPermission::kDeclarative); diff --git a/chrome/renderer/chrome_render_view_observer.cc b/chrome/renderer/chrome_render_view_observer.cc index 3958597..5093e43 100644 --- a/chrome/renderer/chrome_render_view_observer.cc +++ b/chrome/renderer/chrome_render_view_observer.cc @@ -70,6 +70,7 @@ using WebKit::WebURL; using WebKit::WebURLRequest; using WebKit::WebView; using WebKit::WebVector; +using extensions::APIPermission; using webkit_glue::ImageResourceFetcher; // Delay in milliseconds that we'll wait before capturing the page contents @@ -482,31 +483,40 @@ bool ChromeRenderViewObserver::allowWriteToClipboard(WebFrame* frame, return allowed; } -bool ChromeRenderViewObserver::IsExperimentalWebFeatureAllowed( - const WebDocument& document) { - // Experimental Web API is enabled when - // - The specific API is allowed from command line flag, or - // - If the document is running extensions or apps which - // has the "experimental" permission, or - // - The document is running Web UI. - WebSecurityOrigin origin = document.securityOrigin(); - if (EqualsASCII(origin.protocol(), chrome::kChromeUIScheme)) - return true; +bool ChromeRenderViewObserver::HasExtensionPermission( + const WebSecurityOrigin& origin, APIPermission::ID permission) const { + if (!EqualsASCII(origin.protocol(), chrome::kExtensionScheme)) + return false; + + const std::string extension_id = origin.host().utf8().data(); + if (!extension_dispatcher_->IsExtensionActive(extension_id)) + return false; + const extensions::Extension* extension = - extension_dispatcher_->extensions()->GetExtensionOrAppByURL( - ExtensionURLInfo(origin, document.url())); + extension_dispatcher_->extensions()->GetByID(extension_id); if (!extension) return false; - return (extension_dispatcher_->IsExtensionActive(extension->id()) && - extension->HasAPIPermission( - extensions::APIPermission::kExperimental)); + + return extension->HasAPIPermission(permission); } bool ChromeRenderViewObserver::allowWebComponents(const WebDocument& document, bool defaultValue) { if (defaultValue) return true; - return IsExperimentalWebFeatureAllowed(document); + + WebSecurityOrigin origin = document.securityOrigin(); + if (EqualsASCII(origin.protocol(), chrome::kChromeUIScheme)) + return true; + + // The <browser> tag is implemented via Shadow DOM. + if (HasExtensionPermission(origin, APIPermission::kBrowserTag)) + return true; + + if (HasExtensionPermission(origin, APIPermission::kExperimental)) + return true; + + return false; } static void SendInsecureContentSignal(int signal) { diff --git a/chrome/renderer/chrome_render_view_observer.h b/chrome/renderer/chrome_render_view_observer.h index 57a28a8..ac48adf 100644 --- a/chrome/renderer/chrome_render_view_observer.h +++ b/chrome/renderer/chrome_render_view_observer.h @@ -13,6 +13,7 @@ #include "base/memory/linked_ptr.h" #include "base/memory/scoped_ptr.h" #include "base/timer.h" +#include "chrome/common/extensions/permissions/api_permission.h" #include "content/public/renderer/render_view_observer.h" #include "googleurl/src/gurl.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebPermissionClient.h" @@ -183,8 +184,10 @@ class ChromeRenderViewObserver : public content::RenderViewObserver, // Determines if a host is in the strict security host set. bool IsStrictSecurityHost(const std::string& host); - // Determines if the document has a permission to use experimental Web API - bool IsExperimentalWebFeatureAllowed(const WebKit::WebDocument& document); + // Checks if |origin| correponds to an installed extension that has been + // granted the |permission|. + bool HasExtensionPermission(const WebKit::WebSecurityOrigin& origin, + extensions::APIPermission::ID permission) const; // Save the JavaScript to preload if a ViewMsg_WebUIJavaScript is received. scoped_ptr<WebUIJavaScript> webui_javascript_; diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc index 7ef396f..a7da860 100644 --- a/chrome/renderer/extensions/extension_dispatcher.cc +++ b/chrome/renderer/extensions/extension_dispatcher.cc @@ -75,6 +75,7 @@ using WebKit::WebVector; using WebKit::WebView; using content::RenderThread; using content::RenderView; +using extensions::APIPermission; using extensions::ApiDefinitionsNatives; using extensions::AppWindowCustomBindings; using extensions::ContextMenusCustomBindings; @@ -597,7 +598,6 @@ void ExtensionDispatcher::PopulateSourceMap() { source_map_.RegisterSource("pageAction", IDR_PAGE_ACTION_CUSTOM_BINDINGS_JS); source_map_.RegisterSource("pageCapture", IDR_PAGE_CAPTURE_CUSTOM_BINDINGS_JS); - source_map_.RegisterSource("platformApp", IDR_PLATFORM_APP_JS); source_map_.RegisterSource("runtime", IDR_RUNTIME_CUSTOM_BINDINGS_JS); source_map_.RegisterSource("storage", IDR_STORAGE_CUSTOM_BINDINGS_JS); source_map_.RegisterSource("tabs", IDR_TABS_CUSTOM_BINDINGS_JS); @@ -608,6 +608,10 @@ void ExtensionDispatcher::PopulateSourceMap() { source_map_.RegisterSource("webRequestInternal", IDR_WEB_REQUEST_INTERNAL_CUSTOM_BINDINGS_JS); source_map_.RegisterSource("webstore", IDR_WEBSTORE_CUSTOM_BINDINGS_JS); + + // Platform app sources that are not API-specific.. + source_map_.RegisterSource("browserTag", IDR_BROWSER_TAG_JS); + source_map_.RegisterSource("platformApp", IDR_PLATFORM_APP_JS); } void ExtensionDispatcher::PopulateLazyBindingsMap() { @@ -726,6 +730,11 @@ void ExtensionDispatcher::DidCreateScriptContext( if (IsWithinPlatformApp(frame)) module_system->Require("platformApp"); + if (context_type == Feature::BLESSED_EXTENSION_CONTEXT && + extension && extension->HasAPIPermission(APIPermission::kBrowserTag)) { + module_system->Require("browserTag"); + } + context->set_module_system(module_system.Pass()); int manifest_version = 1; @@ -792,7 +801,7 @@ void ExtensionDispatcher::InitOriginPermissions(const Extension* extension) { // TODO(jstritar): We should try to remove this special case. Also, these // whitelist entries need to be updated when the kManagement permission // changes. - if (extension->HasAPIPermission(extensions::APIPermission::kManagement)) { + if (extension->HasAPIPermission(APIPermission::kManagement)) { WebSecurityPolicy::addOriginAccessWhitelistEntry( extension->url(), WebString::fromUTF8(chrome::kChromeUIScheme), diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd index 85675bc..eb63855 100644 --- a/chrome/renderer/renderer_resources.grd +++ b/chrome/renderer/renderer_resources.grd @@ -24,8 +24,6 @@ without changes to the corresponding grd file. fb9 --> <include name="IDR_JSON_SCHEMA_JS" file="resources\extensions\json_schema.js" type="BINDATA" /> <include name="IDR_MISCELLANEOUS_BINDINGS_JS" file="resources\extensions\miscellaneous_bindings.js" type="BINDATA" /> <include name="IDR_NET_ERROR_HTML" file="resources\neterror.html" flattenhtml="true" type="BINDATA" /> - <include name="IDR_PLATFORM_APP_CSS" file="resources\extensions\platform_app.css" type="BINDATA" /> - <include name="IDR_PLATFORM_APP_JS" file="resources\extensions\platform_app.js" type="BINDATA" /> <include name="IDR_SAD_PLUGIN" file="resources\sadplugin.png" type="BINDATA" /> <include name="IDR_SCHEMA_GENERATED_BINDINGS_JS" file="resources\extensions\schema_generated_bindings.js" type="BINDATA" /> @@ -35,11 +33,12 @@ without changes to the corresponding grd file. fb9 --> <include name="IDR_SET_ICON_JS" file="resources\extensions\set_icon.js" type="BINDATA" /> <include name="IDR_UTILS_JS" file="resources\extensions\utils.js" type="BINDATA" /> - <!-- Custom bindings for extension APIs. --> <if expr="pp_ifdef('enable_extensions')"> + <!-- Custom bindings for extension APIs. --> <include name="IDR_APP_CUSTOM_BINDINGS_JS" file="resources\extensions\app_custom_bindings.js" type="BINDATA" /> <include name="IDR_APP_WINDOW_CUSTOM_BINDINGS_JS" file="resources\extensions\app_window_custom_bindings.js" type="BINDATA" /> <include name="IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS" file="resources\extensions\browser_action_custom_bindings.js" type="BINDATA" /> + <include name="IDR_BROWSER_TAG_JS" file="resources\extensions\browser_tag.js" type="BINDATA" /> <include name="IDR_CONTENT_SETTINGS_CUSTOM_BINDINGS_JS" file="resources\extensions\content_settings_custom_bindings.js" type="BINDATA" /> <include name="IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS" file="resources\extensions\context_menus_custom_bindings.js" type="BINDATA" /> <include name="IDR_DECLARATIVE_WEBREQUEST_CUSTOM_BINDINGS_JS" file="resources\extensions\declarative_webrequest_custom_bindings.js" type="BINDATA" /> @@ -68,6 +67,10 @@ without changes to the corresponding grd file. fb9 --> <include name="IDR_WEB_REQUEST_CUSTOM_BINDINGS_JS" file="resources\extensions\web_request_custom_bindings.js" type="BINDATA" /> <include name="IDR_WEB_REQUEST_INTERNAL_CUSTOM_BINDINGS_JS" file="resources\extensions\web_request_internal_custom_bindings.js" type="BINDATA" /> <include name="IDR_WEBSTORE_CUSTOM_BINDINGS_JS" file="resources\extensions\webstore_custom_bindings.js" type="BINDATA" /> + + <!-- Platform app support. --> + <include name="IDR_PLATFORM_APP_CSS" file="resources\extensions\platform_app.css" type="BINDATA" /> + <include name="IDR_PLATFORM_APP_JS" file="resources\extensions\platform_app.js" type="BINDATA" /> </if> </includes> </release> diff --git a/chrome/renderer/resources/extensions/browser_tag.js b/chrome/renderer/resources/extensions/browser_tag.js new file mode 100644 index 0000000..796eb34 --- /dev/null +++ b/chrome/renderer/resources/extensions/browser_tag.js @@ -0,0 +1,90 @@ +// Copyright (c) 2012 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. + +// Shim that simulates a <browser> tag via Mutation Observers. +// +// The actual tag is implemented via the browser plugin. The internals of this +// are hidden via Shadow DOM. + +var BROWSER_TAG_ATTRIBUTES = ['src', 'width', 'height']; + +// Handle <browser> tags already in the document. +window.addEventListener('DOMContentLoaded', function() { + var browserNodes = document.body.querySelectorAll('browser'); + for (var i = 0, browserNode; browserNode = browserNodes[i]; i++) { + new BrowserTag(browserNode); + } +}); + +// Handle <browser> tags added later. +var observer = new WebKitMutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + for (var i = 0, addedNode; addedNode = mutation.addedNodes[i]; i++) { + if (addedNode.tagName == 'BROWSER') { + new BrowserTag(addedNode); + } + } + }); +}); +observer.observe(document, {subtree: true, childList: true}); + +/** + * @constructor + */ +function BrowserTag(node) { + this.node_ = node; + var shadowRoot = new WebKitShadowRoot(node); + + this.objectNode_ = document.createElement('object'); + this.objectNode_.type = 'application/browser-plugin'; + BROWSER_TAG_ATTRIBUTES.forEach(this.copyAttribute_, this); + shadowRoot.appendChild(this.objectNode_); + + // Map attribute modifications on the <browser> tag to changes on the + // underlying <object> node. + var handleMutation = this.handleMutation_.bind(this); + var observer = new WebKitMutationObserver(function(mutations) { + mutations.forEach(handleMutation); + }); + observer.observe( + this.node_, + {attributes: true, attributeFilter: BROWSER_TAG_ATTRIBUTES}); + + // Expose getters and setters for the attributes. + BROWSER_TAG_ATTRIBUTES.forEach(function(attributeName) { + Object.defineProperty(this.node_, attributeName, { + get: function() { + var value = node.getAttribute(attributeName); + var numericValue = parseInt(value, 10); + return isNaN(numericValue) ? value : numericValue; + }, + set: function(value) { + node.setAttribute(attributeName, value); + }, + enumerable: true + }); + }, this); +}; + +/** + * @private + */ +BrowserTag.prototype.handleMutation_ = function(mutation) { + switch (mutation.attributeName) { + case 'src': + this.objectNode_.postMessage(this.node_.getAttribute('src')); + break; + default: + this.copyAttribute_(mutation.attributeName); + break; + } +}; + +/** + * @private + */ +BrowserTag.prototype.copyAttribute_ = function(attributeName) { + this.objectNode_.setAttribute( + attributeName, this.node_.getAttribute(attributeName)); +}; diff --git a/chrome/renderer/resources/extensions/platform_app.css b/chrome/renderer/resources/extensions/platform_app.css index 7976a85..6f26923 100644 --- a/chrome/renderer/resources/extensions/platform_app.css +++ b/chrome/renderer/resources/extensions/platform_app.css @@ -12,3 +12,7 @@ body { -webkit-user-select: none; cursor: default; } + +browser { + display: inline-block; +} diff --git a/chrome/test/data/extensions/api_test/shadow_dom/background.js b/chrome/test/data/extensions/api_test/shadow_dom/background.js new file mode 100644 index 0000000..e2e4428 --- /dev/null +++ b/chrome/test/data/extensions/api_test/shadow_dom/background.js @@ -0,0 +1,16 @@ +// Copyright (c) 2012 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. + +chrome.test.runTests([ + function currentWindow() { + chrome.test.assertTrue('WebKitShadowRoot' in window); + chrome.test.succeed(); + }, + + function newWindow() { + var w = window.open('empty.html'); + chrome.test.assertTrue('WebKitShadowRoot' in w); + chrome.test.succeed(); + } +]); diff --git a/chrome/test/data/extensions/api_test/shadow_dom/empty.html b/chrome/test/data/extensions/api_test/shadow_dom/empty.html new file mode 100644 index 0000000..1f1a5c18 --- /dev/null +++ b/chrome/test/data/extensions/api_test/shadow_dom/empty.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<html> +<head> + <title>Just an empty window</title> +</head> +<body> +</body> +</html> diff --git a/chrome/test/data/extensions/api_test/shadow_dom/manifest.json b/chrome/test/data/extensions/api_test/shadow_dom/manifest.json new file mode 100644 index 0000000..e77681b --- /dev/null +++ b/chrome/test/data/extensions/api_test/shadow_dom/manifest.json @@ -0,0 +1,9 @@ +{ + "name": "Shadow DOM API Test", + "version": "0.1", + "manifest_version": 2, + "background": { + "scripts": ["background.js"] + }, + "permissions": [ "experimental" ] +} diff --git a/chrome/test/data/extensions/platform_apps/browser_tag/main.html b/chrome/test/data/extensions/platform_apps/browser_tag/main.html new file mode 100644 index 0000000..3b6711ec --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/browser_tag/main.html @@ -0,0 +1,12 @@ +<!-- + * Copyright (c) 2012 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. +--> +<html> +<body> +<browser src="data:text/html,hello world" width="300" height="200"></browser> + +<script src="main.js"></script> +</body> +</html> diff --git a/chrome/test/data/extensions/platform_apps/browser_tag/main.js b/chrome/test/data/extensions/platform_apps/browser_tag/main.js new file mode 100644 index 0000000..98a8642 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/browser_tag/main.js @@ -0,0 +1,41 @@ +// Copyright (c) 2012 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. + +onload = function() { + chrome.test.runTests([ + function browserTag() { + var browserTag = document.querySelector('browser'); + // Since we can't currently inspect the page loaded inside the <browser>, + // the only way we can check that the shim is working is by changing the + // size and seeing if the shim updates the size of the DOM. + chrome.test.assertEq(300, browserTag.offsetWidth); + chrome.test.assertEq(200, browserTag.offsetHeight); + + browserTag.setAttribute('width', 310); + browserTag.setAttribute('height', 210); + + // Timeout is necessary to give the mutation observers a chance to fire. + setTimeout(function() { + chrome.test.assertEq(310, browserTag.offsetWidth); + chrome.test.assertEq(210, browserTag.offsetHeight); + + // Should also be able to query/update the dimensions via getterts/ + // setters. + chrome.test.assertEq(310, browserTag.width); + chrome.test.assertEq(210, browserTag.height); + + browserTag.width = 320; + browserTag.height = 220; + + // Setters also end up operating via mutation observers. + setTimeout(function() { + chrome.test.assertEq(320, browserTag.offsetWidth); + chrome.test.assertEq(220, browserTag.offsetHeight); + + chrome.test.succeed(); + }, 0); + }, 0); + } + ]); +}; diff --git a/chrome/test/data/extensions/platform_apps/browser_tag/manifest.json b/chrome/test/data/extensions/platform_apps/browser_tag/manifest.json new file mode 100644 index 0000000..660c0c9 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/browser_tag/manifest.json @@ -0,0 +1,15 @@ +{ + "name": "Platform App Test: <browser>", + "version": "1", + "manifest_version": 2, + "permissions": [ + "experimental", + "appWindow", + "browserTag" + ], + "app": { + "background": { + "scripts": ["test.js"] + } + } +} diff --git a/chrome/test/data/extensions/platform_apps/browser_tag/test.js b/chrome/test/data/extensions/platform_apps/browser_tag/test.js new file mode 100644 index 0000000..ce719f7 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/browser_tag/test.js @@ -0,0 +1,7 @@ +// Copyright (c) 2012 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. + +chrome.experimental.app.onLaunched.addListener(function() { + chrome.appWindow.create('main.html', {}, function () {}); +}); |