| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "content/browser/devtools/protocol/page_handler.h" | 5 #include "content/browser/devtools/protocol/page_handler.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/base64.h" | 9 #include "base/base64.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 } // namespace | 89 } // namespace |
| 90 | 90 |
| 91 typedef DevToolsProtocolClient::Response Response; | 91 typedef DevToolsProtocolClient::Response Response; |
| 92 | 92 |
| 93 PageHandler::PageHandler() | 93 PageHandler::PageHandler() |
| 94 : enabled_(false), | 94 : enabled_(false), |
| 95 screencast_enabled_(false), | 95 screencast_enabled_(false), |
| 96 screencast_quality_(kDefaultScreenshotQuality), | 96 screencast_quality_(kDefaultScreenshotQuality), |
| 97 screencast_max_width_(-1), | 97 screencast_max_width_(-1), |
| 98 screencast_max_height_(-1), | 98 screencast_max_height_(-1), |
| 99 capture_every_nth_frame_(1), |
| 99 capture_retry_count_(0), | 100 capture_retry_count_(0), |
| 100 has_compositor_frame_metadata_(false), | 101 has_compositor_frame_metadata_(false), |
| 101 screencast_frame_sent_(0), | 102 session_id_(0), |
| 102 screencast_frame_acked_(0), | 103 frame_counter_(0), |
| 103 processing_screencast_frame_(false), | 104 frames_in_flight_(0), |
| 104 color_picker_(new ColorPicker(base::Bind( | 105 color_picker_(new ColorPicker(base::Bind( |
| 105 &PageHandler::OnColorPicked, base::Unretained(this)))), | 106 &PageHandler::OnColorPicked, base::Unretained(this)))), |
| 106 host_(nullptr), | 107 host_(nullptr), |
| 107 weak_factory_(this) { | 108 weak_factory_(this) { |
| 108 } | 109 } |
| 109 | 110 |
| 110 PageHandler::~PageHandler() { | 111 PageHandler::~PageHandler() { |
| 111 } | 112 } |
| 112 | 113 |
| 113 void PageHandler::SetRenderFrameHost(RenderFrameHostImpl* host) { | 114 void PageHandler::SetRenderFrameHost(RenderFrameHostImpl* host) { |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 281 *result = true; | 282 *result = true; |
| 282 #else | 283 #else |
| 283 *result = false; | 284 *result = false; |
| 284 #endif // defined(OS_ANDROID) | 285 #endif // defined(OS_ANDROID) |
| 285 return Response::OK(); | 286 return Response::OK(); |
| 286 } | 287 } |
| 287 | 288 |
| 288 Response PageHandler::StartScreencast(const std::string* format, | 289 Response PageHandler::StartScreencast(const std::string* format, |
| 289 const int* quality, | 290 const int* quality, |
| 290 const int* max_width, | 291 const int* max_width, |
| 291 const int* max_height) { | 292 const int* max_height, |
| 293 const int* every_nth_frame) { |
| 292 RenderWidgetHostImpl* widget_host = | 294 RenderWidgetHostImpl* widget_host = |
| 293 host_ ? host_->GetRenderWidgetHost() : nullptr; | 295 host_ ? host_->GetRenderWidgetHost() : nullptr; |
| 294 if (!widget_host) | 296 if (!widget_host) |
| 295 return Response::InternalError("Could not connect to view"); | 297 return Response::InternalError("Could not connect to view"); |
| 296 | 298 |
| 297 screencast_enabled_ = true; | 299 screencast_enabled_ = true; |
| 298 screencast_format_ = format ? *format : kPng; | 300 screencast_format_ = format ? *format : kPng; |
| 299 screencast_quality_ = quality ? *quality : kDefaultScreenshotQuality; | 301 screencast_quality_ = quality ? *quality : kDefaultScreenshotQuality; |
| 300 if (screencast_quality_ < 0 || screencast_quality_ > 100) | 302 if (screencast_quality_ < 0 || screencast_quality_ > 100) |
| 301 screencast_quality_ = kDefaultScreenshotQuality; | 303 screencast_quality_ = kDefaultScreenshotQuality; |
| 302 screencast_max_width_ = max_width ? *max_width : -1; | 304 screencast_max_width_ = max_width ? *max_width : -1; |
| 303 screencast_max_height_ = max_height ? *max_height : -1; | 305 screencast_max_height_ = max_height ? *max_height : -1; |
| 306 ++session_id_; |
| 307 frame_counter_ = 0; |
| 308 frames_in_flight_ = 0; |
| 309 capture_every_nth_frame_ = every_nth_frame ? *every_nth_frame : 1; |
| 304 | 310 |
| 305 bool visible = !widget_host->is_hidden(); | 311 bool visible = !widget_host->is_hidden(); |
| 306 NotifyScreencastVisibility(visible); | 312 NotifyScreencastVisibility(visible); |
| 307 if (visible) { | 313 if (visible) { |
| 308 if (has_compositor_frame_metadata_) { | 314 if (has_compositor_frame_metadata_) { |
| 309 InnerSwapCompositorFrame(); | 315 InnerSwapCompositorFrame(); |
| 310 } else { | 316 } else { |
| 311 widget_host->Send( | 317 widget_host->Send( |
| 312 new ViewMsg_ForceRedraw(widget_host->GetRoutingID(), 0)); | 318 new ViewMsg_ForceRedraw(widget_host->GetRoutingID(), 0)); |
| 313 } | 319 } |
| 314 } | 320 } |
| 315 return Response::FallThrough(); | 321 return Response::FallThrough(); |
| 316 } | 322 } |
| 317 | 323 |
| 318 Response PageHandler::StopScreencast() { | 324 Response PageHandler::StopScreencast() { |
| 319 screencast_enabled_ = false; | 325 screencast_enabled_ = false; |
| 320 return Response::FallThrough(); | 326 return Response::FallThrough(); |
| 321 } | 327 } |
| 322 | 328 |
| 323 Response PageHandler::ScreencastFrameAck(int frame_number) { | 329 Response PageHandler::ScreencastFrameAck(int session_id) { |
| 324 screencast_frame_acked_ = frame_number; | 330 if (session_id == session_id_) |
| 331 --frames_in_flight_; |
| 325 return Response::OK(); | 332 return Response::OK(); |
| 326 } | 333 } |
| 327 | 334 |
| 328 Response PageHandler::HandleJavaScriptDialog(bool accept, | 335 Response PageHandler::HandleJavaScriptDialog(bool accept, |
| 329 const std::string* prompt_text) { | 336 const std::string* prompt_text) { |
| 330 base::string16 prompt_override; | 337 base::string16 prompt_override; |
| 331 if (prompt_text) | 338 if (prompt_text) |
| 332 prompt_override = base::UTF8ToUTF16(*prompt_text); | 339 prompt_override = base::UTF8ToUTF16(*prompt_text); |
| 333 | 340 |
| 334 WebContentsImpl* web_contents = GetWebContents(); | 341 WebContentsImpl* web_contents = GetWebContents(); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 365 } | 372 } |
| 366 | 373 |
| 367 void PageHandler::NotifyScreencastVisibility(bool visible) { | 374 void PageHandler::NotifyScreencastVisibility(bool visible) { |
| 368 if (visible) | 375 if (visible) |
| 369 capture_retry_count_ = kCaptureRetryLimit; | 376 capture_retry_count_ = kCaptureRetryLimit; |
| 370 client_->ScreencastVisibilityChanged( | 377 client_->ScreencastVisibilityChanged( |
| 371 ScreencastVisibilityChangedParams::Create()->set_visible(visible)); | 378 ScreencastVisibilityChangedParams::Create()->set_visible(visible)); |
| 372 } | 379 } |
| 373 | 380 |
| 374 void PageHandler::InnerSwapCompositorFrame() { | 381 void PageHandler::InnerSwapCompositorFrame() { |
| 375 if (screencast_frame_sent_ - screencast_frame_acked_ > | |
| 376 kMaxScreencastFramesInFlight || processing_screencast_frame_) { | |
| 377 return; | |
| 378 } | |
| 379 | |
| 380 if (!host_ || !host_->GetView()) | 382 if (!host_ || !host_->GetView()) |
| 381 return; | 383 return; |
| 382 | 384 |
| 385 if (frames_in_flight_ > kMaxScreencastFramesInFlight) |
| 386 return; |
| 387 |
| 388 if (++frame_counter_ % capture_every_nth_frame_) |
| 389 return; |
| 390 |
| 383 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( | 391 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( |
| 384 host_->GetView()); | 392 host_->GetView()); |
| 385 // TODO(vkuzkokov): do not use previous frame metadata. | 393 // TODO(vkuzkokov): do not use previous frame metadata. |
| 386 cc::CompositorFrameMetadata& metadata = last_compositor_frame_metadata_; | 394 cc::CompositorFrameMetadata& metadata = last_compositor_frame_metadata_; |
| 387 | 395 |
| 388 gfx::SizeF viewport_size_dip = gfx::ScaleSize( | 396 gfx::SizeF viewport_size_dip = gfx::ScaleSize( |
| 389 metadata.scrollable_viewport_size, metadata.page_scale_factor); | 397 metadata.scrollable_viewport_size, metadata.page_scale_factor); |
| 390 gfx::SizeF screen_size_dip = | 398 gfx::SizeF screen_size_dip = |
| 391 gfx::ScaleSize(gfx::SizeF(view->GetPhysicalBackingSize()), | 399 gfx::ScaleSize(gfx::SizeF(view->GetPhysicalBackingSize()), |
| 392 1 / metadata.device_scale_factor); | 400 1 / metadata.device_scale_factor); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 405 scale = std::min(scale, max_height_dip / screen_size_dip.height()); | 413 scale = std::min(scale, max_height_dip / screen_size_dip.height()); |
| 406 } | 414 } |
| 407 | 415 |
| 408 if (scale <= 0) | 416 if (scale <= 0) |
| 409 scale = 0.1; | 417 scale = 0.1; |
| 410 | 418 |
| 411 gfx::Size snapshot_size_dip(gfx::ToRoundedSize( | 419 gfx::Size snapshot_size_dip(gfx::ToRoundedSize( |
| 412 gfx::ScaleSize(viewport_size_dip, scale))); | 420 gfx::ScaleSize(viewport_size_dip, scale))); |
| 413 | 421 |
| 414 if (snapshot_size_dip.width() > 0 && snapshot_size_dip.height() > 0) { | 422 if (snapshot_size_dip.width() > 0 && snapshot_size_dip.height() > 0) { |
| 415 processing_screencast_frame_ = true; | |
| 416 gfx::Rect viewport_bounds_dip(gfx::ToRoundedSize(viewport_size_dip)); | 423 gfx::Rect viewport_bounds_dip(gfx::ToRoundedSize(viewport_size_dip)); |
| 417 view->CopyFromCompositingSurface( | 424 view->CopyFromCompositingSurface( |
| 418 viewport_bounds_dip, | 425 viewport_bounds_dip, |
| 419 snapshot_size_dip, | 426 snapshot_size_dip, |
| 420 base::Bind(&PageHandler::ScreencastFrameCaptured, | 427 base::Bind(&PageHandler::ScreencastFrameCaptured, |
| 421 weak_factory_.GetWeakPtr(), | 428 weak_factory_.GetWeakPtr(), |
| 422 last_compositor_frame_metadata_), | 429 last_compositor_frame_metadata_), |
| 423 kN32_SkColorType); | 430 kN32_SkColorType); |
| 431 frames_in_flight_++; |
| 424 } | 432 } |
| 425 } | 433 } |
| 426 | 434 |
| 427 void PageHandler::ScreencastFrameCaptured( | 435 void PageHandler::ScreencastFrameCaptured( |
| 428 const cc::CompositorFrameMetadata& metadata, | 436 const cc::CompositorFrameMetadata& metadata, |
| 429 const SkBitmap& bitmap, | 437 const SkBitmap& bitmap, |
| 430 ReadbackResponse response) { | 438 ReadbackResponse response) { |
| 431 if (response != READBACK_SUCCESS) { | 439 if (response != READBACK_SUCCESS) { |
| 432 processing_screencast_frame_ = false; | |
| 433 if (capture_retry_count_) { | 440 if (capture_retry_count_) { |
| 434 --capture_retry_count_; | 441 --capture_retry_count_; |
| 435 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 442 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 436 FROM_HERE, base::Bind(&PageHandler::InnerSwapCompositorFrame, | 443 FROM_HERE, base::Bind(&PageHandler::InnerSwapCompositorFrame, |
| 437 weak_factory_.GetWeakPtr()), | 444 weak_factory_.GetWeakPtr()), |
| 438 base::TimeDelta::FromMilliseconds(kFrameRetryDelayMs)); | 445 base::TimeDelta::FromMilliseconds(kFrameRetryDelayMs)); |
| 439 } | 446 } |
| 447 --frames_in_flight_; |
| 440 return; | 448 return; |
| 441 } | 449 } |
| 442 base::PostTaskAndReplyWithResult( | 450 base::PostTaskAndReplyWithResult( |
| 443 base::WorkerPool::GetTaskRunner(true).get(), | 451 base::WorkerPool::GetTaskRunner(true).get(), |
| 444 FROM_HERE, | 452 FROM_HERE, |
| 445 base::Bind(&EncodeScreencastFrame, | 453 base::Bind(&EncodeScreencastFrame, |
| 446 bitmap, screencast_format_, screencast_quality_), | 454 bitmap, screencast_format_, screencast_quality_), |
| 447 base::Bind(&PageHandler::ScreencastFrameEncoded, | 455 base::Bind(&PageHandler::ScreencastFrameEncoded, |
| 448 weak_factory_.GetWeakPtr(), metadata, base::Time::Now())); | 456 weak_factory_.GetWeakPtr(), metadata, base::Time::Now())); |
| 449 } | 457 } |
| 450 | 458 |
| 451 void PageHandler::ScreencastFrameEncoded( | 459 void PageHandler::ScreencastFrameEncoded( |
| 452 const cc::CompositorFrameMetadata& metadata, | 460 const cc::CompositorFrameMetadata& metadata, |
| 453 const base::Time& timestamp, | 461 const base::Time& timestamp, |
| 454 const std::string& data) { | 462 const std::string& data) { |
| 455 processing_screencast_frame_ = false; | |
| 456 | |
| 457 // Consider metadata empty in case it has no device scale factor. | 463 // Consider metadata empty in case it has no device scale factor. |
| 458 if (metadata.device_scale_factor == 0 || !host_ || data.empty()) | 464 if (metadata.device_scale_factor == 0 || !host_ || data.empty()) { |
| 465 --frames_in_flight_; |
| 459 return; | 466 return; |
| 467 } |
| 460 | 468 |
| 461 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( | 469 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( |
| 462 host_->GetView()); | 470 host_->GetView()); |
| 463 if (!view) | 471 if (!view) { |
| 472 --frames_in_flight_; |
| 464 return; | 473 return; |
| 474 } |
| 465 | 475 |
| 466 gfx::SizeF screen_size_dip = | 476 gfx::SizeF screen_size_dip = |
| 467 gfx::ScaleSize(gfx::SizeF(view->GetPhysicalBackingSize()), | 477 gfx::ScaleSize(gfx::SizeF(view->GetPhysicalBackingSize()), |
| 468 1 / metadata.device_scale_factor); | 478 1 / metadata.device_scale_factor); |
| 469 scoped_refptr<ScreencastFrameMetadata> param_metadata = | 479 scoped_refptr<ScreencastFrameMetadata> param_metadata = |
| 470 ScreencastFrameMetadata::Create() | 480 ScreencastFrameMetadata::Create() |
| 471 ->set_page_scale_factor(metadata.page_scale_factor) | 481 ->set_page_scale_factor(metadata.page_scale_factor) |
| 472 ->set_offset_top(metadata.location_bar_content_translation.y()) | 482 ->set_offset_top(metadata.location_bar_content_translation.y()) |
| 473 ->set_device_width(screen_size_dip.width()) | 483 ->set_device_width(screen_size_dip.width()) |
| 474 ->set_device_height(screen_size_dip.height()) | 484 ->set_device_height(screen_size_dip.height()) |
| 475 ->set_scroll_offset_x(metadata.root_scroll_offset.x()) | 485 ->set_scroll_offset_x(metadata.root_scroll_offset.x()) |
| 476 ->set_scroll_offset_y(metadata.root_scroll_offset.y()) | 486 ->set_scroll_offset_y(metadata.root_scroll_offset.y()) |
| 477 ->set_timestamp(timestamp.ToDoubleT()); | 487 ->set_timestamp(timestamp.ToDoubleT()); |
| 478 client_->ScreencastFrame(ScreencastFrameParams::Create() | 488 client_->ScreencastFrame(ScreencastFrameParams::Create() |
| 479 ->set_data(data) | 489 ->set_data(data) |
| 480 ->set_metadata(param_metadata) | 490 ->set_metadata(param_metadata) |
| 481 ->set_frame_number(++screencast_frame_sent_)); | 491 ->set_session_id(session_id_)); |
| 482 } | 492 } |
| 483 | 493 |
| 484 void PageHandler::ScreenshotCaptured(DevToolsCommandId command_id, | 494 void PageHandler::ScreenshotCaptured(DevToolsCommandId command_id, |
| 485 const unsigned char* png_data, | 495 const unsigned char* png_data, |
| 486 size_t png_size) { | 496 size_t png_size) { |
| 487 if (!png_data || !png_size) { | 497 if (!png_data || !png_size) { |
| 488 client_->SendError(command_id, | 498 client_->SendError(command_id, |
| 489 Response::InternalError("Unable to capture screenshot")); | 499 Response::InternalError("Unable to capture screenshot")); |
| 490 return; | 500 return; |
| 491 } | 501 } |
| 492 | 502 |
| 493 std::string base_64_data; | 503 std::string base_64_data; |
| 494 base::Base64Encode( | 504 base::Base64Encode( |
| 495 base::StringPiece(reinterpret_cast<const char*>(png_data), png_size), | 505 base::StringPiece(reinterpret_cast<const char*>(png_data), png_size), |
| 496 &base_64_data); | 506 &base_64_data); |
| 497 | 507 |
| 498 client_->SendCaptureScreenshotResponse(command_id, | 508 client_->SendCaptureScreenshotResponse(command_id, |
| 499 CaptureScreenshotResponse::Create()->set_data(base_64_data)); | 509 CaptureScreenshotResponse::Create()->set_data(base_64_data)); |
| 500 } | 510 } |
| 501 | 511 |
| 502 void PageHandler::OnColorPicked(int r, int g, int b, int a) { | 512 void PageHandler::OnColorPicked(int r, int g, int b, int a) { |
| 503 scoped_refptr<dom::RGBA> color = | 513 scoped_refptr<dom::RGBA> color = |
| 504 dom::RGBA::Create()->set_r(r)->set_g(g)->set_b(b)->set_a(a); | 514 dom::RGBA::Create()->set_r(r)->set_g(g)->set_b(b)->set_a(a); |
| 505 client_->ColorPicked(ColorPickedParams::Create()->set_color(color)); | 515 client_->ColorPicked(ColorPickedParams::Create()->set_color(color)); |
| 506 } | 516 } |
| 507 | 517 |
| 508 } // namespace page | 518 } // namespace page |
| 509 } // namespace devtools | 519 } // namespace devtools |
| 510 } // namespace content | 520 } // namespace content |
| OLD | NEW |