Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 5 #include "chrome/browser/extensions/api/document_scan/document_scan_api.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #if defined(OS_CHROMEOS) | |
| 10 #include "base/task_runner_util.h" | |
| 11 #include "base/threading/worker_pool.h" | |
| 12 #include "chromeos/dbus/dbus_thread_manager.h" | |
| 13 #include "chromeos/dbus/lorgnette_manager_client.h" | |
| 14 #include "chromeos/dbus/pipe_reader.h" | |
| 15 #endif // OS_CHROMEOS | |
| 16 #include "content/public/browser/browser_thread.h" | |
| 17 #include "extensions/browser/extension_system.h" | |
| 18 #if defined(OS_CHROMEOS) | |
| 19 #include "third_party/cros_system_api/dbus/service_constants.h" | |
| 20 #endif // OS_CHROMEOS | |
| 21 | |
| 22 using content::BrowserThread; | |
| 23 using std::string; | |
| 24 using std::vector; | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 const char kImageScanFailedError[] = "Image scan failed"; | |
| 29 const char kScannerImageMimeTypePng[] = "image/png"; | |
| 30 const char kScannerNotAvailable[] = "Scanner not available"; | |
| 31 const char kScanFunctionNotImplementedError[] = "Scan function not implemented"; | |
| 32 const char kUserGestureRequiredError[] = | |
| 33 "User gesture required to perform scan"; | |
| 34 const char kPngImageDataUrlPrefix[] = "data:image/png;base64,"; | |
| 35 } // namespace | |
| 36 | |
| 37 namespace extensions { | |
| 38 | |
| 39 namespace api { | |
| 40 | |
| 41 #if defined(OS_CHROMEOS) | |
|
mef
2014/10/13 15:59:54
Suggest: split into 3 files:
document_scan_interf
Paul Stewart
2014/10/14 19:28:31
Done, except for consistency sake with the generat
| |
| 42 class DocumentScanInterfaceImpl : public DocumentScanInterface { | |
| 43 public: | |
| 44 DocumentScanInterfaceImpl() {} | |
| 45 virtual ~DocumentScanInterfaceImpl() {} | |
| 46 | |
| 47 virtual void ListScanners( | |
| 48 const ListScannersResultsCallback& callback) OVERRIDE; | |
| 49 virtual void Scan(const string& scanner_name, | |
| 50 ScanMode mode, | |
| 51 int resolution_dpi, | |
| 52 const ScanResultsCallback& callback) OVERRIDE; | |
| 53 | |
| 54 private: | |
| 55 void OnScannerListReceived( | |
| 56 const ListScannersResultsCallback& callback, | |
| 57 bool succeeded, | |
| 58 const chromeos::LorgnetteManagerClient::ScannerTable &scanners); | |
| 59 void OnScanCompleted(const ScanResultsCallback &callback, bool succeeded); | |
| 60 void OnScanDataCompleted(); | |
| 61 string GetImageURL(string image_data); | |
| 62 | |
| 63 scoped_ptr<chromeos::PipeReaderForString> pipe_reader_; | |
| 64 string scanned_image_data_; | |
| 65 | |
| 66 DISALLOW_COPY_AND_ASSIGN(DocumentScanInterfaceImpl); | |
| 67 }; | |
| 68 | |
| 69 void DocumentScanInterfaceImpl::ListScanners( | |
| 70 const ListScannersResultsCallback& callback) { | |
| 71 chromeos::DBusThreadManager::Get()->GetLorgnetteManagerClient()-> | |
| 72 ListScanners(base::Bind( | |
| 73 &DocumentScanInterfaceImpl::OnScannerListReceived, | |
| 74 base::Unretained(this), | |
| 75 callback)); | |
| 76 } | |
| 77 | |
| 78 void DocumentScanInterfaceImpl::OnScannerListReceived( | |
| 79 const ListScannersResultsCallback& callback, | |
| 80 bool succeeded, | |
| 81 const chromeos::LorgnetteManagerClient::ScannerTable &scanners) { | |
| 82 vector<ScannerDescription> scanner_descriptions; | |
| 83 for (chromeos::LorgnetteManagerClient::ScannerTable::const_iterator iter = | |
| 84 scanners.begin(); | |
| 85 iter != scanners.end(); | |
| 86 ++iter) { | |
| 87 ScannerDescription description; | |
| 88 description.name = iter->first; | |
| 89 const chromeos::LorgnetteManagerClient::ScannerTableEntry &entry = | |
| 90 iter->second; | |
| 91 chromeos::LorgnetteManagerClient::ScannerTableEntry::const_iterator info_it; | |
| 92 info_it = entry.find(lorgnette::kScannerPropertyManufacturer); | |
| 93 if (info_it != entry.end()) { | |
| 94 description.manufacturer = info_it->second; | |
| 95 } | |
| 96 info_it = entry.find(lorgnette::kScannerPropertyModel); | |
| 97 if (info_it != entry.end()) { | |
| 98 description.model = info_it->second; | |
| 99 } | |
| 100 info_it = entry.find(lorgnette::kScannerPropertyType); | |
| 101 if (info_it != entry.end()) { | |
| 102 description.scanner_type = info_it->second; | |
| 103 } | |
| 104 description.image_mime_type = kScannerImageMimeTypePng; | |
| 105 scanner_descriptions.push_back(description); | |
| 106 } | |
| 107 callback.Run(scanner_descriptions, ""); | |
| 108 } | |
| 109 | |
| 110 void DocumentScanInterfaceImpl::Scan(const string& scanner_name, | |
| 111 ScanMode mode, | |
| 112 int resolution_dpi, | |
| 113 const ScanResultsCallback& callback) { | |
| 114 VLOG(1) << "Choosing scanner " << scanner_name; | |
| 115 chromeos::LorgnetteManagerClient::ScanProperties properties; | |
| 116 switch (mode) { | |
| 117 case kScanModeColor: | |
| 118 properties.mode = lorgnette::kScanPropertyModeColor; | |
| 119 break; | |
| 120 | |
| 121 case kScanModeGray: | |
| 122 properties.mode = lorgnette::kScanPropertyModeGray; | |
| 123 break; | |
| 124 | |
| 125 case kScanModeLineart: | |
| 126 properties.mode = lorgnette::kScanPropertyModeLineart; | |
| 127 break; | |
| 128 | |
| 129 default: | |
| 130 // Leave the mode parameter empty, thereby using the default. | |
| 131 break; | |
| 132 } | |
| 133 | |
| 134 if (resolution_dpi != 0) { | |
| 135 properties.resolution_dpi = resolution_dpi; | |
| 136 } | |
| 137 | |
| 138 const bool kTasksAreSlow = true; | |
| 139 scoped_refptr<base::TaskRunner> task_runner = | |
| 140 base::WorkerPool::GetTaskRunner(kTasksAreSlow); | |
| 141 | |
| 142 pipe_reader_.reset(new chromeos::PipeReaderForString( | |
| 143 task_runner, | |
| 144 base::Bind(&DocumentScanInterfaceImpl::OnScanDataCompleted, | |
| 145 base::Unretained(this)))); | |
| 146 base::File file = pipe_reader_->StartIO(); | |
| 147 base::PlatformFile platform_file = file.TakePlatformFile(); | |
| 148 VLOG(1) << "ScanImage platform_file is " << platform_file; | |
| 149 chromeos::DBusThreadManager::Get()->GetLorgnetteManagerClient()-> | |
| 150 ScanImage(scanner_name, platform_file, properties, | |
| 151 base::Bind(&DocumentScanInterfaceImpl::OnScanCompleted, | |
| 152 base::Unretained(this), | |
| 153 callback)); | |
| 154 } | |
| 155 | |
| 156 void DocumentScanInterfaceImpl::OnScanCompleted( | |
| 157 const ScanResultsCallback &callback, bool succeeded) { | |
| 158 VLOG(1) << "ScanImage returns " << succeeded; | |
| 159 if (pipe_reader_.get()) { | |
| 160 pipe_reader_->OnDataReady(-1); // terminate data stream | |
| 161 } | |
| 162 | |
| 163 string error_string; | |
| 164 if (!succeeded) { | |
| 165 error_string = kImageScanFailedError; | |
| 166 } | |
| 167 | |
| 168 vector<string> scanned_image_data_array; | |
| 169 scanned_image_data_array.push_back(GetImageURL(scanned_image_data_)); | |
| 170 callback.Run( | |
| 171 document_scan::Scan::Results::Create( | |
| 172 scanned_image_data_array, kScannerImageMimeTypePng), error_string); | |
| 173 } | |
| 174 | |
| 175 string DocumentScanInterfaceImpl::GetImageURL(string image_data) { | |
| 176 string image_data_base64; | |
| 177 base::Base64Encode(image_data, &image_data_base64); | |
| 178 return string(kPngImageDataUrlPrefix) + image_data_base64; | |
| 179 } | |
| 180 | |
| 181 void DocumentScanInterfaceImpl::OnScanDataCompleted() { | |
| 182 pipe_reader_->GetData(&scanned_image_data_); | |
| 183 pipe_reader_.reset(); | |
| 184 } | |
| 185 | |
| 186 #else // OS_CHROMEOS | |
| 187 class DocumentScanInterfaceImpl : public DocumentScanInterface { | |
|
mef
2014/10/13 15:59:54
If this is not implemented and not intended for im
Paul Stewart
2014/10/14 19:28:31
The intent is to make it possible to implement thi
| |
| 188 public: | |
| 189 DocumentScanInterfaceImpl() {} | |
| 190 virtual ~DocumentScanInterfaceImpl() {} | |
| 191 | |
| 192 virtual void ListScanners( | |
| 193 const ListScannersResultsCallback& callback) OVERRIDE { | |
| 194 callback.Run(vector<ScannerDescription> (), ""); | |
| 195 } | |
| 196 virtual void Scan(const string& scanner_name, | |
| 197 ScanMode mode, | |
| 198 int resolution_dpi, | |
| 199 const ScanResultsCallback& callback) OVERRIDE { | |
| 200 vector<string> null_scan_results; | |
| 201 callback.Run(document_scan::Scan::Results::Create(null_scan_results, ""), | |
| 202 kScanFunctionNotImplementedError); | |
| 203 } | |
| 204 | |
| 205 private: | |
| 206 DISALLOW_COPY_AND_ASSIGN(DocumentScanInterfaceImpl); | |
| 207 }; | |
| 208 #endif // OS_CHROMEOS | |
| 209 | |
| 210 DocumentScanScanFunction::DocumentScanScanFunction() | |
| 211 : document_scan_interface_(new DocumentScanInterfaceImpl()) {} | |
| 212 | |
| 213 DocumentScanScanFunction::~DocumentScanScanFunction() {} | |
| 214 | |
| 215 bool DocumentScanScanFunction::Prepare() { | |
| 216 set_work_thread_id(BrowserThread::FILE); | |
| 217 params_ = document_scan::Scan::Params::Create(*args_); | |
| 218 EXTENSION_FUNCTION_VALIDATE(params_.get()); | |
| 219 return true; | |
| 220 } | |
| 221 | |
| 222 void DocumentScanScanFunction::AsyncWorkStart() { | |
| 223 if (!user_gesture()) { | |
| 224 error_ = kUserGestureRequiredError; | |
| 225 AsyncWorkCompleted(); | |
| 226 return; | |
| 227 } | |
| 228 | |
| 229 // Add a reference, which is balanced in OnScannerListReceived to keep the | |
| 230 // object around and allow the callback to be invoked. | |
| 231 AddRef(); | |
| 232 | |
| 233 document_scan_interface_->ListScanners( | |
| 234 base::Bind(&DocumentScanScanFunction::OnScannerListReceived, | |
| 235 base::Unretained(this))); | |
| 236 } | |
| 237 | |
| 238 void DocumentScanScanFunction::OnScannerListReceived( | |
| 239 const vector<DocumentScanInterface::ScannerDescription>& | |
| 240 scanner_descriptions, | |
| 241 const string& error) { | |
| 242 vector<DocumentScanInterface::ScannerDescription>::const_iterator | |
| 243 scanner_i = scanner_descriptions.begin(); | |
| 244 if (params_->options.accepted_mime_types) { | |
| 245 vector<string>& accepted_types = | |
| 246 *params_->options.accepted_mime_types.get(); | |
| 247 for (; scanner_i != scanner_descriptions.end(); ++scanner_i) { | |
| 248 if (std::find(accepted_types.begin(), accepted_types.end(), | |
| 249 scanner_i->image_mime_type) != accepted_types.end()) { | |
| 250 break; | |
| 251 } | |
| 252 } | |
| 253 } | |
| 254 | |
| 255 if (scanner_i == scanner_descriptions.end()) { | |
| 256 vector<string> null_scan_results; | |
| 257 results_ = document_scan::Scan::Results::Create(null_scan_results, ""); | |
| 258 error_ = kScannerNotAvailable; | |
| 259 AsyncWorkCompleted(); | |
| 260 | |
| 261 // Balance the AddRef in AsyncWorkStart(). | |
| 262 Release(); | |
| 263 return; | |
| 264 } | |
| 265 | |
| 266 // TODO(pstew): Display a user interface for choosing a scanner. | |
| 267 // This is where the scan mode, DPI, etc, would be specified. | |
| 268 | |
| 269 document_scan_interface_->Scan( | |
| 270 scanner_i->name, | |
| 271 DocumentScanInterface::kScanModeColor, | |
| 272 0, | |
| 273 base::Bind(&DocumentScanScanFunction::OnResultsReceived, | |
| 274 base::Unretained(this))); | |
| 275 } | |
| 276 | |
| 277 void DocumentScanScanFunction::OnResultsReceived( | |
| 278 scoped_ptr<base::ListValue> results, const string& error) { | |
| 279 // TODO(pstew): Display receied scan in the UI and confirm that this | |
| 280 // scan should be sent to the caller. If this is a multi-page scan, | |
| 281 // provide a means for adding additional scanned images up to the | |
| 282 // requested limit. | |
| 283 results_ = results.Pass(); | |
| 284 error_ = error; | |
| 285 AsyncWorkCompleted(); | |
| 286 | |
| 287 // Balance the AddRef in AsyncWorkStart(). | |
| 288 Release(); | |
| 289 } | |
| 290 | |
| 291 bool DocumentScanScanFunction::Respond() { | |
| 292 return error_.empty(); | |
| 293 } | |
| 294 | |
| 295 } // namespace api | |
| 296 | |
| 297 } // namespace extensions | |
| OLD | NEW |