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

Side by Side Diff: headless/lib/browser/headless_devtools_manager_delegate.cc

Issue 2896763002: Implement window management devtools commands for headless. (Closed)
Patch Set: nit Created 3 years, 7 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "headless/lib/browser/headless_devtools_manager_delegate.h" 5 #include "headless/lib/browser/headless_devtools_manager_delegate.h"
6 6
7 #include <string> 7 #include <string>
8 #include <utility> 8 #include <utility>
9 9
10 #include "content/public/browser/browser_thread.h" 10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/devtools_agent_host.h" 11 #include "content/public/browser/devtools_agent_host.h"
12 #include "content/public/browser/devtools_frontend_host.h" 12 #include "content/public/browser/devtools_frontend_host.h"
13 #include "content/public/browser/render_widget_host_view.h"
13 #include "content/public/browser/web_contents.h" 14 #include "content/public/browser/web_contents.h"
14 #include "headless/grit/headless_lib_resources.h" 15 #include "headless/grit/headless_lib_resources.h"
15 #include "headless/lib/browser/headless_browser_context_impl.h" 16 #include "headless/lib/browser/headless_browser_context_impl.h"
16 #include "headless/lib/browser/headless_browser_impl.h" 17 #include "headless/lib/browser/headless_browser_impl.h"
17 #include "headless/lib/browser/headless_web_contents_impl.h" 18 #include "headless/lib/browser/headless_web_contents_impl.h"
18 #include "headless/public/devtools/domains/target.h" 19 #include "headless/public/devtools/domains/target.h"
19 #include "printing/units.h" 20 #include "printing/units.h"
20 #include "ui/base/resource/resource_bundle.h" 21 #include "ui/base/resource/resource_bundle.h"
21 22
22 namespace headless { 23 namespace headless {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 } 62 }
62 63
63 std::unique_ptr<base::DictionaryValue> CreateInvalidParamResponse( 64 std::unique_ptr<base::DictionaryValue> CreateInvalidParamResponse(
64 int command_id, 65 int command_id,
65 const std::string& param) { 66 const std::string& param) {
66 return CreateErrorResponse( 67 return CreateErrorResponse(
67 command_id, kErrorInvalidParam, 68 command_id, kErrorInvalidParam,
68 base::StringPrintf("Missing or invalid '%s' parameter", param.c_str())); 69 base::StringPrintf("Missing or invalid '%s' parameter", param.c_str()));
69 } 70 }
70 71
72 gfx::Rect BoundsOnScreen(const HeadlessBrowserWindow* window,
73 const gfx::Size& screen_size) {
74 if (window->state() == "maximized" || window->state() == "fullscreen")
75 return gfx::Rect(screen_size);
76 return window->bounds();
77 }
78
79 std::unique_ptr<base::DictionaryValue> CreateBoundsDict(
80 const HeadlessBrowserWindow* window,
81 const gfx::Size& screen_size) {
82 auto bounds_object = base::MakeUnique<base::DictionaryValue>();
83 gfx::Rect bounds = BoundsOnScreen(window, screen_size);
84 bounds_object->SetInteger("left", bounds.x());
85 bounds_object->SetInteger("top", bounds.y());
86 bounds_object->SetInteger("width", bounds.width());
87 bounds_object->SetInteger("height", bounds.height());
88 bounds_object->SetString("windowState", window->state());
89 return bounds_object;
90 }
91
71 #if BUILDFLAG(ENABLE_BASIC_PRINTING) 92 #if BUILDFLAG(ENABLE_BASIC_PRINTING)
72 void PDFCreated( 93 void PDFCreated(
73 const content::DevToolsManagerDelegate::CommandCallback& callback, 94 const content::DevToolsManagerDelegate::CommandCallback& callback,
74 int command_id, 95 int command_id,
75 printing::HeadlessPrintManager::PrintResult print_result, 96 printing::HeadlessPrintManager::PrintResult print_result,
76 const std::string& data) { 97 const std::string& data) {
77 std::unique_ptr<base::DictionaryValue> response; 98 std::unique_ptr<base::DictionaryValue> response;
78 if (print_result == printing::HeadlessPrintManager::PRINT_SUCCESS) { 99 if (print_result == printing::HeadlessPrintManager::PRINT_SUCCESS) {
79 response = CreateSuccessResponse( 100 response = CreateSuccessResponse(
80 command_id, 101 command_id,
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 command_map_["Target.createTarget"] = base::Bind( 183 command_map_["Target.createTarget"] = base::Bind(
163 &HeadlessDevToolsManagerDelegate::CreateTarget, base::Unretained(this)); 184 &HeadlessDevToolsManagerDelegate::CreateTarget, base::Unretained(this));
164 command_map_["Target.closeTarget"] = base::Bind( 185 command_map_["Target.closeTarget"] = base::Bind(
165 &HeadlessDevToolsManagerDelegate::CloseTarget, base::Unretained(this)); 186 &HeadlessDevToolsManagerDelegate::CloseTarget, base::Unretained(this));
166 command_map_["Target.createBrowserContext"] = 187 command_map_["Target.createBrowserContext"] =
167 base::Bind(&HeadlessDevToolsManagerDelegate::CreateBrowserContext, 188 base::Bind(&HeadlessDevToolsManagerDelegate::CreateBrowserContext,
168 base::Unretained(this)); 189 base::Unretained(this));
169 command_map_["Target.disposeBrowserContext"] = 190 command_map_["Target.disposeBrowserContext"] =
170 base::Bind(&HeadlessDevToolsManagerDelegate::DisposeBrowserContext, 191 base::Bind(&HeadlessDevToolsManagerDelegate::DisposeBrowserContext,
171 base::Unretained(this)); 192 base::Unretained(this));
193 command_map_["Browser.getWindowForTarget"] =
194 base::Bind(&HeadlessDevToolsManagerDelegate::GetWindowForTarget,
195 base::Unretained(this));
196 command_map_["Browser.getWindowBounds"] =
197 base::Bind(&HeadlessDevToolsManagerDelegate::GetWindowBounds,
198 base::Unretained(this));
199 command_map_["Browser.setWindowBounds"] =
200 base::Bind(&HeadlessDevToolsManagerDelegate::SetWindowBounds,
201 base::Unretained(this));
172 202
173 async_command_map_["Page.printToPDF"] = base::Bind( 203 async_command_map_["Page.printToPDF"] = base::Bind(
174 &HeadlessDevToolsManagerDelegate::PrintToPDF, base::Unretained(this)); 204 &HeadlessDevToolsManagerDelegate::PrintToPDF, base::Unretained(this));
175 } 205 }
176 206
177 HeadlessDevToolsManagerDelegate::~HeadlessDevToolsManagerDelegate() {} 207 HeadlessDevToolsManagerDelegate::~HeadlessDevToolsManagerDelegate() {}
178 208
179 base::DictionaryValue* HeadlessDevToolsManagerDelegate::HandleCommand( 209 base::DictionaryValue* HeadlessDevToolsManagerDelegate::HandleCommand(
180 content::DevToolsAgentHost* agent_host, 210 content::DevToolsAgentHost* agent_host,
181 base::DictionaryValue* command) { 211 base::DictionaryValue* command) {
182 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 212 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
183 213
184 if (!browser_) 214 if (!browser_)
185 return nullptr; 215 return nullptr;
186 216
187 int id; 217 int id;
188 std::string method; 218 std::string method;
189 if (!command->GetInteger("id", &id) || !command->GetString("method", &method)) 219 if (!command->GetInteger("id", &id) || !command->GetString("method", &method))
190 return nullptr; 220 return nullptr;
191 221
192 auto find_it = command_map_.find(method); 222 auto find_it = command_map_.find(method);
193 if (find_it == command_map_.end()) 223 if (find_it == command_map_.end())
194 return nullptr; 224 return nullptr;
195 225
226 // Only handle Browser domain commands from Browser DevToolsAgentHost.
Eric Seckler 2017/05/22 19:13:40 nit: Handle Browser domain commands only from ...
jzfeng 2017/05/24 05:05:39 Done.
227 if (method.find("Browser.") == 0 &&
228 agent_host->GetType() != content::DevToolsAgentHost::kTypeBrowser)
229 return nullptr;
230
196 const base::DictionaryValue* params = nullptr; 231 const base::DictionaryValue* params = nullptr;
197 command->GetDictionary("params", &params); 232 command->GetDictionary("params", &params);
198 auto cmd_result = find_it->second.Run(id, params); 233 auto cmd_result = find_it->second.Run(id, params);
199 return cmd_result.release(); 234 return cmd_result.release();
200 } 235 }
201 236
202 bool HeadlessDevToolsManagerDelegate::HandleAsyncCommand( 237 bool HeadlessDevToolsManagerDelegate::HandleAsyncCommand(
203 content::DevToolsAgentHost* agent_host, 238 content::DevToolsAgentHost* agent_host,
204 base::DictionaryValue* command, 239 base::DictionaryValue* command,
205 const CommandCallback& callback) { 240 const CommandCallback& callback) {
(...skipping 13 matching lines...) Expand all
219 254
220 const base::DictionaryValue* params = nullptr; 255 const base::DictionaryValue* params = nullptr;
221 command->GetDictionary("params", &params); 256 command->GetDictionary("params", &params);
222 find_it->second.Run(agent_host, id, params, callback); 257 find_it->second.Run(agent_host, id, params, callback);
223 return true; 258 return true;
224 } 259 }
225 260
226 scoped_refptr<content::DevToolsAgentHost> 261 scoped_refptr<content::DevToolsAgentHost>
227 HeadlessDevToolsManagerDelegate::CreateNewTarget(const GURL& url) { 262 HeadlessDevToolsManagerDelegate::CreateNewTarget(const GURL& url) {
228 HeadlessBrowserContext* context = browser_->GetDefaultBrowserContext(); 263 HeadlessBrowserContext* context = browser_->GetDefaultBrowserContext();
229 HeadlessWebContentsImpl* web_contents_impl = HeadlessWebContentsImpl::From( 264 gfx::Rect bounds =
230 context->CreateWebContentsBuilder() 265 BoundsOnScreen(browser_->window(), browser_->options()->screen_size);
231 .SetInitialURL(url) 266 HeadlessWebContentsImpl* web_contents_impl =
232 .SetWindowSize(browser_->options()->window_size) 267 HeadlessWebContentsImpl::From(context->CreateWebContentsBuilder()
233 .Build()); 268 .SetInitialURL(url)
269 .SetWindowSize(bounds.size())
270 .Build());
234 return content::DevToolsAgentHost::GetOrCreateFor( 271 return content::DevToolsAgentHost::GetOrCreateFor(
235 web_contents_impl->web_contents()); 272 web_contents_impl->web_contents());
236 } 273 }
237 274
238 std::string HeadlessDevToolsManagerDelegate::GetDiscoveryPageHTML() { 275 std::string HeadlessDevToolsManagerDelegate::GetDiscoveryPageHTML() {
239 return ResourceBundle::GetSharedInstance() 276 return ResourceBundle::GetSharedInstance()
240 .GetRawDataResource(IDR_HEADLESS_LIB_DEVTOOLS_DISCOVERY_PAGE) 277 .GetRawDataResource(IDR_HEADLESS_LIB_DEVTOOLS_DISCOVERY_PAGE)
241 .as_string(); 278 .as_string();
242 } 279 }
243 280
(...skipping 28 matching lines...) Expand all
272 "Printing is not enabled")); 309 "Printing is not enabled"));
273 #endif 310 #endif
274 } 311 }
275 312
276 std::unique_ptr<base::DictionaryValue> 313 std::unique_ptr<base::DictionaryValue>
277 HeadlessDevToolsManagerDelegate::CreateTarget( 314 HeadlessDevToolsManagerDelegate::CreateTarget(
278 int command_id, 315 int command_id,
279 const base::DictionaryValue* params) { 316 const base::DictionaryValue* params) {
280 std::string url; 317 std::string url;
281 std::string browser_context_id; 318 std::string browser_context_id;
282 int width = browser_->options()->window_size.width(); 319 gfx::Rect bounds =
283 int height = browser_->options()->window_size.height(); 320 BoundsOnScreen(browser_->window(), browser_->options()->screen_size);
321 int width = bounds.width();
322 int height = bounds.height();
284 if (!params || !params->GetString("url", &url)) 323 if (!params || !params->GetString("url", &url))
285 return CreateInvalidParamResponse(command_id, "url"); 324 return CreateInvalidParamResponse(command_id, "url");
286 params->GetString("browserContextId", &browser_context_id); 325 params->GetString("browserContextId", &browser_context_id);
287 params->GetInteger("width", &width); 326 params->GetInteger("width", &width);
288 params->GetInteger("height", &height); 327 params->GetInteger("height", &height);
289 328
290 HeadlessBrowserContext* context = 329 HeadlessBrowserContext* context =
291 browser_->GetBrowserContextForId(browser_context_id); 330 browser_->GetBrowserContextForId(browser_context_id);
292 if (!browser_context_id.empty()) { 331 if (!browser_context_id.empty()) {
293 context = browser_->GetBrowserContextForId(browser_context_id); 332 context = browser_->GetBrowserContextForId(browser_context_id);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 } 410 }
372 411
373 std::unique_ptr<base::Value> result( 412 std::unique_ptr<base::Value> result(
374 target::DisposeBrowserContextResult::Builder() 413 target::DisposeBrowserContextResult::Builder()
375 .SetSuccess(success) 414 .SetSuccess(success)
376 .Build() 415 .Build()
377 ->Serialize()); 416 ->Serialize());
378 return CreateSuccessResponse(command_id, std::move(result)); 417 return CreateSuccessResponse(command_id, std::move(result));
379 } 418 }
380 419
420 std::unique_ptr<base::DictionaryValue>
421 HeadlessDevToolsManagerDelegate::GetWindowForTarget(
422 int command_id,
423 const base::DictionaryValue* params) {
424 std::string target_id;
425 if (!params->GetString("targetId", &target_id))
426 return CreateInvalidParamResponse(command_id, "targetId");
427
428 bool found_web_contents = false;
429 for (HeadlessBrowserContext* context : browser_->GetAllBrowserContexts()) {
430 if (context->GetWebContentsForDevToolsAgentHostId(target_id)) {
431 found_web_contents = true;
432 break;
433 }
434 }
435 if (!found_web_contents) {
436 return CreateErrorResponse(command_id, kErrorServerError,
437 "No web contents for the given target id");
438 }
439
440 auto result = base::MakeUnique<base::DictionaryValue>();
441 result->SetInteger("windowId", 0);
Sami 2017/05/22 16:30:57 Let's make this a named constant -- and also non-z
442 result->Set("bounds", CreateBoundsDict(browser_->window(),
443 browser_->options()->screen_size));
444 return CreateSuccessResponse(command_id, std::move(result));
445 }
446
447 std::unique_ptr<base::DictionaryValue>
448 HeadlessDevToolsManagerDelegate::GetWindowBounds(
449 int command_id,
450 const base::DictionaryValue* params) {
451 int window_id;
452 if (!params->GetInteger("windowId", &window_id))
453 return CreateInvalidParamResponse(command_id, "windowId");
454 if (window_id != 0) {
455 return CreateErrorResponse(command_id, kErrorServerError,
456 "Browser window not found");
457 }
458
459 auto result = base::MakeUnique<base::DictionaryValue>();
460 result->Set("bounds", CreateBoundsDict(browser_->window(),
461 browser_->options()->screen_size));
462 return CreateSuccessResponse(command_id, std::move(result));
463 }
464
465 std::unique_ptr<base::DictionaryValue>
466 HeadlessDevToolsManagerDelegate::SetWindowBounds(
467 int command_id,
468 const base::DictionaryValue* params) {
469 int window_id;
470 if (!params->GetInteger("windowId", &window_id))
471 return CreateInvalidParamResponse(command_id, "windowId");
472 if (window_id != 0) {
473 return CreateErrorResponse(command_id, kErrorServerError,
474 "Browser window not found");
475 }
476
477 const base::Value* value = nullptr;
478 const base::DictionaryValue* bounds_dict = nullptr;
479 if (!params->Get("bounds", &value) || !value->GetAsDictionary(&bounds_dict))
480 return CreateInvalidParamResponse(command_id, "bounds");
481
482 std::string window_state;
483 if (!bounds_dict->GetString("windowState", &window_state))
Sami 2017/05/22 16:30:57 nit: Add {}s please
jzfeng 2017/05/24 05:05:39 Done.
484 window_state = "normal";
485 else if (window_state != "normal" && window_state != "minimized" &&
486 window_state != "maximized" && window_state != "fullscreen")
487 return CreateInvalidParamResponse(command_id, "windowState");
488
489 // Compute updated bounds when window state is normal.
490 bool set_bounds = false;
491 gfx::Rect bounds = browser_->window()->bounds();
492 int left, top, width, height;
493 if (bounds_dict->GetInteger("left", &left)) {
494 bounds.set_x(left);
495 set_bounds = true;
496 }
497 if (bounds_dict->GetInteger("top", &top)) {
498 bounds.set_y(top);
499 set_bounds = true;
500 }
501 if (bounds_dict->GetInteger("width", &width)) {
502 if (width < 0)
503 return CreateInvalidParamResponse(command_id, "width");
504 bounds.set_width(width);
505 set_bounds = true;
506 }
507 if (bounds_dict->GetInteger("height", &height)) {
508 if (height < 0)
509 return CreateInvalidParamResponse(command_id, "height");
510 bounds.set_height(height);
511 set_bounds = true;
512 }
513
514 if (set_bounds && window_state != "normal") {
515 return CreateErrorResponse(
516 command_id, kErrorServerError,
517 "The 'minimized', 'maximized' and 'fullscreen' states cannot be "
518 "combined with 'left', 'top', 'width' or 'height'");
519 }
520
521 if (set_bounds && browser_->window()->state() != "normal") {
522 return CreateErrorResponse(
523 command_id, kErrorServerError,
524 "To resize minimized/maximized/fullscreen window, restore it to normal "
525 "state first.");
526 }
527
528 browser_->window()->set_state(window_state);
529
530 if (window_state == "minimized")
531 return CreateSuccessResponse(command_id, nullptr);
532
533 if (window_state == "maximized" || window_state == "fullscreen")
534 bounds = gfx::Rect(browser_->options()->screen_size);
535 else
536 browser_->window()->set_bounds(bounds);
537
538 for (HeadlessBrowserContext* context : browser_->GetAllBrowserContexts()) {
539 for (HeadlessWebContents* web_contents : context->GetAllWebContents()) {
Eric Seckler 2017/05/22 19:13:40 We should allow controlling the window size of ind
540 auto* contents = HeadlessWebContentsImpl::From(web_contents);
541 if (contents) {
542 contents->web_contents()->GetRenderWidgetHostView()->SetSize(
543 bounds.size());
544 }
545 }
546 }
547
548 return CreateSuccessResponse(command_id, nullptr);
549 }
550
381 } // namespace headless 551 } // namespace headless
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698