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/android/thumbnail/thumbnail_impl.h" | |
6 | |
7 #include "base/files/file.h" | |
8 #include "base/files/file_path.h" | |
9 #include "cc/resources/ui_resource_bitmap.h" | |
10 #include "chrome/browser/android/thumbnail/thumbnail_cache.h" | |
11 #include "third_party/android_opengl/etc1/etc1.h" | |
12 #include "third_party/skia/include/core/SkBitmap.h" | |
13 #include "third_party/skia/include/core/SkCanvas.h" | |
14 #include "third_party/skia/include/core/SkData.h" | |
15 #include "third_party/skia/include/core/SkMallocPixelRef.h" | |
16 #include "third_party/skia/include/core/SkPixelRef.h" | |
17 #include "ui/gfx/geometry/size_conversions.h" | |
18 | |
19 namespace { | |
20 | |
21 const int kCompressedKey = 0xABABABAB; | |
22 const int kDecompressedKey = 0xCDCDCDCD; | |
23 | |
24 // ETC1 texture sizes are multiples of four. | |
25 size_t NextETC1Size(size_t s) { | |
26 return (s / 4 + (s % 4 ? 1 : 0)) * 4; | |
27 } | |
28 | |
29 gfx::Size GetEncodedSize(gfx::Size bitmap_size) { | |
David Trainor- moved to gerrit
2014/06/17 08:12:11
const gfx::Size&
powei
2014/06/19 23:05:59
Done.
| |
30 return gfx::Size(NextETC1Size(bitmap_size.width()), | |
31 NextETC1Size(bitmap_size.height())); | |
32 } | |
33 | |
34 } // namespace | |
35 | |
36 ThumbnailImpl::ThumbnailImpl(TabId tab_id, | |
37 const SkBitmap& bitmap, | |
38 float scale, | |
39 ThumbnailImplManager* thumbnail_impl_manager, | |
40 content::UIResourceProvider* ui_resource_provider) | |
41 : tab_id_(tab_id), | |
42 ui_resource_id_(0), | |
43 thumbnail_impl_manager_(thumbnail_impl_manager), | |
44 ui_resource_provider_(ui_resource_provider) { | |
45 DCHECK(ui_resource_provider); | |
46 SetRawData(bitmap, scale); | |
47 } | |
48 | |
49 ThumbnailImpl::~ThumbnailImpl() { | |
50 CleanupUIResource(); | |
51 } | |
52 | |
53 void ThumbnailImpl::CleanupUIResource() { | |
54 DCHECK(ui_resource_provider_); | |
55 if (ui_resource_id_) | |
56 ui_resource_provider_->DeleteUIResource(ui_resource_id_); | |
57 ui_resource_id_ = 0; | |
58 } | |
59 | |
60 void ThumbnailImpl::BuildUIResource() { | |
61 CleanupUIResource(); | |
62 if (raw_data_.empty() && !compressed_data_) | |
63 return; | |
64 ui_resource_id_ = ui_resource_provider_->CreateUIResource(this); | |
65 } | |
66 | |
67 bool ThumbnailImpl::IsValid() const { | |
68 return ui_resource_provider_ && scale_ > 0 && !data_size_.IsEmpty() && | |
69 !content_size_.IsEmpty(); | |
70 } | |
71 | |
72 gfx::Size ThumbnailImpl::GetScaledContentSize() const { | |
73 return gfx::ToRoundedSize(gfx::ScaleSize(content_size_, 1.f / scale_)); | |
74 } | |
75 | |
76 gfx::SizeF ThumbnailImpl::GetScaledDataSize() const { | |
77 return gfx::ScaleSize(data_size_, 1.f / scale_); | |
78 } | |
79 | |
80 void ThumbnailImpl::Compress(scoped_refptr<ThumbnailImpl> in_thumbnail, | |
David Trainor- moved to gerrit
2014/06/17 08:12:11
I reviewed this before the actual cache, but why h
powei
2014/06/19 23:05:59
This is just to make this method be more functiona
David Trainor- moved to gerrit
2014/06/25 07:40:16
Could it still act on the same class that's passed
| |
81 scoped_refptr<ThumbnailImpl> out_thumbnail) { | |
82 SkBitmap raw_data = in_thumbnail->raw_data_; | |
83 if (raw_data.empty()) | |
84 return; | |
85 | |
86 SkAutoLockPixels raw_data_lock(raw_data); | |
87 gfx::Size raw_data_size(raw_data.width(), raw_data.height()); | |
88 DCHECK_EQ(raw_data.config(), SkBitmap::kARGB_8888_Config); | |
89 size_t pixel_size = 4; // Pixel size is 4 bytes for kARGB_8888_Config. | |
90 size_t stride = pixel_size * raw_data_size.width(); | |
91 | |
92 gfx::Size encoded_size = GetEncodedSize(raw_data_size); | |
93 size_t encoded_bytes = | |
94 etc1_get_encoded_data_size(encoded_size.width(), encoded_size.height()); | |
95 SkImageInfo info = {encoded_size.width(), | |
96 encoded_size.height(), | |
97 kUnknown_SkColorType, | |
98 kUnpremul_SkAlphaType}; | |
99 skia::RefPtr<SkData> etc1_pixel_data = skia::AdoptRef( | |
100 SkData::NewFromMalloc(new uint8_t[encoded_bytes], encoded_bytes)); | |
101 skia::RefPtr<SkMallocPixelRef> etc1_pixel_ref = skia::AdoptRef( | |
102 SkMallocPixelRef::NewWithData(info, 0, NULL, etc1_pixel_data.get())); | |
103 | |
104 etc1_pixel_ref->lockPixels(); | |
105 bool success = etc1_encode_image( | |
106 reinterpret_cast<unsigned char*>(raw_data.getPixels()), | |
107 raw_data_size.width(), | |
108 raw_data_size.height(), | |
109 pixel_size, | |
110 stride, | |
111 reinterpret_cast<unsigned char*>(etc1_pixel_ref->pixels()), | |
112 encoded_size.width(), | |
113 encoded_size.height()); | |
114 etc1_pixel_ref->setImmutable(); | |
115 etc1_pixel_ref->unlockPixels(); | |
116 if (success) { | |
117 out_thumbnail->SetCompressedData( | |
118 etc1_pixel_ref, in_thumbnail->scale_, raw_data_size); | |
119 } | |
120 } | |
121 | |
122 bool ThumbnailImpl::WriteToFile(scoped_refptr<ThumbnailImpl> thumbnail, | |
123 base::File& file) { | |
124 // We assume caller has already initialized the file and will also close it. | |
125 DCHECK(file.IsValid()); | |
126 DCHECK(thumbnail); | |
127 DCHECK(thumbnail->compressed_data_); | |
128 | |
129 thumbnail->compressed_data_->lockPixels(); | |
130 bool success = true; | |
131 int content_width = thumbnail->content_size_.width(); | |
132 int content_height = thumbnail->content_size_.height(); | |
133 int data_width = thumbnail->data_size_.width(); | |
134 int data_height = thumbnail->data_size_.height(); | |
135 | |
136 if (file.WriteAtCurrentPos(reinterpret_cast<const char*>(&kCompressedKey), | |
137 sizeof(int)) < 0 || | |
138 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&content_width), | |
139 sizeof(int)) < 0 || | |
140 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&content_height), | |
141 sizeof(int)) < 0 || | |
142 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&data_width), | |
143 sizeof(int)) < 0 || | |
144 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&data_height), | |
145 sizeof(int)) < 0 || | |
146 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&thumbnail->scale_), | |
147 sizeof(float)) < 0) { | |
148 success = false; | |
149 } | |
150 | |
151 size_t compressed_bytes = etc1_get_encoded_data_size( | |
152 thumbnail->data_size_.width(), thumbnail->data_size_.height()); | |
153 | |
154 if (file.WriteAtCurrentPos( | |
155 reinterpret_cast<char*>(thumbnail->compressed_data_->pixels()), | |
156 compressed_bytes) < 0) | |
157 success = false; | |
158 | |
159 thumbnail->compressed_data_->unlockPixels(); | |
160 return success; | |
161 } | |
162 | |
163 bool ThumbnailImpl::ReadFromFile(base::File& file, | |
164 scoped_refptr<ThumbnailImpl> thumbnail) { | |
165 // We assume caller has already initialized the file and will also close it. | |
166 DCHECK(file.IsValid()); | |
167 | |
168 int key; | |
169 bool success = true; | |
170 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&key), sizeof(int)) < 0 || | |
171 key != kCompressedKey) | |
172 success = false; | |
173 | |
174 int width, height; | |
175 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&width), sizeof(int)) < 0 || | |
176 file.ReadAtCurrentPos(reinterpret_cast<char*>(&height), sizeof(int)) < 0) | |
177 success = false; | |
178 gfx::Size content_size = gfx::Size(width, height); | |
David Trainor- moved to gerrit
2014/06/17 08:12:11
gfx::Size content_size(width, height);
Same for b
powei
2014/06/19 23:05:59
Done.
| |
179 | |
180 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&width), sizeof(int)) < 0 || | |
181 file.ReadAtCurrentPos(reinterpret_cast<char*>(&height), sizeof(int)) < 0) | |
182 success = false; | |
183 gfx::Size data_size = gfx::Size(width, height); | |
184 | |
185 float scale = 0.f; | |
186 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&scale), sizeof(float)) < 0) | |
187 success = false; | |
188 | |
189 size_t compressed_bytes = | |
190 etc1_get_encoded_data_size(data_size.width(), data_size.height()); | |
191 | |
192 SkImageInfo info = {data_size.width(), | |
193 data_size.height(), | |
194 kUnknown_SkColorType, | |
195 kUnpremul_SkAlphaType}; | |
196 | |
197 scoped_ptr<uint8_t[]> data(new uint8_t[compressed_bytes]); | |
198 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(data.get()), | |
199 compressed_bytes) < 0) | |
200 success = false; | |
201 | |
202 skia::RefPtr<SkData> etc1_pixel_data = | |
203 skia::AdoptRef(SkData::NewFromMalloc(data.release(), compressed_bytes)); | |
204 skia::RefPtr<SkPixelRef> compressed_data = skia::AdoptRef( | |
205 SkMallocPixelRef::NewWithData(info, 0, NULL, etc1_pixel_data.get())); | |
206 | |
207 if (success) | |
208 thumbnail->SetCompressedData(compressed_data, scale, content_size); | |
209 return success; | |
210 } | |
211 | |
212 scoped_refptr<ThumbnailImpl> ThumbnailImpl::PassDataToNewThumbnail() { | |
213 scoped_refptr<ThumbnailImpl> new_thumbnail = | |
214 make_scoped_refptr(new ThumbnailImpl(tab_id_, | |
215 SkBitmap(), | |
216 0.f, | |
217 thumbnail_impl_manager_, | |
218 ui_resource_provider_)); | |
219 new_thumbnail->raw_data_ = raw_data_; | |
220 new_thumbnail->compressed_data_ = compressed_data_; | |
221 new_thumbnail->scale_ = scale_; | |
222 new_thumbnail->data_size_ = data_size_; | |
223 new_thumbnail->content_size_ = content_size_; | |
224 | |
225 // Release this Thumbnail's reference to the data. | |
226 raw_data_ = SkBitmap(); | |
227 compressed_data_.clear(); | |
228 return new_thumbnail; | |
229 } | |
230 | |
231 cc::UIResourceBitmap ThumbnailImpl::GetBitmap(cc::UIResourceId uid, | |
232 bool resource_lost) { | |
233 if (!raw_data_.empty()) { | |
234 DCHECK(!compressed_data_); | |
235 return cc::UIResourceBitmap(raw_data_); | |
236 } else if (compressed_data_) { | |
237 DCHECK(raw_data_.empty()); | |
238 return cc::UIResourceBitmap(compressed_data_, data_size_); | |
239 } | |
240 | |
241 // Return a place holder for all other calls to GetBitmap. | |
242 SkBitmap tiny_bitmap; | |
243 SkCanvas canvas(tiny_bitmap); | |
244 tiny_bitmap.setConfig( | |
245 SkBitmap::kARGB_8888_Config, 1, 1, 0, kOpaque_SkAlphaType); | |
246 tiny_bitmap.allocPixels(); | |
247 canvas.drawColor(SK_ColorWHITE); | |
248 tiny_bitmap.setImmutable(); | |
249 return cc::UIResourceBitmap(tiny_bitmap); | |
250 } | |
251 | |
252 void ThumbnailImpl::UIResourceIsInvalid() { | |
253 ui_resource_id_ = 0; | |
254 if (thumbnail_impl_manager_) { | |
255 scoped_refptr<ThumbnailImpl> this_thumbnail(this); | |
256 thumbnail_impl_manager_->InvalidateCachedThumbnail(this_thumbnail); | |
257 } | |
258 } | |
259 | |
260 void ThumbnailImpl::SetCompressedData(skia::RefPtr<SkPixelRef> compressed_data, | |
261 float scale, | |
262 const gfx::Size& content_size) { | |
263 DCHECK(compressed_data); | |
264 compressed_data_ = compressed_data; | |
265 raw_data_ = SkBitmap(); | |
266 scale_ = scale; | |
267 content_size_ = content_size; | |
268 data_size_ = gfx::Size(compressed_data_->info().width(), | |
269 compressed_data_->info().height()); | |
270 BuildUIResource(); | |
powei
2014/06/19 23:05:59
Just realized this can be called on the wrong thre
David Trainor- moved to gerrit
2014/06/25 07:40:16
Won't this defeat the purpose of using the UI reso
| |
271 } | |
272 | |
273 void ThumbnailImpl::SetRawData(SkBitmap bitmap, float scale) { | |
274 raw_data_ = bitmap; | |
275 compressed_data_.clear(); | |
276 data_size_ = gfx::Size(bitmap.width(), bitmap.height()); | |
277 content_size_ = data_size_; | |
278 scale_ = scale; | |
279 BuildUIResource(); | |
280 } | |
OLD | NEW |