| 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 std::unique_ptr<base::DictionaryValue> CreateBoundsDict( |
| 73 const HeadlessWebContentsImpl* web_contents) { |
| 74 auto bounds_object = base::MakeUnique<base::DictionaryValue>(); |
| 75 gfx::Rect bounds = |
| 76 web_contents->web_contents()->GetRenderWidgetHostView()->GetViewBounds(); |
| 77 bounds_object->SetInteger("left", bounds.x()); |
| 78 bounds_object->SetInteger("top", bounds.y()); |
| 79 bounds_object->SetInteger("width", bounds.width()); |
| 80 bounds_object->SetInteger("height", bounds.height()); |
| 81 bounds_object->SetString("windowState", web_contents->window_state()); |
| 82 return bounds_object; |
| 83 } |
| 84 |
| 71 #if BUILDFLAG(ENABLE_BASIC_PRINTING) | 85 #if BUILDFLAG(ENABLE_BASIC_PRINTING) |
| 72 void PDFCreated( | 86 void PDFCreated( |
| 73 const content::DevToolsManagerDelegate::CommandCallback& callback, | 87 const content::DevToolsManagerDelegate::CommandCallback& callback, |
| 74 int command_id, | 88 int command_id, |
| 75 printing::HeadlessPrintManager::PrintResult print_result, | 89 printing::HeadlessPrintManager::PrintResult print_result, |
| 76 const std::string& data) { | 90 const std::string& data) { |
| 77 std::unique_ptr<base::DictionaryValue> response; | 91 std::unique_ptr<base::DictionaryValue> response; |
| 78 if (print_result == printing::HeadlessPrintManager::PRINT_SUCCESS) { | 92 if (print_result == printing::HeadlessPrintManager::PRINT_SUCCESS) { |
| 79 response = CreateSuccessResponse( | 93 response = CreateSuccessResponse( |
| 80 command_id, | 94 command_id, |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 command_map_["Target.createTarget"] = base::Bind( | 176 command_map_["Target.createTarget"] = base::Bind( |
| 163 &HeadlessDevToolsManagerDelegate::CreateTarget, base::Unretained(this)); | 177 &HeadlessDevToolsManagerDelegate::CreateTarget, base::Unretained(this)); |
| 164 command_map_["Target.closeTarget"] = base::Bind( | 178 command_map_["Target.closeTarget"] = base::Bind( |
| 165 &HeadlessDevToolsManagerDelegate::CloseTarget, base::Unretained(this)); | 179 &HeadlessDevToolsManagerDelegate::CloseTarget, base::Unretained(this)); |
| 166 command_map_["Target.createBrowserContext"] = | 180 command_map_["Target.createBrowserContext"] = |
| 167 base::Bind(&HeadlessDevToolsManagerDelegate::CreateBrowserContext, | 181 base::Bind(&HeadlessDevToolsManagerDelegate::CreateBrowserContext, |
| 168 base::Unretained(this)); | 182 base::Unretained(this)); |
| 169 command_map_["Target.disposeBrowserContext"] = | 183 command_map_["Target.disposeBrowserContext"] = |
| 170 base::Bind(&HeadlessDevToolsManagerDelegate::DisposeBrowserContext, | 184 base::Bind(&HeadlessDevToolsManagerDelegate::DisposeBrowserContext, |
| 171 base::Unretained(this)); | 185 base::Unretained(this)); |
| 186 command_map_["Browser.getWindowForTarget"] = |
| 187 base::Bind(&HeadlessDevToolsManagerDelegate::GetWindowForTarget, |
| 188 base::Unretained(this)); |
| 189 command_map_["Browser.getWindowBounds"] = |
| 190 base::Bind(&HeadlessDevToolsManagerDelegate::GetWindowBounds, |
| 191 base::Unretained(this)); |
| 192 command_map_["Browser.setWindowBounds"] = |
| 193 base::Bind(&HeadlessDevToolsManagerDelegate::SetWindowBounds, |
| 194 base::Unretained(this)); |
| 172 | 195 |
| 173 async_command_map_["Page.printToPDF"] = base::Bind( | 196 async_command_map_["Page.printToPDF"] = base::Bind( |
| 174 &HeadlessDevToolsManagerDelegate::PrintToPDF, base::Unretained(this)); | 197 &HeadlessDevToolsManagerDelegate::PrintToPDF, base::Unretained(this)); |
| 175 } | 198 } |
| 176 | 199 |
| 177 HeadlessDevToolsManagerDelegate::~HeadlessDevToolsManagerDelegate() {} | 200 HeadlessDevToolsManagerDelegate::~HeadlessDevToolsManagerDelegate() {} |
| 178 | 201 |
| 179 base::DictionaryValue* HeadlessDevToolsManagerDelegate::HandleCommand( | 202 base::DictionaryValue* HeadlessDevToolsManagerDelegate::HandleCommand( |
| 180 content::DevToolsAgentHost* agent_host, | 203 content::DevToolsAgentHost* agent_host, |
| 181 base::DictionaryValue* command) { | 204 base::DictionaryValue* command) { |
| 182 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 205 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 183 | 206 |
| 184 if (!browser_) | 207 if (!browser_) |
| 185 return nullptr; | 208 return nullptr; |
| 186 | 209 |
| 187 int id; | 210 int id; |
| 188 std::string method; | 211 std::string method; |
| 189 if (!command->GetInteger("id", &id) || !command->GetString("method", &method)) | 212 if (!command->GetInteger("id", &id) || !command->GetString("method", &method)) |
| 190 return nullptr; | 213 return nullptr; |
| 191 | 214 |
| 192 auto find_it = command_map_.find(method); | 215 auto find_it = command_map_.find(method); |
| 193 if (find_it == command_map_.end()) | 216 if (find_it == command_map_.end()) |
| 194 return nullptr; | 217 return nullptr; |
| 195 | 218 |
| 219 // Handle Browser domain commands only from Browser DevToolsAgentHost. |
| 220 if (method.find("Browser.") == 0 && |
| 221 agent_host->GetType() != content::DevToolsAgentHost::kTypeBrowser) |
| 222 return nullptr; |
| 223 |
| 196 const base::DictionaryValue* params = nullptr; | 224 const base::DictionaryValue* params = nullptr; |
| 197 command->GetDictionary("params", ¶ms); | 225 command->GetDictionary("params", ¶ms); |
| 198 auto cmd_result = find_it->second.Run(id, params); | 226 auto cmd_result = find_it->second.Run(id, params); |
| 199 return cmd_result.release(); | 227 return cmd_result.release(); |
| 200 } | 228 } |
| 201 | 229 |
| 202 bool HeadlessDevToolsManagerDelegate::HandleAsyncCommand( | 230 bool HeadlessDevToolsManagerDelegate::HandleAsyncCommand( |
| 203 content::DevToolsAgentHost* agent_host, | 231 content::DevToolsAgentHost* agent_host, |
| 204 base::DictionaryValue* command, | 232 base::DictionaryValue* command, |
| 205 const CommandCallback& callback) { | 233 const CommandCallback& callback) { |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 } | 399 } |
| 372 | 400 |
| 373 std::unique_ptr<base::Value> result( | 401 std::unique_ptr<base::Value> result( |
| 374 target::DisposeBrowserContextResult::Builder() | 402 target::DisposeBrowserContextResult::Builder() |
| 375 .SetSuccess(success) | 403 .SetSuccess(success) |
| 376 .Build() | 404 .Build() |
| 377 ->Serialize()); | 405 ->Serialize()); |
| 378 return CreateSuccessResponse(command_id, std::move(result)); | 406 return CreateSuccessResponse(command_id, std::move(result)); |
| 379 } | 407 } |
| 380 | 408 |
| 409 std::unique_ptr<base::DictionaryValue> |
| 410 HeadlessDevToolsManagerDelegate::GetWindowForTarget( |
| 411 int command_id, |
| 412 const base::DictionaryValue* params) { |
| 413 std::string target_id; |
| 414 if (!params->GetString("targetId", &target_id)) |
| 415 return CreateInvalidParamResponse(command_id, "targetId"); |
| 416 |
| 417 HeadlessWebContentsImpl* web_contents = HeadlessWebContentsImpl::From( |
| 418 browser_->GetWebContentsForDevToolsAgentHostId(target_id)); |
| 419 if (!web_contents) { |
| 420 return CreateErrorResponse(command_id, kErrorServerError, |
| 421 "No web contents for the given target id"); |
| 422 } |
| 423 |
| 424 auto result = base::MakeUnique<base::DictionaryValue>(); |
| 425 result->SetInteger("windowId", web_contents->window_id()); |
| 426 result->Set("bounds", CreateBoundsDict(web_contents)); |
| 427 return CreateSuccessResponse(command_id, std::move(result)); |
| 428 } |
| 429 |
| 430 std::unique_ptr<base::DictionaryValue> |
| 431 HeadlessDevToolsManagerDelegate::GetWindowBounds( |
| 432 int command_id, |
| 433 const base::DictionaryValue* params) { |
| 434 int window_id; |
| 435 if (!params->GetInteger("windowId", &window_id)) |
| 436 return CreateInvalidParamResponse(command_id, "windowId"); |
| 437 HeadlessWebContentsImpl* web_contents = |
| 438 browser_->GetWebContentsForWindowId(window_id); |
| 439 if (!web_contents) { |
| 440 return CreateErrorResponse(command_id, kErrorServerError, |
| 441 "Browser window not found"); |
| 442 } |
| 443 |
| 444 auto result = base::MakeUnique<base::DictionaryValue>(); |
| 445 result->Set("bounds", CreateBoundsDict(web_contents)); |
| 446 return CreateSuccessResponse(command_id, std::move(result)); |
| 447 } |
| 448 |
| 449 std::unique_ptr<base::DictionaryValue> |
| 450 HeadlessDevToolsManagerDelegate::SetWindowBounds( |
| 451 int command_id, |
| 452 const base::DictionaryValue* params) { |
| 453 int window_id; |
| 454 if (!params->GetInteger("windowId", &window_id)) |
| 455 return CreateInvalidParamResponse(command_id, "windowId"); |
| 456 HeadlessWebContentsImpl* web_contents = |
| 457 browser_->GetWebContentsForWindowId(window_id); |
| 458 if (!web_contents) { |
| 459 return CreateErrorResponse(command_id, kErrorServerError, |
| 460 "Browser window not found"); |
| 461 } |
| 462 |
| 463 const base::Value* value = nullptr; |
| 464 const base::DictionaryValue* bounds_dict = nullptr; |
| 465 if (!params->Get("bounds", &value) || !value->GetAsDictionary(&bounds_dict)) |
| 466 return CreateInvalidParamResponse(command_id, "bounds"); |
| 467 |
| 468 std::string window_state; |
| 469 if (!bounds_dict->GetString("windowState", &window_state)) { |
| 470 window_state = "normal"; |
| 471 } else if (window_state != "normal" && window_state != "minimized" && |
| 472 window_state != "maximized" && window_state != "fullscreen") { |
| 473 return CreateInvalidParamResponse(command_id, "windowState"); |
| 474 } |
| 475 |
| 476 // Compute updated bounds when window state is normal. |
| 477 bool set_bounds = false; |
| 478 gfx::Rect bounds = |
| 479 web_contents->web_contents()->GetRenderWidgetHostView()->GetViewBounds(); |
| 480 int left, top, width, height; |
| 481 if (bounds_dict->GetInteger("left", &left)) { |
| 482 bounds.set_x(left); |
| 483 set_bounds = true; |
| 484 } |
| 485 if (bounds_dict->GetInteger("top", &top)) { |
| 486 bounds.set_y(top); |
| 487 set_bounds = true; |
| 488 } |
| 489 if (bounds_dict->GetInteger("width", &width)) { |
| 490 if (width < 0) |
| 491 return CreateInvalidParamResponse(command_id, "width"); |
| 492 bounds.set_width(width); |
| 493 set_bounds = true; |
| 494 } |
| 495 if (bounds_dict->GetInteger("height", &height)) { |
| 496 if (height < 0) |
| 497 return CreateInvalidParamResponse(command_id, "height"); |
| 498 bounds.set_height(height); |
| 499 set_bounds = true; |
| 500 } |
| 501 |
| 502 if (set_bounds && window_state != "normal") { |
| 503 return CreateErrorResponse( |
| 504 command_id, kErrorServerError, |
| 505 "The 'minimized', 'maximized' and 'fullscreen' states cannot be " |
| 506 "combined with 'left', 'top', 'width' or 'height'"); |
| 507 } |
| 508 |
| 509 if (set_bounds && web_contents->window_state() != "normal") { |
| 510 return CreateErrorResponse( |
| 511 command_id, kErrorServerError, |
| 512 "To resize minimized/maximized/fullscreen window, restore it to normal " |
| 513 "state first."); |
| 514 } |
| 515 |
| 516 web_contents->set_window_state(window_state); |
| 517 web_contents->web_contents()->GetRenderWidgetHostView()->SetBounds(bounds); |
| 518 return CreateSuccessResponse(command_id, nullptr); |
| 519 } |
| 520 |
| 381 } // namespace headless | 521 } // namespace headless |
| OLD | NEW |