OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 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 | |
5 #include "components/screenshot_taker/screenshot_taker.h" | |
6 | |
7 #include <climits> | |
8 #include <string> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/files/file_util.h" | |
12 #include "base/logging.h" | |
13 #include "base/threading/sequenced_worker_pool.h" | |
14 #include "base/time/time.h" | |
15 #include "content/public/browser/browser_thread.h" | |
16 #include "ui/aura/window.h" | |
17 #include "ui/gfx/image/image.h" | |
18 #include "ui/snapshot/snapshot.h" | |
19 | |
20 namespace { | |
21 // The minimum interval between two screenshot commands. It has to be | |
22 // more than 1000 to prevent the conflict of filenames. | |
23 const int kScreenshotMinimumIntervalInMS = 1000; | |
24 | |
25 typedef base::Callback< | |
26 void(ScreenshotTakerObserver::Result screenshot_result, | |
27 const base::FilePath& screenshot_path)> ShowNotificationCallback; | |
28 | |
29 void SaveScreenshot(const ShowNotificationCallback& callback, | |
30 const base::FilePath& screenshot_path, | |
31 scoped_refptr<base::RefCountedBytes> png_data, | |
32 ScreenshotTakerClient::WritableFileResult result, | |
33 const base::FilePath& local_path) { | |
34 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
Jun Mukai
2014/11/12 19:36:21
Can we use SequencedWorkerPool as a constructor pa
flackr
2014/11/18 16:46:30
Done.
| |
35 DCHECK(!screenshot_path.empty()); | |
36 | |
37 // Convert WritableFileResult into ScreenshotTakerObserver::Result. | |
38 ScreenshotTakerObserver::Result screenshot_result = | |
39 ScreenshotTakerObserver::SCREENSHOT_SUCCESS; | |
40 switch(result) { | |
41 case ScreenshotTakerClient::WRITABLE_FILE_SUCCESS: | |
42 // Successful so far, continue to attempt to take screenshot. | |
43 break; | |
44 case ScreenshotTakerClient::WRITABLE_FILE_CHECK_DIR_FAILED: | |
45 screenshot_result = | |
46 ScreenshotTakerObserver::SCREENSHOT_CHECK_DIR_FAILED; | |
47 break; | |
48 case ScreenshotTakerClient::WRITABLE_FILE_CREATE_DIR_FAILED: | |
49 screenshot_result = | |
50 ScreenshotTakerObserver::SCREENSHOT_CREATE_DIR_FAILED; | |
51 break; | |
52 case ScreenshotTakerClient::WRITABLE_FILE_CREATE_FAILED: | |
53 screenshot_result = | |
54 ScreenshotTakerObserver::SCREENSHOT_CREATE_FILE_FAILED; | |
55 break; | |
56 } | |
57 | |
58 if (screenshot_result == ScreenshotTakerObserver::SCREENSHOT_SUCCESS && | |
59 static_cast<size_t>(base::WriteFile( | |
60 local_path, | |
61 reinterpret_cast<char*>(&(png_data->data()[0])), | |
62 png_data->size())) != png_data->size()) { | |
63 LOG(ERROR) << "Failed to save to " << local_path.value(); | |
64 screenshot_result = ScreenshotTakerObserver::SCREENSHOT_WRITE_FILE_FAILED; | |
65 } | |
66 | |
67 // Report the result on the UI thread. | |
68 content::BrowserThread::PostTask( | |
69 content::BrowserThread::UI, FROM_HERE, | |
70 base::Bind(callback, screenshot_result, screenshot_path)); | |
71 } | |
72 | |
73 void EnsureLocalDirectoryExists( | |
74 const base::FilePath& path, | |
75 ScreenshotTakerClient::WritableFileCallback callback) { | |
76 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
77 DCHECK(!path.empty()); | |
78 | |
79 if (!base::CreateDirectory(path.DirName())) { | |
80 LOG(ERROR) << "Failed to ensure the existence of " | |
81 << path.DirName().value(); | |
82 content::BrowserThread::PostTask( | |
83 content::BrowserThread::UI, FROM_HERE, | |
84 base::Bind(callback, | |
85 ScreenshotTakerClient::WRITABLE_FILE_CREATE_DIR_FAILED, | |
86 path)); | |
87 return; | |
88 } | |
89 | |
90 callback.Run(ScreenshotTakerClient::WRITABLE_FILE_SUCCESS, path); | |
91 } | |
92 | |
93 } // namespace | |
94 | |
95 void ScreenshotTakerClient::PrepareWritableFileAndRunOnBlockingPool( | |
96 const base::FilePath& path, | |
97 WritableFileCallback callback_on_blocking_pool) { | |
98 content::BrowserThread::GetBlockingPool()->PostTask( | |
99 FROM_HERE, base::Bind(EnsureLocalDirectoryExists, | |
100 path, | |
101 callback_on_blocking_pool)); | |
102 } | |
103 | |
104 ScreenshotTaker::ScreenshotTaker(ScreenshotTakerClient* client) | |
105 : client_(client), | |
106 factory_(this) { | |
107 } | |
108 | |
109 ScreenshotTaker::~ScreenshotTaker() { | |
110 } | |
111 | |
112 void ScreenshotTaker::TakeScreenshot( | |
113 aura::Window* window, | |
114 const gfx::Rect& rect, | |
115 const base::FilePath& screenshot_path) { | |
116 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
117 last_screenshot_timestamp_ = base::Time::Now(); | |
118 | |
119 bool is_partial = rect == window->bounds(); | |
120 ui::GrabWindowSnapshotAsync( | |
121 window, | |
122 rect, | |
123 content::BrowserThread::GetBlockingPool(), | |
124 base::Bind(&ScreenshotTaker::GrabWindowSnapshotAsyncCallback, | |
125 factory_.GetWeakPtr(), | |
126 window->GetBoundsInScreen().ToString(), | |
127 screenshot_path, | |
128 is_partial)); | |
129 } | |
130 | |
131 bool ScreenshotTaker::CanTakeScreenshot() { | |
132 return last_screenshot_timestamp_.is_null() || | |
133 base::Time::Now() - last_screenshot_timestamp_ > | |
134 base::TimeDelta::FromMilliseconds( | |
135 kScreenshotMinimumIntervalInMS); | |
136 } | |
137 | |
138 void ScreenshotTaker::NotifyScreenshotCompleted( | |
139 ScreenshotTakerObserver::Result screenshot_result, | |
140 const base::FilePath& screenshot_path) { | |
141 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
142 FOR_EACH_OBSERVER(ScreenshotTakerObserver, observers_, | |
143 OnScreenshotCompleted(screenshot_result, screenshot_path)); | |
144 } | |
145 | |
146 void ScreenshotTaker::AddObserver(ScreenshotTakerObserver* observer) { | |
147 observers_.AddObserver(observer); | |
148 } | |
149 | |
150 void ScreenshotTaker::RemoveObserver(ScreenshotTakerObserver* observer) { | |
151 observers_.RemoveObserver(observer); | |
152 } | |
153 | |
154 bool ScreenshotTaker::HasObserver( | |
155 const ScreenshotTakerObserver* observer) const { | |
156 return observers_.HasObserver(observer); | |
157 } | |
158 | |
159 void ScreenshotTaker::GrabWindowSnapshotAsyncCallback( | |
160 const std::string& screen_bounds, | |
161 base::FilePath screenshot_path, | |
162 bool is_partial, | |
163 scoped_refptr<base::RefCountedBytes> png_data) { | |
164 if (!png_data.get()) { | |
165 if (is_partial) { | |
166 LOG(ERROR) << "Failed to grab the window screenshot"; | |
167 NotifyScreenshotCompleted( | |
168 ScreenshotTakerObserver::SCREENSHOT_GRABWINDOW_PARTIAL_FAILED, | |
169 screenshot_path); | |
170 } else { | |
171 LOG(ERROR) << "Failed to grab the window screenshot for " | |
172 << screen_bounds; | |
173 NotifyScreenshotCompleted( | |
174 ScreenshotTakerObserver::SCREENSHOT_GRABWINDOW_FULL_FAILED, | |
175 screenshot_path); | |
176 } | |
177 return; | |
178 } | |
179 | |
180 client_->PrepareWritableFileAndRunOnBlockingPool( | |
181 screenshot_path, base::Bind( | |
182 &SaveScreenshot, | |
183 base::Bind(&ScreenshotTaker::NotifyScreenshotCompleted, | |
184 factory_.GetWeakPtr()), | |
185 screenshot_path, | |
186 png_data)); | |
187 } | |
OLD | NEW |