OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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/download/ui/thumbnail_provider.h" | |
6 | |
7 #include "base/android/jni_string.h" | |
8 #include "base/files/file_path.h" | |
9 #include "base/files/file_util.h" | |
10 #include "base/memory/weak_ptr.h" | |
11 #include "chrome/browser/image_decoder.h" | |
12 #include "content/public/browser/browser_thread.h" | |
13 #include "jni/ThumbnailProviderImpl_jni.h" | |
14 #include "skia/ext/image_operations.h" | |
15 #include "third_party/skia/include/core/SkBitmap.h" | |
16 #include "ui/gfx/android/java_bitmap.h" | |
17 #include "ui/gfx/skbitmap_operations.h" | |
18 | |
19 class SkBitmap; | |
20 | |
21 using base::android::JavaParamRef; | |
22 | |
23 namespace { | |
24 | |
25 // Ignore image files that are too large to avoid long delays. | |
26 const int64_t kMaxImageSize = 10 * 1024 * 1024; // 10 MB | |
27 | |
28 class ImageThumbnailRequest : public ImageDecoder::ImageRequest { | |
29 public: | |
30 ImageThumbnailRequest(int icon_size, | |
31 const std::string& file_path, | |
32 base::WeakPtr<ThumbnailProvider> weak_provider) | |
33 : icon_size_(icon_size), | |
34 file_path_(file_path), | |
35 weak_provider_(weak_provider) { | |
36 } | |
37 | |
38 void Start() { | |
39 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)) { | |
Ted C
2016/08/31 00:34:35
let's pull this out to a separate function and mak
gone
2016/08/31 01:35:04
Turns out you can force all of this to be on the F
| |
40 content::BrowserThread::PostTask( | |
41 content::BrowserThread::FILE, | |
42 FROM_HERE, | |
43 base::Bind(&ImageThumbnailRequest::Start, base::Unretained(this))); | |
44 return; | |
45 } | |
46 | |
47 // Re-check the file's size because it may have changed. | |
Ted C
2016/08/31 00:34:34
I think "// Ensure the file does not exceed our ma
gone
2016/08/31 01:35:04
Did some variant of this sentence.
| |
48 int64_t file_size; | |
49 base::FilePath path = base::FilePath::FromUTF8Unsafe(file_path_); | |
50 if (!base::GetFileSize(path, &file_size) || | |
51 file_size > kMaxImageSize) { | |
52 LOG(ERROR) << "Unexpected file size: " << file_path_ << ", " << file_size; | |
53 FinishRequest(SkBitmap()); | |
54 } | |
55 | |
56 // Make sure the file isn't empty. | |
57 std::string data; | |
58 bool success = base::ReadFileToString(path, &data); | |
59 if (!success || data.empty()) { | |
60 LOG(ERROR) << "Failed to read file: " << file_path_; | |
61 FinishRequest(SkBitmap()); | |
62 } | |
63 | |
64 ImageDecoder::Start(this, data); | |
65 } | |
66 | |
67 void OnImageDecoded(const SkBitmap& decoded_image) override { | |
68 SkBitmap thumbnail = decoded_image; | |
69 if (!decoded_image.drawsNothing()) { | |
70 // Shrink the image down so that its smallest dimension is within range. | |
71 int min_dimension = std::min(decoded_image.width(), | |
72 decoded_image.height()); | |
73 | |
74 if (min_dimension > icon_size_) { | |
75 uint64_t width = static_cast<uint64_t>(decoded_image.width()); | |
76 uint64_t height = static_cast<uint64_t>(decoded_image.height()); | |
77 thumbnail = skia::ImageOperations::Resize( | |
Ted C
2016/08/31 00:34:35
it'd be nice to not do this on the UI thread...don
gone
2016/08/31 01:35:04
Done.
| |
78 decoded_image, | |
Ted C
2016/08/31 00:34:34
this looks wonky to me. I think it should be 4 fr
gone
2016/08/31 01:35:04
Actually ran git cl format this time.
| |
79 skia::ImageOperations::RESIZE_BEST, | |
80 width * icon_size_ / min_dimension, | |
81 height * icon_size_ / min_dimension); | |
82 } | |
83 } | |
84 | |
85 FinishRequest(thumbnail); | |
86 } | |
87 | |
88 void OnDecodeImageFailed() override { | |
89 LOG(ERROR) << "Failed to decode image: " << file_path_; | |
90 FinishRequest(SkBitmap()); | |
91 } | |
92 | |
93 private: | |
94 void FinishRequest(const SkBitmap& thumbnail) { | |
95 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { | |
96 content::BrowserThread::PostTask( | |
Ted C
2016/08/31 00:34:35
ideally the same comment as above and have anyone
gone
2016/08/31 01:35:04
Done.
| |
97 content::BrowserThread::UI, | |
98 FROM_HERE, | |
99 base::Bind(&ImageThumbnailRequest::FinishRequest, | |
100 base::Unretained(this), thumbnail)); | |
101 return; | |
102 } | |
103 | |
104 if (weak_provider_) | |
105 weak_provider_->OnThumbnailRetrieved(file_path_, thumbnail); | |
106 task_runner()->DeleteSoon(FROM_HERE, this); | |
107 } | |
108 | |
109 const int icon_size_; | |
110 std::string file_path_; | |
111 base::WeakPtr<ThumbnailProvider> weak_provider_; | |
112 | |
113 DISALLOW_IMPLICIT_CONSTRUCTORS(ImageThumbnailRequest); | |
114 }; | |
115 | |
116 } // namespace | |
117 | |
118 ThumbnailProvider::ThumbnailProvider(const JavaParamRef<jobject>& jobj, | |
119 int icon_size) | |
120 : java_delegate_(jobj), | |
121 weak_factory_(this) { | |
122 } | |
123 | |
124 ThumbnailProvider::~ThumbnailProvider() { | |
125 java_delegate_.Reset(); | |
126 weak_factory_.InvalidateWeakPtrs(); | |
Ted C
2016/08/31 00:34:35
This happens as a result of destructing the WeakPt
gone
2016/08/31 01:35:04
Done.
| |
127 } | |
128 | |
129 void ThumbnailProvider::Destroy(JNIEnv* env, | |
130 const JavaParamRef<jobject>& jobj) { | |
131 delete this; | |
132 } | |
133 | |
134 void ThumbnailProvider::OnThumbnailRetrieved(const std::string& file_path, | |
135 const SkBitmap& thumbnail) { | |
136 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
137 | |
138 if (java_delegate_.is_null()) | |
139 return; | |
140 | |
141 // Send the bitmap back to Java-land. | |
142 JNIEnv* env = base::android::AttachCurrentThread(); | |
143 Java_ThumbnailProviderImpl_onThumbnailRetrieved( | |
144 env, | |
145 java_delegate_, | |
146 base::android::ConvertUTF8ToJavaString(env, file_path), | |
147 gfx::ConvertToJavaBitmap(&thumbnail)); | |
148 } | |
149 | |
150 void ThumbnailProvider::RetrieveThumbnail(JNIEnv* env, | |
151 const JavaParamRef<jobject>& jobj, | |
152 jstring file_path, | |
153 jint icon_size) { | |
154 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
155 | |
156 // The ImageThumbnailRequest deletes itself on completion. | |
157 std::string path = base::android::ConvertJavaStringToUTF8(env, file_path); | |
158 ImageThumbnailRequest* request = new ImageThumbnailRequest( | |
159 icon_size, path, weak_factory_.GetWeakPtr()); | |
160 request->Start(); | |
161 } | |
162 | |
163 // static | |
164 bool ThumbnailProvider::RegisterJNI(JNIEnv* env) { | |
165 return RegisterNativesImpl(env); | |
166 } | |
167 | |
168 // static | |
169 static jlong Init(JNIEnv* env, | |
170 const JavaParamRef<jobject>& jobj, | |
171 int icon_size) { | |
172 return reinterpret_cast<intptr_t>(new ThumbnailProvider(jobj, icon_size)); | |
173 } | |
OLD | NEW |