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...) 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...) 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...) 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 |