screenshot_grabber.cc 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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
  3. // found in the LICENSE file.
  4. #include "ui/snapshot/screenshot_grabber.h"
  5. #include <stddef.h>
  6. #include <climits>
  7. #include "base/bind.h"
  8. #include "base/callback.h"
  9. #include "base/callback_helpers.h"
  10. #include "base/location.h"
  11. #include "base/logging.h"
  12. #include "base/memory/ptr_util.h"
  13. #include "base/memory/raw_ptr.h"
  14. #include "base/task/current_thread.h"
  15. #include "base/task/single_thread_task_runner.h"
  16. #include "base/task/task_runner.h"
  17. #include "base/threading/thread_task_runner_handle.h"
  18. #include "base/time/time.h"
  19. #include "ui/snapshot/snapshot.h"
  20. #if defined(USE_AURA)
  21. #include "ui/aura/client/cursor_client.h"
  22. #include "ui/aura/window.h"
  23. #endif
  24. namespace ui {
  25. namespace {
  26. // The minimum interval between two screenshot commands. It has to be
  27. // more than 1000 to prevent the conflict of filenames.
  28. const int kScreenshotMinimumIntervalInMS = 1000;
  29. } // namespace
  30. #if defined(USE_AURA)
  31. class ScreenshotGrabber::ScopedCursorHider {
  32. public:
  33. // The nullptr might be returned when GetCursorClient is nullptr.
  34. static std::unique_ptr<ScopedCursorHider> Create(aura::Window* window) {
  35. DCHECK(window->IsRootWindow());
  36. aura::client::CursorClient* cursor_client =
  37. aura::client::GetCursorClient(window);
  38. if (!cursor_client)
  39. return nullptr;
  40. cursor_client->HideCursor();
  41. return std::unique_ptr<ScopedCursorHider>(
  42. base::WrapUnique(new ScopedCursorHider(window)));
  43. }
  44. ScopedCursorHider(const ScopedCursorHider&) = delete;
  45. ScopedCursorHider& operator=(const ScopedCursorHider&) = delete;
  46. ~ScopedCursorHider() {
  47. aura::client::CursorClient* cursor_client =
  48. aura::client::GetCursorClient(window_);
  49. cursor_client->ShowCursor();
  50. }
  51. private:
  52. explicit ScopedCursorHider(aura::Window* window) : window_(window) {}
  53. raw_ptr<aura::Window> window_;
  54. };
  55. #endif
  56. ScreenshotGrabber::ScreenshotGrabber() {}
  57. ScreenshotGrabber::~ScreenshotGrabber() {
  58. }
  59. void ScreenshotGrabber::TakeScreenshot(gfx::NativeWindow window,
  60. const gfx::Rect& rect,
  61. ScreenshotCallback callback) {
  62. DCHECK(base::CurrentUIThread::IsSet());
  63. last_screenshot_timestamp_ = base::TimeTicks::Now();
  64. bool is_partial = true;
  65. // Window identifier is used to log a message on failure to capture a full
  66. // screen (i.e. non partial) screenshot. The only time is_partial can be
  67. // false, we will also have an identification string for the window.
  68. std::string window_identifier;
  69. #if defined(USE_AURA)
  70. aura::Window* aura_window = static_cast<aura::Window*>(window);
  71. is_partial = rect.size() != aura_window->bounds().size();
  72. window_identifier = aura_window->GetBoundsInScreen().ToString();
  73. cursor_hider_ = ScopedCursorHider::Create(aura_window->GetRootWindow());
  74. #endif
  75. ui::GrabWindowSnapshotAsyncPNG(
  76. window, rect,
  77. base::BindOnce(&ScreenshotGrabber::GrabWindowSnapshotAsyncCallback,
  78. factory_.GetWeakPtr(), window_identifier, is_partial,
  79. std::move(callback)));
  80. }
  81. bool ScreenshotGrabber::CanTakeScreenshot() {
  82. return last_screenshot_timestamp_.is_null() ||
  83. base::TimeTicks::Now() - last_screenshot_timestamp_ >
  84. base::Milliseconds(kScreenshotMinimumIntervalInMS);
  85. }
  86. void ScreenshotGrabber::GrabWindowSnapshotAsyncCallback(
  87. const std::string& window_identifier,
  88. bool is_partial,
  89. ScreenshotCallback callback,
  90. scoped_refptr<base::RefCountedMemory> png_data) {
  91. DCHECK(base::CurrentUIThread::IsSet());
  92. #if defined(USE_AURA)
  93. cursor_hider_.reset();
  94. #endif
  95. if (!png_data.get()) {
  96. if (is_partial) {
  97. LOG(ERROR) << "Failed to grab the window screenshot";
  98. std::move(callback).Run(ScreenshotResult::GRABWINDOW_PARTIAL_FAILED,
  99. nullptr);
  100. } else {
  101. LOG(ERROR) << "Failed to grab the window screenshot for "
  102. << window_identifier;
  103. std::move(callback).Run(ScreenshotResult::GRABWINDOW_FULL_FAILED,
  104. nullptr);
  105. }
  106. return;
  107. }
  108. std::move(callback).Run(ScreenshotResult::SUCCESS, std::move(png_data));
  109. }
  110. } // namespace ui