| 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" |
| 11 #include "base/location.h" | 11 #include "base/location.h" |
| 12 #include "base/memory/ref_counted.h" | |
| 13 #include "base/memory/ref_counted_memory.h" | |
| 14 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
| 15 #include "base/strings/string16.h" | 13 #include "base/strings/string16.h" |
| 16 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
| 17 #include "base/task_scheduler/post_task.h" | 15 #include "base/task_scheduler/post_task.h" |
| 18 #include "base/threading/thread_task_runner_handle.h" | 16 #include "base/threading/thread_task_runner_handle.h" |
| 19 #include "content/browser/devtools/devtools_session.h" | 17 #include "content/browser/devtools/devtools_session.h" |
| 20 #include "content/browser/devtools/page_navigation_throttle.h" | 18 #include "content/browser/devtools/page_navigation_throttle.h" |
| 21 #include "content/browser/devtools/protocol/color_picker.h" | 19 #include "content/browser/devtools/protocol/color_picker.h" |
| 22 #include "content/browser/renderer_host/render_widget_host_impl.h" | 20 #include "content/browser/renderer_host/render_widget_host_impl.h" |
| 23 #include "content/browser/renderer_host/render_widget_host_view_base.h" | 21 #include "content/browser/renderer_host/render_widget_host_view_base.h" |
| 24 #include "content/browser/web_contents/web_contents_impl.h" | 22 #include "content/browser/web_contents/web_contents_impl.h" |
| 25 #include "content/browser/web_contents/web_contents_view.h" | 23 #include "content/browser/web_contents/web_contents_view.h" |
| 26 #include "content/common/view_messages.h" | 24 #include "content/common/view_messages.h" |
| 27 #include "content/public/browser/browser_thread.h" | 25 #include "content/public/browser/browser_thread.h" |
| 28 #include "content/public/browser/javascript_dialog_manager.h" | 26 #include "content/public/browser/javascript_dialog_manager.h" |
| 29 #include "content/public/browser/navigation_controller.h" | 27 #include "content/public/browser/navigation_controller.h" |
| 30 #include "content/public/browser/navigation_entry.h" | 28 #include "content/public/browser/navigation_entry.h" |
| 31 #include "content/public/browser/navigation_handle.h" | 29 #include "content/public/browser/navigation_handle.h" |
| 32 #include "content/public/browser/notification_service.h" | 30 #include "content/public/browser/notification_service.h" |
| 33 #include "content/public/browser/notification_types.h" | 31 #include "content/public/browser/notification_types.h" |
| 34 #include "content/public/browser/storage_partition.h" | 32 #include "content/public/browser/storage_partition.h" |
| 35 #include "content/public/browser/web_contents_delegate.h" | 33 #include "content/public/browser/web_contents_delegate.h" |
| 36 #include "content/public/common/referrer.h" | 34 #include "content/public/common/referrer.h" |
| 37 #include "third_party/skia/include/core/SkBitmap.h" | 35 #include "third_party/skia/include/core/SkBitmap.h" |
| 38 #include "ui/base/page_transition_types.h" | 36 #include "ui/base/page_transition_types.h" |
| 39 #include "ui/gfx/codec/jpeg_codec.h" | 37 #include "ui/gfx/codec/jpeg_codec.h" |
| 40 #include "ui/gfx/codec/png_codec.h" | 38 #include "ui/gfx/codec/png_codec.h" |
| 41 #include "ui/gfx/geometry/size_conversions.h" | 39 #include "ui/gfx/geometry/size_conversions.h" |
| 42 #include "ui/gfx/image/image.h" | |
| 43 #include "ui/gfx/image/image_util.h" | |
| 44 #include "ui/snapshot/snapshot.h" | 40 #include "ui/snapshot/snapshot.h" |
| 45 #include "url/gurl.h" | 41 #include "url/gurl.h" |
| 46 | 42 |
| 47 namespace content { | 43 namespace content { |
| 48 namespace protocol { | 44 namespace protocol { |
| 49 | 45 |
| 50 namespace { | 46 namespace { |
| 51 | 47 |
| 52 static const char kPng[] = "png"; | 48 static const char kPng[] = "png"; |
| 53 static const char kJpeg[] = "jpeg"; | 49 static const char kJpeg[] = "jpeg"; |
| 54 static int kDefaultScreenshotQuality = 80; | 50 static int kDefaultScreenshotQuality = 80; |
| 55 static int kFrameRetryDelayMs = 100; | 51 static int kFrameRetryDelayMs = 100; |
| 56 static int kCaptureRetryLimit = 2; | 52 static int kCaptureRetryLimit = 2; |
| 57 static int kMaxScreencastFramesInFlight = 2; | 53 static int kMaxScreencastFramesInFlight = 2; |
| 58 | 54 |
| 59 std::string EncodeImage(const gfx::Image& image, | 55 std::string EncodeScreencastFrame(const SkBitmap& bitmap, |
| 60 const std::string& format, | 56 const std::string& format, |
| 61 int quality) { | 57 int quality) { |
| 62 DCHECK(!image.IsEmpty()); | 58 std::vector<unsigned char> data; |
| 63 | 59 SkAutoLockPixels lock_image(bitmap); |
| 64 scoped_refptr<base::RefCountedMemory> data; | 60 bool encoded; |
| 65 if (format == kPng) { | 61 if (format == kPng) { |
| 66 data = image.As1xPNGBytes(); | 62 encoded = gfx::PNGCodec::Encode( |
| 63 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)), |
| 64 gfx::PNGCodec::FORMAT_SkBitmap, |
| 65 gfx::Size(bitmap.width(), bitmap.height()), |
| 66 bitmap.width() * bitmap.bytesPerPixel(), |
| 67 false, std::vector<gfx::PNGCodec::Comment>(), &data); |
| 67 } else if (format == kJpeg) { | 68 } else if (format == kJpeg) { |
| 68 scoped_refptr<base::RefCountedBytes> bytes(new base::RefCountedBytes()); | 69 encoded = gfx::JPEGCodec::Encode( |
| 69 if (gfx::JPEG1xEncodedDataFromImage(image, quality, &bytes->data())) | 70 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)), |
| 70 data = bytes; | 71 gfx::JPEGCodec::FORMAT_SkBitmap, |
| 72 bitmap.width(), |
| 73 bitmap.height(), |
| 74 bitmap.width() * bitmap.bytesPerPixel(), |
| 75 quality, &data); |
| 76 } else { |
| 77 encoded = false; |
| 71 } | 78 } |
| 72 | 79 |
| 73 if (!data || !data->front()) | 80 if (!encoded) |
| 74 return std::string(); | 81 return std::string(); |
| 75 | 82 |
| 76 std::string base_64_data; | 83 std::string base_64_data; |
| 77 base::Base64Encode( | 84 base::Base64Encode( |
| 78 base::StringPiece(reinterpret_cast<const char*>(data->front()), | 85 base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()), |
| 79 data->size()), | |
| 80 &base_64_data); | 86 &base_64_data); |
| 81 | 87 |
| 82 return base_64_data; | 88 return base_64_data; |
| 83 } | 89 } |
| 84 | 90 |
| 85 } // namespace | 91 } // namespace |
| 86 | 92 |
| 87 PageHandler::PageHandler() | 93 PageHandler::PageHandler() |
| 88 : DevToolsDomainHandler(Page::Metainfo::domainName), | 94 : DevToolsDomainHandler(Page::Metainfo::domainName), |
| 89 enabled_(false), | 95 enabled_(false), |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 if (controller.GetEntryAtIndex(i)->GetUniqueID() == entry_id) { | 278 if (controller.GetEntryAtIndex(i)->GetUniqueID() == entry_id) { |
| 273 controller.GoToIndex(i); | 279 controller.GoToIndex(i); |
| 274 return Response::OK(); | 280 return Response::OK(); |
| 275 } | 281 } |
| 276 } | 282 } |
| 277 | 283 |
| 278 return Response::InvalidParams("No entry with passed id"); | 284 return Response::InvalidParams("No entry with passed id"); |
| 279 } | 285 } |
| 280 | 286 |
| 281 void PageHandler::CaptureScreenshot( | 287 void PageHandler::CaptureScreenshot( |
| 282 Maybe<std::string> format, | |
| 283 Maybe<int> quality, | |
| 284 std::unique_ptr<CaptureScreenshotCallback> callback) { | 288 std::unique_ptr<CaptureScreenshotCallback> callback) { |
| 285 if (!host_ || !host_->GetRenderWidgetHost()) { | 289 if (!host_ || !host_->GetRenderWidgetHost()) { |
| 286 callback->sendFailure(Response::InternalError()); | 290 callback->sendFailure(Response::InternalError()); |
| 287 return; | 291 return; |
| 288 } | 292 } |
| 289 | 293 |
| 290 std::string screenshot_format = format.fromMaybe(kPng); | |
| 291 int screenshot_quality = quality.fromMaybe(kDefaultScreenshotQuality); | |
| 292 | |
| 293 host_->GetRenderWidgetHost()->GetSnapshotFromBrowser( | 294 host_->GetRenderWidgetHost()->GetSnapshotFromBrowser( |
| 294 base::Bind(&PageHandler::ScreenshotCaptured, weak_factory_.GetWeakPtr(), | 295 base::Bind(&PageHandler::ScreenshotCaptured, |
| 295 base::Passed(std::move(callback)), screenshot_format, | 296 weak_factory_.GetWeakPtr(), base::Passed(std::move(callback)))); |
| 296 screenshot_quality)); | |
| 297 } | 297 } |
| 298 | 298 |
| 299 Response PageHandler::StartScreencast(Maybe<std::string> format, | 299 Response PageHandler::StartScreencast(Maybe<std::string> format, |
| 300 Maybe<int> quality, | 300 Maybe<int> quality, |
| 301 Maybe<int> max_width, | 301 Maybe<int> max_width, |
| 302 Maybe<int> max_height, | 302 Maybe<int> max_height, |
| 303 Maybe<int> every_nth_frame) { | 303 Maybe<int> every_nth_frame) { |
| 304 RenderWidgetHostImpl* widget_host = | 304 RenderWidgetHostImpl* widget_host = |
| 305 host_ ? host_->GetRenderWidgetHost() : nullptr; | 305 host_ ? host_->GetRenderWidgetHost() : nullptr; |
| 306 if (!widget_host) | 306 if (!widget_host) |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 FROM_HERE, base::Bind(&PageHandler::InnerSwapCompositorFrame, | 512 FROM_HERE, base::Bind(&PageHandler::InnerSwapCompositorFrame, |
| 513 weak_factory_.GetWeakPtr()), | 513 weak_factory_.GetWeakPtr()), |
| 514 base::TimeDelta::FromMilliseconds(kFrameRetryDelayMs)); | 514 base::TimeDelta::FromMilliseconds(kFrameRetryDelayMs)); |
| 515 } | 515 } |
| 516 --frames_in_flight_; | 516 --frames_in_flight_; |
| 517 return; | 517 return; |
| 518 } | 518 } |
| 519 base::PostTaskWithTraitsAndReplyWithResult( | 519 base::PostTaskWithTraitsAndReplyWithResult( |
| 520 FROM_HERE, base::TaskTraits().WithShutdownBehavior( | 520 FROM_HERE, base::TaskTraits().WithShutdownBehavior( |
| 521 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN), | 521 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN), |
| 522 base::Bind(&EncodeImage, gfx::Image::CreateFrom1xBitmap(bitmap), | 522 base::Bind(&EncodeScreencastFrame, bitmap, screencast_format_, |
| 523 screencast_format_, screencast_quality_), | 523 screencast_quality_), |
| 524 base::Bind(&PageHandler::ScreencastFrameEncoded, | 524 base::Bind(&PageHandler::ScreencastFrameEncoded, |
| 525 weak_factory_.GetWeakPtr(), base::Passed(&metadata), | 525 weak_factory_.GetWeakPtr(), base::Passed(&metadata), |
| 526 base::Time::Now())); | 526 base::Time::Now())); |
| 527 } | 527 } |
| 528 | 528 |
| 529 void PageHandler::ScreencastFrameEncoded(cc::CompositorFrameMetadata metadata, | 529 void PageHandler::ScreencastFrameEncoded(cc::CompositorFrameMetadata metadata, |
| 530 const base::Time& timestamp, | 530 const base::Time& timestamp, |
| 531 const std::string& data) { | 531 const std::string& data) { |
| 532 // Consider metadata empty in case it has no device scale factor. | 532 // Consider metadata empty in case it has no device scale factor. |
| 533 if (metadata.device_scale_factor == 0 || !host_ || data.empty()) { | 533 if (metadata.device_scale_factor == 0 || !host_ || data.empty()) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 554 .SetDeviceHeight(screen_size_dip.height()) | 554 .SetDeviceHeight(screen_size_dip.height()) |
| 555 .SetScrollOffsetX(metadata.root_scroll_offset.x()) | 555 .SetScrollOffsetX(metadata.root_scroll_offset.x()) |
| 556 .SetScrollOffsetY(metadata.root_scroll_offset.y()) | 556 .SetScrollOffsetY(metadata.root_scroll_offset.y()) |
| 557 .SetTimestamp(timestamp.ToDoubleT()) | 557 .SetTimestamp(timestamp.ToDoubleT()) |
| 558 .Build(); | 558 .Build(); |
| 559 frontend_->ScreencastFrame(data, std::move(param_metadata), session_id_); | 559 frontend_->ScreencastFrame(data, std::move(param_metadata), session_id_); |
| 560 } | 560 } |
| 561 | 561 |
| 562 void PageHandler::ScreenshotCaptured( | 562 void PageHandler::ScreenshotCaptured( |
| 563 std::unique_ptr<CaptureScreenshotCallback> callback, | 563 std::unique_ptr<CaptureScreenshotCallback> callback, |
| 564 const std::string& format, | 564 const unsigned char* png_data, |
| 565 int quality, | 565 size_t png_size) { |
| 566 const gfx::Image& image) { | 566 if (!png_data || !png_size) { |
| 567 if (image.IsEmpty()) { | |
| 568 callback->sendFailure(Response::Error("Unable to capture screenshot")); | 567 callback->sendFailure(Response::Error("Unable to capture screenshot")); |
| 569 return; | 568 return; |
| 570 } | 569 } |
| 571 | 570 |
| 572 callback->sendSuccess(EncodeImage(image, format, quality)); | 571 std::string base_64_data; |
| 572 base::Base64Encode( |
| 573 base::StringPiece(reinterpret_cast<const char*>(png_data), png_size), |
| 574 &base_64_data); |
| 575 callback->sendSuccess(base_64_data); |
| 573 } | 576 } |
| 574 | 577 |
| 575 void PageHandler::OnColorPicked(int r, int g, int b, int a) { | 578 void PageHandler::OnColorPicked(int r, int g, int b, int a) { |
| 576 frontend_->ColorPicked( | 579 frontend_->ColorPicked( |
| 577 DOM::RGBA::Create().SetR(r).SetG(g).SetB(b).SetA(a).Build()); | 580 DOM::RGBA::Create().SetR(r).SetG(g).SetB(b).SetA(a).Build()); |
| 578 } | 581 } |
| 579 | 582 |
| 580 Response PageHandler::StopLoading() { | 583 Response PageHandler::StopLoading() { |
| 581 WebContentsImpl* web_contents = GetWebContents(); | 584 WebContentsImpl* web_contents = GetWebContents(); |
| 582 if (!web_contents) | 585 if (!web_contents) |
| 583 return Response::InternalError(); | 586 return Response::InternalError(); |
| 584 web_contents->Stop(); | 587 web_contents->Stop(); |
| 585 return Response::OK(); | 588 return Response::OK(); |
| 586 } | 589 } |
| 587 | 590 |
| 588 } // namespace protocol | 591 } // namespace protocol |
| 589 } // namespace content | 592 } // namespace content |
| OLD | NEW |