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 "chrome/browser/extensions/image_utils.h" | |
6 | |
7 #include "base/callback.h" | |
8 #include "base/file_util.h" | |
9 #include "base/threading/sequenced_worker_pool.h" | |
10 #include "chrome/common/chrome_notification_types.h" | |
11 #include "chrome/common/extensions/extension.h" | |
12 #include "content/public/browser/browser_thread.h" | |
13 #include "content/public/browser/notification_observer.h" | |
14 #include "content/public/browser/notification_registrar.h" | |
15 #include "content/public/browser/notification_service.h" | |
16 #include "grit/component_extension_resources_map.h" | |
17 #include "skia/ext/image_operations.h" | |
18 #include "third_party/skia/include/core/SkBitmap.h" | |
19 #include "ui/base/resource/resource_bundle.h" | |
20 #include "ui/gfx/image/image.h" | |
21 #include "ui/gfx/image/image_skia.h" | |
22 #include "webkit/glue/image_decoder.h" | |
23 | |
24 using content::BrowserThread; | |
25 using extension_image_utils::ImageRepresentation; | |
26 using extensions::Extension; | |
27 | |
28 namespace { | |
29 | |
30 // TODO: adapt to my refactoring | |
31 bool IsComponentExtensionResource( | |
Finnur
2012/10/05 14:41:33
This is copied from the ImageLoadingTracker. Did y
Marijn Kruisselbrink
2012/10/05 18:00:08
I'm using the git workflow, so no svn copy; I coul
| |
32 Extension::Location extension_location, | |
33 const ExtensionResource& resource, | |
34 int& resource_id) { | |
Finnur
2012/10/05 14:41:33
You should use int* resource_id, not int&.
Marijn Kruisselbrink
2012/10/05 18:00:08
Ah yes, I fixed that in ILT in another CL but appa
| |
35 if (extension_location != Extension::COMPONENT) | |
36 return false; | |
37 | |
38 FilePath directory_path = resource.extension_root(); | |
39 FilePath relative_path = directory_path.BaseName().Append( | |
40 resource.relative_path()); | |
41 | |
42 for (size_t i = 0; i < kComponentExtensionResourcesSize; ++i) { | |
43 FilePath resource_path = | |
44 FilePath().AppendASCII(kComponentExtensionResources[i].name); | |
45 resource_path = resource_path.NormalizePathSeparators(); | |
46 | |
47 if (relative_path == resource_path) { | |
48 resource_id = kComponentExtensionResources[i].value; | |
49 return true; | |
50 } | |
51 } | |
52 return false; | |
53 } | |
54 | |
55 bool ShouldResizeImageRepresentation( | |
56 ImageRepresentation::ResizeCondition resize_method, | |
57 const gfx::Size& decoded_size, | |
58 const gfx::Size& desired_size) { | |
59 switch (resize_method) { | |
60 case ImageRepresentation::ALWAYS_RESIZE: | |
61 return decoded_size != desired_size; | |
62 case ImageRepresentation::RESIZE_WHEN_LARGER: | |
63 return decoded_size.width() > desired_size.width() || | |
64 decoded_size.height() > desired_size.height(); | |
65 default: | |
66 NOTREACHED(); | |
67 return false; | |
68 } | |
69 } | |
70 | |
71 SkBitmap ResizeIfNeeded(const SkBitmap& bitmap, | |
72 const ImageRepresentation& image_info) { | |
73 gfx::Size original_size(bitmap.width(), bitmap.height()); | |
74 if (ShouldResizeImageRepresentation(image_info.resize_condition, | |
75 original_size, | |
76 image_info.desired_size)) { | |
77 return skia::ImageOperations::Resize( | |
78 bitmap, skia::ImageOperations::RESIZE_LANCZOS3, | |
79 image_info.desired_size.width(), image_info.desired_size.height()); | |
80 } | |
81 | |
82 return bitmap; | |
83 } | |
84 | |
85 void LoadResourceOnBlockingPool(int resource_id, | |
86 SkBitmap* bitmap) { | |
87 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
88 | |
89 gfx::ImageSkia image( | |
90 *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id)); | |
91 image.MakeThreadSafe(); | |
92 *bitmap = *image.bitmap(); | |
93 } | |
94 | |
95 void LoadImageOnBlockingPool(const ImageRepresentation& image_info, | |
96 SkBitmap* bitmap) { | |
97 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
98 | |
99 // Read the file from disk. | |
100 std::string file_contents; | |
101 FilePath path = image_info.resource.GetFilePath(); | |
102 if (path.empty() || !file_util::ReadFileToString(path, &file_contents)) { | |
103 return; | |
104 } | |
105 | |
106 // Decode the bitmap using WebKit's image decoder. | |
107 const unsigned char* data = | |
108 reinterpret_cast<const unsigned char*>(file_contents.data()); | |
109 webkit_glue::ImageDecoder decoder; | |
110 // Note: This class only decodes bitmaps from extension resources. Chrome | |
111 // doesn't (for security reasons) directly load extension resources provided | |
112 // by the extension author, but instead decodes them in a separate | |
113 // locked-down utility process. Only if the decoding succeeds is the image | |
114 // saved from memory to disk and subsequently used in the Chrome UI. | |
115 // Chrome is therefore decoding bitmaps here that were generated by Chrome. | |
116 *bitmap = decoder.Decode(data, file_contents.length()); | |
117 } | |
118 | |
119 void LoadImagesOnBlockingPool( | |
120 const std::vector<ImageRepresentation>& info_list, | |
121 Extension::Location extension_location, | |
122 const base::Callback<void(const gfx::Image&)>& callback, | |
123 BrowserThread::ID thread_id) { | |
124 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
125 | |
126 gfx::ImageSkia image_skia; | |
127 | |
128 for (std::vector<ImageRepresentation>::const_iterator it = info_list.begin(); | |
129 it != info_list.end(); ++it) { | |
130 // If we don't have a path there isn't anything we can do, just skip it. | |
131 if (it->resource.relative_path().empty()) | |
132 continue; | |
Finnur
2012/10/05 14:41:33
We used to let the caller know when we were done,
Marijn Kruisselbrink
2012/10/05 18:00:08
ILT only internally needed to send itself a null b
| |
133 | |
134 int resource_id; | |
135 SkBitmap bitmap; | |
136 if (IsComponentExtensionResource(extension_location, it->resource, | |
137 resource_id)) | |
138 LoadResourceOnBlockingPool(resource_id, &bitmap); | |
139 else | |
140 LoadImageOnBlockingPool(*it, &bitmap); | |
141 | |
142 // If the image failed to load, skip it. | |
143 if (bitmap.isNull() || bitmap.empty()) | |
144 continue; | |
145 | |
146 bitmap = ResizeIfNeeded(bitmap, *it); | |
147 | |
148 image_skia.AddRepresentation(gfx::ImageSkiaRep(bitmap, it->scale_factor)); | |
149 } | |
150 | |
151 gfx::Image image; | |
152 | |
153 if (!image_skia.isNull()) { | |
154 image_skia.MakeThreadSafe(); | |
155 image = gfx::Image(image_skia); | |
156 } | |
157 | |
158 BrowserThread::PostTask(thread_id, FROM_HERE, base::Bind(callback, image)); | |
159 } | |
160 | |
161 } // namespace | |
162 | |
163 namespace extension_image_utils { | |
164 | |
165 ImageRepresentation::ImageRepresentation( | |
166 const ExtensionResource& resource, | |
167 ResizeCondition resize_condition, | |
168 const gfx::Size& desired_size, | |
169 ui::ScaleFactor scale_factor) | |
170 : resource(resource), | |
171 resize_condition(resize_condition), | |
172 desired_size(desired_size), | |
173 scale_factor(scale_factor) { | |
174 } | |
175 | |
176 ImageRepresentation::~ImageRepresentation() { | |
177 } | |
178 | |
179 void LoadImageAsync(const Extension* extension, | |
180 const ExtensionResource& resource, | |
181 const gfx::Size& max_size, | |
182 const base::Callback<void(const gfx::Image&)>& callback) { | |
183 std::vector<ImageRepresentation> info_list; | |
184 info_list.push_back(ImageRepresentation( | |
185 resource, | |
186 ImageRepresentation::RESIZE_WHEN_LARGER, | |
187 max_size, | |
188 ui::SCALE_FACTOR_100P)); | |
189 LoadImagesAsync(extension, info_list, callback); | |
190 } | |
191 | |
192 void LoadImagesAsync(const Extension* extension, | |
193 const std::vector<ImageRepresentation>& info_list, | |
194 const base::Callback<void(const gfx::Image&)>& callback) { | |
195 for (std::vector<ImageRepresentation>::const_iterator it = info_list.begin(); | |
196 it != info_list.end(); ++it) { | |
197 DCHECK(it->resource.relative_path().empty() || | |
198 extension->path() == it->resource.extension_root()); | |
199 } | |
200 | |
201 BrowserThread::ID thread_id; | |
202 CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_id)); | |
203 DCHECK(!BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); | |
204 BrowserThread::PostBlockingPoolTask( | |
205 FROM_HERE, | |
206 base::Bind(&LoadImagesOnBlockingPool, info_list, | |
207 extension->location(), callback, thread_id)); | |
208 } | |
209 | |
210 } // namespace extension_image_utils | |
OLD | NEW |