[chromedriver] Make GetElementLocationInView return the top-left coordinate rather...
[chromium-blink-merge.git] / chrome / utility / chrome_content_utility_client.cc
blob25a744455b2a2a8978f1b0dc63202c2b09140588
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.
5 #include "chrome/utility/chrome_content_utility_client.h"
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/json/json_reader.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/time/time.h"
12 #include "chrome/common/chrome_utility_messages.h"
13 #include "chrome/common/safe_browsing/zip_analyzer.h"
14 #include "chrome/utility/chrome_content_utility_ipc_whitelist.h"
15 #include "chrome/utility/utility_message_handler.h"
16 #include "content/public/child/image_decoder_utils.h"
17 #include "content/public/common/content_switches.h"
18 #include "content/public/utility/utility_thread.h"
19 #include "courgette/courgette.h"
20 #include "courgette/third_party/bsdiff.h"
21 #include "ipc/ipc_channel.h"
22 #include "skia/ext/image_operations.h"
23 #include "third_party/skia/include/core/SkBitmap.h"
24 #include "third_party/zlib/google/zip.h"
25 #include "ui/gfx/codec/jpeg_codec.h"
26 #include "ui/gfx/geometry/size.h"
28 #if !defined(OS_ANDROID)
29 #include "chrome/utility/profile_import_handler.h"
30 #endif
32 #if defined(OS_WIN)
33 #include "chrome/utility/font_cache_handler_win.h"
34 #include "chrome/utility/shell_handler_win.h"
35 #endif
37 #if defined(ENABLE_EXTENSIONS)
38 #include "chrome/common/extensions/chrome_utility_extensions_messages.h"
39 #include "chrome/utility/extensions/extensions_handler.h"
40 #include "chrome/utility/image_writer/image_writer_handler.h"
41 #include "chrome/utility/media_galleries/ipc_data_source.h"
42 #include "chrome/utility/media_galleries/media_metadata_parser.h"
43 #endif
45 #if defined(ENABLE_PRINT_PREVIEW) || defined(OS_WIN)
46 #include "chrome/utility/printing_handler.h"
47 #endif
49 #if defined(ENABLE_MDNS)
50 #include "chrome/utility/local_discovery/service_discovery_message_handler.h"
51 #endif
53 namespace {
55 bool Send(IPC::Message* message) {
56 return content::UtilityThread::Get()->Send(message);
59 void ReleaseProcessIfNeeded() {
60 content::UtilityThread::Get()->ReleaseProcessIfNeeded();
63 #if defined(ENABLE_EXTENSIONS)
64 void FinishParseMediaMetadata(
65 metadata::MediaMetadataParser* /* parser */,
66 const extensions::api::media_galleries::MediaMetadata& metadata,
67 const std::vector<metadata::AttachedImage>& attached_images) {
68 Send(new ChromeUtilityHostMsg_ParseMediaMetadata_Finished(
69 true, *metadata.ToValue(), attached_images));
70 ReleaseProcessIfNeeded();
72 #endif
74 } // namespace
76 int64_t ChromeContentUtilityClient::max_ipc_message_size_ =
77 IPC::Channel::kMaximumMessageSize;
79 ChromeContentUtilityClient::ChromeContentUtilityClient()
80 : filter_messages_(false) {
81 #if !defined(OS_ANDROID)
82 handlers_.push_back(new ProfileImportHandler());
83 #endif
85 #if defined(ENABLE_EXTENSIONS)
86 handlers_.push_back(new extensions::ExtensionsHandler());
87 handlers_.push_back(new image_writer::ImageWriterHandler());
88 #endif
90 #if defined(ENABLE_PRINT_PREVIEW) || defined(OS_WIN)
91 handlers_.push_back(new PrintingHandler());
92 #endif
94 #if defined(ENABLE_MDNS)
95 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
96 switches::kUtilityProcessEnableMDns)) {
97 handlers_.push_back(new local_discovery::ServiceDiscoveryMessageHandler());
99 #endif
101 #if defined(OS_WIN)
102 handlers_.push_back(new ShellHandler());
103 handlers_.push_back(new FontCacheHandler());
104 #endif
107 ChromeContentUtilityClient::~ChromeContentUtilityClient() {
110 void ChromeContentUtilityClient::UtilityThreadStarted() {
111 #if defined(ENABLE_EXTENSIONS)
112 extensions::ExtensionsHandler::UtilityThreadStarted();
113 #endif
115 if (kMessageWhitelistSize > 0) {
116 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
117 if (command_line->HasSwitch(switches::kUtilityProcessRunningElevated)) {
118 message_id_whitelist_.insert(kMessageWhitelist,
119 kMessageWhitelist + kMessageWhitelistSize);
120 filter_messages_ = true;
125 bool ChromeContentUtilityClient::OnMessageReceived(
126 const IPC::Message& message) {
127 if (filter_messages_ && !ContainsKey(message_id_whitelist_, message.type()))
128 return false;
130 bool handled = true;
131 IPC_BEGIN_MESSAGE_MAP(ChromeContentUtilityClient, message)
132 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DecodeImage, OnDecodeImage)
133 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RobustJPEGDecodeImage,
134 OnRobustJPEGDecodeImage)
135 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseJSON, OnParseJSON)
136 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileBsdiff,
137 OnPatchFileBsdiff)
138 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_PatchFileCourgette,
139 OnPatchFileCourgette)
140 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_StartupPing, OnStartupPing)
141 #if defined(FULL_SAFE_BROWSING)
142 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_AnalyzeZipFileForDownloadProtection,
143 OnAnalyzeZipFileForDownloadProtection)
144 #endif
145 #if defined(ENABLE_EXTENSIONS)
146 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_ParseMediaMetadata,
147 OnParseMediaMetadata)
148 #endif
149 #if defined(OS_CHROMEOS)
150 IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CreateZipFile, OnCreateZipFile)
151 #endif
152 IPC_MESSAGE_UNHANDLED(handled = false)
153 IPC_END_MESSAGE_MAP()
155 for (Handlers::iterator it = handlers_.begin();
156 !handled && it != handlers_.end(); ++it) {
157 handled = (*it)->OnMessageReceived(message);
160 return handled;
163 // static
164 void ChromeContentUtilityClient::PreSandboxStartup() {
165 #if defined(ENABLE_EXTENSIONS)
166 extensions::ExtensionsHandler::PreSandboxStartup();
167 #endif
169 #if defined(ENABLE_PRINT_PREVIEW) || defined(OS_WIN)
170 PrintingHandler::PreSandboxStartup();
171 #endif
173 #if defined(ENABLE_MDNS)
174 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
175 switches::kUtilityProcessEnableMDns)) {
176 local_discovery::ServiceDiscoveryMessageHandler::PreSandboxStartup();
178 #endif // ENABLE_MDNS
181 // static
182 SkBitmap ChromeContentUtilityClient::DecodeImage(
183 const std::vector<unsigned char>& encoded_data, bool shrink_to_fit) {
184 SkBitmap decoded_image = content::DecodeImage(&encoded_data[0],
185 gfx::Size(),
186 encoded_data.size());
188 int64_t struct_size = sizeof(ChromeUtilityHostMsg_DecodeImage_Succeeded);
189 int64_t image_size = decoded_image.computeSize64();
190 int halves = 0;
191 while (struct_size + (image_size >> 2*halves) > max_ipc_message_size_)
192 halves++;
193 if (halves) {
194 if (shrink_to_fit) {
195 // If decoded image is too large for IPC message, shrink it by halves.
196 // This prevents quality loss, and should never overshrink on displays
197 // smaller than 3600x2400.
198 // TODO (Issue 416916): Instead of shrinking, return via shared memory
199 decoded_image = skia::ImageOperations::Resize(
200 decoded_image, skia::ImageOperations::RESIZE_LANCZOS3,
201 decoded_image.width() >> halves, decoded_image.height() >> halves);
202 } else {
203 // Image too big for IPC message, but caller didn't request resize;
204 // pre-delete image so DecodeImageAndSend() will send an error.
205 decoded_image.reset();
206 LOG(ERROR) << "Decoded image too large for IPC message";
210 return decoded_image;
213 // static
214 void ChromeContentUtilityClient::DecodeImageAndSend(
215 const std::vector<unsigned char>& encoded_data, bool shrink_to_fit){
216 SkBitmap decoded_image = DecodeImage(encoded_data, shrink_to_fit);
218 if (decoded_image.empty()) {
219 Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
220 } else {
221 Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(decoded_image));
223 ReleaseProcessIfNeeded();
226 void ChromeContentUtilityClient::OnDecodeImage(
227 const std::vector<unsigned char>& encoded_data, bool shrink_to_fit) {
228 DecodeImageAndSend(encoded_data, shrink_to_fit);
231 #if defined(OS_CHROMEOS)
232 void ChromeContentUtilityClient::OnCreateZipFile(
233 const base::FilePath& src_dir,
234 const std::vector<base::FilePath>& src_relative_paths,
235 const base::FileDescriptor& dest_fd) {
236 // dest_fd should be closed in the function. See ipc/ipc_message_util.h for
237 // details.
238 base::ScopedFD fd_closer(dest_fd.fd);
239 bool succeeded = true;
241 // Check sanity of source relative paths. Reject if path is absolute or
242 // contains any attempt to reference a parent directory ("../" tricks).
243 for (std::vector<base::FilePath>::const_iterator iter =
244 src_relative_paths.begin(); iter != src_relative_paths.end();
245 ++iter) {
246 if (iter->IsAbsolute() || iter->ReferencesParent()) {
247 succeeded = false;
248 break;
252 if (succeeded)
253 succeeded = zip::ZipFiles(src_dir, src_relative_paths, dest_fd.fd);
255 if (succeeded)
256 Send(new ChromeUtilityHostMsg_CreateZipFile_Succeeded());
257 else
258 Send(new ChromeUtilityHostMsg_CreateZipFile_Failed());
259 ReleaseProcessIfNeeded();
261 #endif // defined(OS_CHROMEOS)
263 void ChromeContentUtilityClient::OnRobustJPEGDecodeImage(
264 const std::vector<unsigned char>& encoded_data) {
265 // Our robust jpeg decoding is using IJG libjpeg.
266 if (gfx::JPEGCodec::JpegLibraryVariant() == gfx::JPEGCodec::IJG_LIBJPEG &&
267 !encoded_data.empty()) {
268 scoped_ptr<SkBitmap> decoded_image(gfx::JPEGCodec::Decode(
269 &encoded_data[0], encoded_data.size()));
270 if (!decoded_image.get() || decoded_image->empty()) {
271 Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
272 } else {
273 Send(new ChromeUtilityHostMsg_DecodeImage_Succeeded(*decoded_image));
275 } else {
276 Send(new ChromeUtilityHostMsg_DecodeImage_Failed());
278 ReleaseProcessIfNeeded();
281 void ChromeContentUtilityClient::OnParseJSON(const std::string& json) {
282 int error_code;
283 std::string error;
284 base::Value* value = base::JSONReader::ReadAndReturnError(
285 json, base::JSON_PARSE_RFC, &error_code, &error);
286 if (value) {
287 base::ListValue wrapper;
288 wrapper.Append(value);
289 Send(new ChromeUtilityHostMsg_ParseJSON_Succeeded(wrapper));
290 } else {
291 Send(new ChromeUtilityHostMsg_ParseJSON_Failed(error));
293 ReleaseProcessIfNeeded();
296 void ChromeContentUtilityClient::OnPatchFileBsdiff(
297 const base::FilePath& input_file,
298 const base::FilePath& patch_file,
299 const base::FilePath& output_file) {
300 if (input_file.empty() || patch_file.empty() || output_file.empty()) {
301 Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1));
302 } else {
303 const int patch_status = courgette::ApplyBinaryPatch(input_file,
304 patch_file,
305 output_file);
306 Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
308 ReleaseProcessIfNeeded();
311 void ChromeContentUtilityClient::OnPatchFileCourgette(
312 const base::FilePath& input_file,
313 const base::FilePath& patch_file,
314 const base::FilePath& output_file) {
315 if (input_file.empty() || patch_file.empty() || output_file.empty()) {
316 Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1));
317 } else {
318 const int patch_status = courgette::ApplyEnsemblePatch(
319 input_file.value().c_str(),
320 patch_file.value().c_str(),
321 output_file.value().c_str());
322 Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
324 ReleaseProcessIfNeeded();
327 void ChromeContentUtilityClient::OnStartupPing() {
328 Send(new ChromeUtilityHostMsg_ProcessStarted);
329 // Don't release the process, we assume further messages are on the way.
332 #if defined(FULL_SAFE_BROWSING)
333 void ChromeContentUtilityClient::OnAnalyzeZipFileForDownloadProtection(
334 const IPC::PlatformFileForTransit& zip_file) {
335 safe_browsing::zip_analyzer::Results results;
336 safe_browsing::zip_analyzer::AnalyzeZipFile(
337 IPC::PlatformFileForTransitToFile(zip_file), &results);
338 Send(new ChromeUtilityHostMsg_AnalyzeZipFileForDownloadProtection_Finished(
339 results));
340 ReleaseProcessIfNeeded();
342 #endif
344 #if defined(ENABLE_EXTENSIONS)
345 // TODO(thestig): Try to move this to
346 // chrome/utility/extensions/extensions_handler.cc.
347 void ChromeContentUtilityClient::OnParseMediaMetadata(
348 const std::string& mime_type, int64 total_size, bool get_attached_images) {
349 // Only one IPCDataSource may be created and added to the list of handlers.
350 metadata::IPCDataSource* source = new metadata::IPCDataSource(total_size);
351 handlers_.push_back(source);
353 metadata::MediaMetadataParser* parser = new metadata::MediaMetadataParser(
354 source, mime_type, get_attached_images);
355 parser->Start(base::Bind(&FinishParseMediaMetadata, base::Owned(parser)));
357 #endif