Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(550)

Side by Side Diff: chrome/browser/extensions/api/app_window/app_window_api.cc

Issue 166443004: Add frame color option to packaged app windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/app_window/app_window_api.h" 5 #include "chrome/browser/extensions/api/app_window/app_window_api.h"
6 6
7 #include "apps/app_window.h" 7 #include "apps/app_window.h"
8 #include "apps/app_window_contents.h" 8 #include "apps/app_window_contents.h"
9 #include "apps/app_window_registry.h" 9 #include "apps/app_window_registry.h"
10 #include "apps/ui/native_app_window.h" 10 #include "apps/ui/native_app_window.h"
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/strings/string_number_conversions.h"
12 #include "base/time/time.h" 13 #include "base/time/time.h"
13 #include "base/values.h" 14 #include "base/values.h"
14 #include "chrome/browser/app_mode/app_mode_utils.h" 15 #include "chrome/browser/app_mode/app_mode_utils.h"
15 #include "chrome/browser/devtools/devtools_window.h" 16 #include "chrome/browser/devtools/devtools_window.h"
16 #include "chrome/browser/extensions/window_controller.h" 17 #include "chrome/browser/extensions/window_controller.h"
17 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/apps/chrome_shell_window_delegate.h" 19 #include "chrome/browser/ui/apps/chrome_shell_window_delegate.h"
19 #include "chrome/common/extensions/api/app_window.h" 20 #include "chrome/common/extensions/api/app_window.h"
20 #include "chrome/common/extensions/features/feature_channel.h" 21 #include "chrome/common/extensions/features/feature_channel.h"
21 #include "content/public/browser/notification_registrar.h" 22 #include "content/public/browser/notification_registrar.h"
22 #include "content/public/browser/notification_types.h" 23 #include "content/public/browser/notification_types.h"
23 #include "content/public/browser/render_process_host.h" 24 #include "content/public/browser/render_process_host.h"
24 #include "content/public/browser/render_view_host.h" 25 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/web_contents.h" 26 #include "content/public/browser/web_contents.h"
26 #include "content/public/common/url_constants.h" 27 #include "content/public/common/url_constants.h"
27 #include "extensions/browser/extensions_browser_client.h" 28 #include "extensions/browser/extensions_browser_client.h"
28 #include "extensions/common/switches.h" 29 #include "extensions/common/switches.h"
30 #include "third_party/skia/include/core/SkColor.h"
29 #include "ui/base/ui_base_types.h" 31 #include "ui/base/ui_base_types.h"
30 #include "ui/gfx/rect.h" 32 #include "ui/gfx/rect.h"
31 #include "url/gurl.h" 33 #include "url/gurl.h"
32 34
33 #if defined(USE_ASH) 35 #if defined(USE_ASH)
34 #include "ash/shell.h" 36 #include "ash/shell.h"
35 #include "ui/aura/root_window.h" 37 #include "ui/aura/root_window.h"
36 #include "ui/aura/window.h" 38 #include "ui/aura/window.h"
37 #endif 39 #endif
38 40
39 using apps::AppWindow; 41 using apps::AppWindow;
40 42
41 namespace app_window = extensions::api::app_window; 43 namespace app_window = extensions::api::app_window;
42 namespace Create = app_window::Create; 44 namespace Create = app_window::Create;
43 45
44 namespace extensions { 46 namespace extensions {
45 47
46 namespace app_window_constants { 48 namespace app_window_constants {
47 const char kInvalidWindowId[] = 49 const char kInvalidWindowId[] =
48 "The window id can not be more than 256 characters long."; 50 "The window id can not be more than 256 characters long.";
49 } 51 const char kInvalidColorSpecification[] =
52 "The color specification could not be parsed.";
53 const char kInvalidChannelForFrameOptions[] =
54 "frameOptions is only available in dev channel.";
55 const char kFrameOptionsAndFrame[] =
56 "Only one of frame and frameOptions can be supplied.";
57 const char kColorWithFrameNone[] = "Windows with no frame cannot have a color.";
58 } // namespace app_window_constants
50 59
51 const char kNoneFrameOption[] = "none"; 60 const char kNoneFrameOption[] = "none";
52 const char kHtmlFrameOption[] = "experimental-html";
53 61
54 namespace { 62 namespace {
55 63
56 // Opens an inspector window and delays the response to the 64 // Opens an inspector window and delays the response to the
57 // AppWindowCreateFunction until the DevToolsWindow has finished loading, and is 65 // AppWindowCreateFunction until the DevToolsWindow has finished loading, and is
58 // ready to stop on breakpoints in the callback. 66 // ready to stop on breakpoints in the callback.
59 class DevToolsRestorer : public base::RefCounted<DevToolsRestorer> { 67 class DevToolsRestorer : public base::RefCounted<DevToolsRestorer> {
60 public: 68 public:
61 DevToolsRestorer(AppWindowCreateFunction* delayed_create_function, 69 DevToolsRestorer(AppWindowCreateFunction* delayed_create_function,
62 content::RenderViewHost* created_view) 70 content::RenderViewHost* created_view)
(...skipping 12 matching lines...) Expand all
75 ~DevToolsRestorer() {} 83 ~DevToolsRestorer() {}
76 84
77 void LoadCompleted() { 85 void LoadCompleted() {
78 delayed_create_function_->SendDelayedResponse(); 86 delayed_create_function_->SendDelayedResponse();
79 Release(); 87 Release();
80 } 88 }
81 89
82 scoped_refptr<AppWindowCreateFunction> delayed_create_function_; 90 scoped_refptr<AppWindowCreateFunction> delayed_create_function_;
83 }; 91 };
84 92
93 bool ParseCSSColorString(const std::string& color_string, SkColor* result) {
Matt Giuca 2014/02/18 06:03:18 It's kind of surprising that there isn't already s
benwells 2014/02/18 07:47:25 Yeah I forgot I had copy pasted this :-/ Using th
94 std::string formatted_color = "#";
Matt Giuca 2014/02/18 06:03:18 Nit: Why does formatted_color need to start with a
95 // Check the string for incorrect formatting.
96 if (color_string[0] != '#')
Matt Giuca 2014/02/18 06:03:18 if (color_string.empty() || ...) (potential buffer
benwells 2014/02/18 07:47:25 Done.
97 return false;
98
99 // Convert the string from #FFF format to #FFFFFF format.
100 if (color_string.length() == 4) {
101 for (size_t i = 1; i < color_string.length(); i++) {
Matt Giuca 2014/02/18 06:03:18 Why not: i < 4 Also: ++i
benwells 2014/02/18 07:47:25 Done.
102 formatted_color += color_string[i];
103 formatted_color += color_string[i];
104 }
105 } else {
Matt Giuca 2014/02/18 06:03:18 How about: // You could even move this first, sinc
benwells 2014/02/18 07:47:25 Done. I think a DCHECK is unwarranted.
106 formatted_color = color_string;
107 }
108
109 if (formatted_color.length() != 7)
110 return false;
111
112 // Convert the string to an integer and make sure it is in the correct value
113 // range.
114 int color_ints[3] = {0};
Matt Giuca 2014/02/18 06:03:18 Use HexStringToBytes instead of manually looping.
benwells 2014/02/18 07:47:25 Done.
115 for (int i = 0; i < 3; i++) {
Matt Giuca 2014/02/18 06:03:18 Nit: ++i
benwells 2014/02/18 07:47:25 Done.
116 if (!base::HexStringToInt(formatted_color.substr(1 + (2 * i), 2),
117 color_ints + i))
Matt Giuca 2014/02/18 06:03:18 Nit: &color_ints[i]
118 return false;
119 if (color_ints[i] > 255 || color_ints[i] < 0)
Matt Giuca 2014/02/18 06:03:18 This should be a DCHECK, since it is not physicall
120 return false;
121 }
122
123 *result = SkColorSetARGB(255, color_ints[0], color_ints[1], color_ints[2]);
124 return true;
125 }
126
85 } // namespace 127 } // namespace
86 128
87 void AppWindowCreateFunction::SendDelayedResponse() { 129 void AppWindowCreateFunction::SendDelayedResponse() {
88 SendResponse(true); 130 SendResponse(true);
89 } 131 }
90 132
91 bool AppWindowCreateFunction::RunImpl() { 133 bool AppWindowCreateFunction::RunImpl() {
92 // Don't create app window if the system is shutting down. 134 // Don't create app window if the system is shutting down.
93 if (extensions::ExtensionsBrowserClient::Get()->IsShuttingDown()) 135 if (extensions::ExtensionsBrowserClient::Get()->IsShuttingDown())
94 return false; 136 return false;
95 137
96 scoped_ptr<Create::Params> params(Create::Params::Create(*args_)); 138 scoped_ptr<Create::Params> params(Create::Params::Create(*args_));
97 EXTENSION_FUNCTION_VALIDATE(params.get()); 139 EXTENSION_FUNCTION_VALIDATE(params.get());
98 140
99 GURL url = GetExtension()->GetResourceURL(params->url); 141 GURL url = GetExtension()->GetResourceURL(params->url);
100 // Allow absolute URLs for component apps, otherwise prepend the extension 142 // Allow absolute URLs for component apps, otherwise prepend the extension
101 // path. 143 // path.
102 if (GetExtension()->location() == extensions::Manifest::COMPONENT) { 144 if (GetExtension()->location() == extensions::Manifest::COMPONENT) {
103 GURL absolute = GURL(params->url); 145 GURL absolute = GURL(params->url);
104 if (absolute.has_scheme()) 146 if (absolute.has_scheme())
105 url = absolute; 147 url = absolute;
106 } 148 }
107 149
108 bool inject_html_titlebar = false;
109
110 // TODO(jeremya): figure out a way to pass the opening WebContents through to 150 // TODO(jeremya): figure out a way to pass the opening WebContents through to
111 // AppWindow::Create so we can set the opener at create time rather than 151 // AppWindow::Create so we can set the opener at create time rather than
112 // with a hack in AppWindowCustomBindings::GetView(). 152 // with a hack in AppWindowCustomBindings::GetView().
113 AppWindow::CreateParams create_params; 153 AppWindow::CreateParams create_params;
114 app_window::CreateWindowOptions* options = params->options.get(); 154 app_window::CreateWindowOptions* options = params->options.get();
115 if (options) { 155 if (options) {
116 if (options->id.get()) { 156 if (options->id.get()) {
117 // TODO(mek): use URL if no id specified? 157 // TODO(mek): use URL if no id specified?
118 // Limit length of id to 256 characters. 158 // Limit length of id to 256 characters.
119 if (options->id->length() > 256) { 159 if (options->id->length() > 256) {
(...skipping 25 matching lines...) Expand all
145 185
146 if (options->focused.get() && !*options->focused.get()) 186 if (options->focused.get() && !*options->focused.get())
147 window->Show(AppWindow::SHOW_INACTIVE); 187 window->Show(AppWindow::SHOW_INACTIVE);
148 else 188 else
149 window->Show(AppWindow::SHOW_ACTIVE); 189 window->Show(AppWindow::SHOW_ACTIVE);
150 190
151 base::DictionaryValue* result = new base::DictionaryValue; 191 base::DictionaryValue* result = new base::DictionaryValue;
152 result->Set("viewId", new base::FundamentalValue(view_id)); 192 result->Set("viewId", new base::FundamentalValue(view_id));
153 window->GetSerializedState(result); 193 window->GetSerializedState(result);
154 result->SetBoolean("existingWindow", true); 194 result->SetBoolean("existingWindow", true);
195 // TODO(benwells): Remove HTML titlebar injection.
Matt Giuca 2014/02/18 06:03:18 I think that removing HTML titlebar injection shou
benwells 2014/02/18 07:47:25 Done.
155 result->SetBoolean("injectTitlebar", false); 196 result->SetBoolean("injectTitlebar", false);
156 SetResult(result); 197 SetResult(result);
157 SendResponse(true); 198 SendResponse(true);
158 return true; 199 return true;
159 } 200 }
160 } 201 }
161 } 202 }
162 203
163 // TODO(jeremya): remove these, since they do the same thing as 204 // TODO(jeremya): remove these, since they do the same thing as
164 // left/top/width/height. 205 // left/top/width/height.
(...skipping 27 matching lines...) Expand all
192 create_params.bounds.set_y(*bounds->top.get()); 233 create_params.bounds.set_y(*bounds->top.get());
193 } 234 }
194 235
195 if (GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV || 236 if (GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV ||
196 GetExtension()->location() == extensions::Manifest::COMPONENT) { 237 GetExtension()->location() == extensions::Manifest::COMPONENT) {
197 if (options->type == extensions::api::app_window::WINDOW_TYPE_PANEL) { 238 if (options->type == extensions::api::app_window::WINDOW_TYPE_PANEL) {
198 create_params.window_type = AppWindow::WINDOW_TYPE_PANEL; 239 create_params.window_type = AppWindow::WINDOW_TYPE_PANEL;
199 } 240 }
200 } 241 }
201 242
202 if (options->frame.get()) { 243 if (!GetFrameOptions(*options, &create_params))
203 if (*options->frame == kHtmlFrameOption && 244 return false;
204 (GetExtension()->HasAPIPermission(APIPermission::kExperimental) ||
205 CommandLine::ForCurrentProcess()->HasSwitch(
206 switches::kEnableExperimentalExtensionApis))) {
207 create_params.frame = AppWindow::FRAME_NONE;
208 inject_html_titlebar = true;
209 } else if (*options->frame == kNoneFrameOption) {
210 create_params.frame = AppWindow::FRAME_NONE;
211 } else {
212 create_params.frame = AppWindow::FRAME_CHROME;
213 }
214 }
215 245
216 if (options->transparent_background.get() && 246 if (options->transparent_background.get() &&
217 (GetExtension()->HasAPIPermission(APIPermission::kExperimental) || 247 (GetExtension()->HasAPIPermission(APIPermission::kExperimental) ||
218 CommandLine::ForCurrentProcess()->HasSwitch( 248 CommandLine::ForCurrentProcess()->HasSwitch(
219 switches::kEnableExperimentalExtensionApis))) { 249 switches::kEnableExperimentalExtensionApis))) {
220 create_params.transparent_background = *options->transparent_background; 250 create_params.transparent_background = *options->transparent_background;
221 } 251 }
222 252
223 gfx::Size& minimum_size = create_params.minimum_size; 253 gfx::Size& minimum_size = create_params.minimum_size;
224 if (options->min_width.get()) 254 if (options->min_width.get())
(...skipping 30 matching lines...) Expand all
255 case extensions::api::app_window::STATE_MAXIMIZED: 285 case extensions::api::app_window::STATE_MAXIMIZED:
256 create_params.state = ui::SHOW_STATE_MAXIMIZED; 286 create_params.state = ui::SHOW_STATE_MAXIMIZED;
257 break; 287 break;
258 case extensions::api::app_window::STATE_MINIMIZED: 288 case extensions::api::app_window::STATE_MINIMIZED:
259 create_params.state = ui::SHOW_STATE_MINIMIZED; 289 create_params.state = ui::SHOW_STATE_MINIMIZED;
260 break; 290 break;
261 } 291 }
262 } 292 }
263 } 293 }
264 294
295 UpdateFrameOptionsForChannel(&create_params);
296
265 create_params.creator_process_id = 297 create_params.creator_process_id =
266 render_view_host_->GetProcess()->GetID(); 298 render_view_host_->GetProcess()->GetID();
267 299
268 AppWindow* app_window = new AppWindow( 300 AppWindow* app_window = new AppWindow(
269 GetProfile(), new ChromeShellWindowDelegate(), GetExtension()); 301 GetProfile(), new ChromeShellWindowDelegate(), GetExtension());
270 app_window->Init( 302 app_window->Init(
271 url, new apps::AppWindowContentsImpl(app_window), create_params); 303 url, new apps::AppWindowContentsImpl(app_window), create_params);
272 304
273 if (chrome::IsRunningInForcedAppMode()) 305 if (chrome::IsRunningInForcedAppMode())
274 app_window->ForcedFullscreen(); 306 app_window->ForcedFullscreen();
275 307
276 content::RenderViewHost* created_view = 308 content::RenderViewHost* created_view =
277 app_window->web_contents()->GetRenderViewHost(); 309 app_window->web_contents()->GetRenderViewHost();
278 int view_id = MSG_ROUTING_NONE; 310 int view_id = MSG_ROUTING_NONE;
279 if (create_params.creator_process_id == created_view->GetProcess()->GetID()) 311 if (create_params.creator_process_id == created_view->GetProcess()->GetID())
280 view_id = created_view->GetRoutingID(); 312 view_id = created_view->GetRoutingID();
281 313
282 base::DictionaryValue* result = new base::DictionaryValue; 314 base::DictionaryValue* result = new base::DictionaryValue;
283 result->Set("viewId", new base::FundamentalValue(view_id)); 315 result->Set("viewId", new base::FundamentalValue(view_id));
284 result->Set("injectTitlebar", 316 // TODO(benwells): Remove HTML titlebar injection.
285 new base::FundamentalValue(inject_html_titlebar)); 317 result->Set("injectTitlebar", new base::FundamentalValue(false));
286 result->Set("id", new base::StringValue(app_window->window_key())); 318 result->Set("id", new base::StringValue(app_window->window_key()));
287 app_window->GetSerializedState(result); 319 app_window->GetSerializedState(result);
288 SetResult(result); 320 SetResult(result);
289 321
290 if (apps::AppWindowRegistry::Get(GetProfile()) 322 if (apps::AppWindowRegistry::Get(GetProfile())
291 ->HadDevToolsAttached(created_view)) { 323 ->HadDevToolsAttached(created_view)) {
292 new DevToolsRestorer(this, created_view); 324 new DevToolsRestorer(this, created_view);
293 return true; 325 return true;
294 } 326 }
295 327
296 SendResponse(true); 328 SendResponse(true);
297 return true; 329 return true;
298 } 330 }
299 331
332 AppWindow::Frame AppWindowCreateFunction::GetFrameFromString(
333 const std::string& frame_string) {
334 if (frame_string == kNoneFrameOption)
335 return AppWindow::FRAME_NONE;
336
337 return AppWindow::FRAME_CHROME;
338 }
339
340 bool AppWindowCreateFunction::GetFrameOptions(
341 const app_window::CreateWindowOptions& options,
342 AppWindow::CreateParams* create_params) {
343 if (options.frame.get() && options.frame_options.get()) {
344 error_ = app_window_constants::kFrameOptionsAndFrame;
345 return false;
346 }
347
348 if (options.frame.get())
349 create_params->frame = GetFrameFromString(*options.frame);
350
351 if (options.frame_options.get()) {
352 if (GetCurrentChannel() <= chrome::VersionInfo::CHANNEL_DEV) {
353 app_window::FrameOptions* frame_options = options.frame_options.get();
354
355 if (frame_options->type.get())
356 create_params->frame = GetFrameFromString(*frame_options->type);
357
358 if (frame_options->color.get()) {
359 if (create_params->frame != AppWindow::FRAME_CHROME) {
360 error_ = app_window_constants::kColorWithFrameNone;
361 return false;
362 }
363
364 if (ParseCSSColorString(*frame_options->color,
365 &create_params->frame_color)) {
366 create_params->has_frame_color = true;
367 } else {
368 error_ = app_window_constants::kInvalidColorSpecification;
Matt Giuca 2014/02/18 06:03:18 Where does this error get displayed or sent? In yo
benwells 2014/02/18 07:47:25 It gets put in chrome.runtime.lastError. For some
369 return false;
370 }
371 }
372 } else {
373 error_ = app_window_constants::kInvalidChannelForFrameOptions;
374 return false;
375 }
376 }
377
378 return true;
379 }
380
381 void AppWindowCreateFunction::UpdateFrameOptionsForChannel(
382 apps::AppWindow::CreateParams* create_params) {
383 if (create_params->frame == AppWindow::FRAME_CHROME &&
384 GetCurrentChannel() > chrome::VersionInfo::CHANNEL_DEV) {
385 // If not on trunk or dev channel, always use the standard white frame. This
Matt Giuca 2014/02/18 06:03:18 Can you change the second sentence into a TODO(ben
benwells 2014/02/18 07:47:25 Done.
386 // code will be remove once we get agreement to use the new native style
387 // frame.
388 create_params->has_frame_color = true;
389 create_params->frame_color = SK_ColorWHITE;
390 }
391 }
392
300 } // namespace extensions 393 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698