Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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", ¶ms); | 232 command->GetDictionary("params", ¶ms); |
| 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 Loading... | |
| 219 | 254 |
| 220 const base::DictionaryValue* params = nullptr; | 255 const base::DictionaryValue* params = nullptr; |
| 221 command->GetDictionary("params", ¶ms); | 256 command->GetDictionary("params", ¶ms); |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |