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 void Start() { | |
38 // Confirm that the file's size is within our threshold. | |
39 int64_t file_size; | |
40 base::FilePath path = base::FilePath::FromUTF8Unsafe(file_path_); | |
41 if (!base::GetFileSize(path, &file_size) || file_size > kMaxImageSize) { | |
42 LOG(ERROR) << "Unexpected file size: " << file_path_ << ", " << file_size; | |
43 FinishRequest(SkBitmap()); | |
44 } | |
45 | |
46 // Make sure the file isn't empty. | |
47 std::string data; | |
48 bool success = base::ReadFileToString(path, &data); | |
49 if (!success || data.empty()) { | |
50 LOG(ERROR) << "Failed to read file: " << file_path_; | |
51 FinishRequest(SkBitmap()); | |
52 } | |
53 | |
54 ImageDecoder::Start(this, data); | |
55 } | |
56 | |
57 void OnImageDecoded(const SkBitmap& decoded_image) override { | |
58 SkBitmap thumbnail = decoded_image; | |
59 if (!decoded_image.drawsNothing()) { | |
60 // Shrink the image down so that its smallest dimension is equal to or | |
61 // smaller than the requested size. | |
62 int min_dimension = | |
63 std::min(decoded_image.width(), decoded_image.height()); | |
64 | |
65 if (min_dimension > icon_size_) { | |
66 uint64_t width = static_cast<uint64_t>(decoded_image.width()); | |
67 uint64_t height = static_cast<uint64_t>(decoded_image.height()); | |
68 thumbnail = skia::ImageOperations::Resize( | |
69 decoded_image, skia::ImageOperations::RESIZE_BEST, | |
70 width * icon_size_ / min_dimension, | |
71 height * icon_size_ / min_dimension); | |
72 } | |
73 } | |
74 | |
75 FinishRequest(thumbnail); | |
76 } | |
77 | |
78 void OnDecodeImageFailed() override { | |
79 LOG(ERROR) << "Failed to decode image: " << file_path_; | |
80 FinishRequest(SkBitmap()); | |
81 } | |
82 | |
83 private: | |
84 void FinishRequest(const SkBitmap& thumbnail) { | |
85 content::BrowserThread::PostTask( | |
86 content::BrowserThread::UI, FROM_HERE, | |
87 base::Bind(&ImageThumbnailRequest::FinishRequestOnUIThread, | |
88 base::Unretained(this), thumbnail)); | |
Ted C
2016/08/31 20:14:40
same question as below, should you be passing the
Ian Wen
2016/08/31 20:43:30
IIRC, weak_ptr is only better than Unretained() if
gone
2016/08/31 22:10:53
This should be fine because the ImageThumbnailRequ
| |
89 } | |
90 | |
91 void FinishRequestOnUIThread(const SkBitmap& thumbnail) { | |
92 if (weak_provider_) | |
93 weak_provider_->OnThumbnailRetrieved(file_path_, thumbnail); | |
94 task_runner()->DeleteSoon(FROM_HERE, this); | |
95 } | |
96 | |
97 const int icon_size_; | |
98 std::string file_path_; | |
99 base::WeakPtr<ThumbnailProvider> weak_provider_; | |
100 | |
101 DISALLOW_IMPLICIT_CONSTRUCTORS(ImageThumbnailRequest); | |
102 }; | |
103 | |
104 } // namespace | |
105 | |
106 ThumbnailProvider::ThumbnailProvider(const JavaParamRef<jobject>& jobj, | |
107 int icon_size) | |
Ted C
2016/08/31 20:14:41
icon_size isn't used
gone
2016/08/31 22:10:53
Whoops. Removed.
| |
108 : java_delegate_(jobj), weak_factory_(this) {} | |
109 | |
110 ThumbnailProvider::~ThumbnailProvider() { | |
111 java_delegate_.Reset(); | |
112 } | |
113 | |
114 void ThumbnailProvider::Destroy(JNIEnv* env, | |
115 const JavaParamRef<jobject>& jobj) { | |
116 delete this; | |
117 } | |
118 | |
119 void ThumbnailProvider::OnThumbnailRetrieved(const std::string& file_path, | |
120 const SkBitmap& thumbnail) { | |
121 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
122 | |
123 if (java_delegate_.is_null()) | |
124 return; | |
125 | |
126 // Send the bitmap back to Java-land. | |
127 JNIEnv* env = base::android::AttachCurrentThread(); | |
128 Java_ThumbnailProviderImpl_onThumbnailRetrieved( | |
129 env, java_delegate_, | |
130 base::android::ConvertUTF8ToJavaString(env, file_path), | |
131 gfx::ConvertToJavaBitmap(&thumbnail)); | |
132 } | |
133 | |
134 void ThumbnailProvider::RetrieveThumbnail(JNIEnv* env, | |
Ted C
2016/08/31 20:14:41
What is the longer term plan for this? Should it
gone
2016/08/31 22:10:53
I'm planning on having this class delegate to diff
| |
135 const JavaParamRef<jobject>& jobj, | |
136 jstring jfile_path, | |
137 jint icon_size) { | |
138 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
139 | |
140 // The ImageThumbnailRequest deletes itself on completion. | |
141 std::string path = base::android::ConvertJavaStringToUTF8(env, jfile_path); | |
142 | |
143 content::BrowserThread::PostTask( | |
144 content::BrowserThread::FILE, FROM_HERE, | |
145 base::Bind(&ThumbnailProvider::RetrieveThumbnailOnFileThread, | |
146 base::Unretained(this), path, icon_size)); | |
Ted C
2016/08/31 20:14:40
I think you need to pass the weak_ptr here. You a
gone
2016/08/31 22:10:53
Blarghhh. Ian and I walked through the wonkiness
| |
147 } | |
148 | |
149 void ThumbnailProvider::RetrieveThumbnailOnFileThread( | |
150 const std::string& file_path, | |
151 int icon_size) { | |
152 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); | |
153 | |
154 ImageThumbnailRequest* request = new ImageThumbnailRequest( | |
155 icon_size, file_path, weak_factory_.GetWeakPtr()); | |
156 request->Start(); | |
157 } | |
158 | |
159 // static | |
160 bool ThumbnailProvider::RegisterJNI(JNIEnv* env) { | |
161 return RegisterNativesImpl(env); | |
162 } | |
163 | |
164 // static | |
165 static jlong Init(JNIEnv* env, | |
166 const JavaParamRef<jobject>& jobj, | |
167 int icon_size) { | |
168 return reinterpret_cast<intptr_t>(new ThumbnailProvider(jobj, icon_size)); | |
169 } | |
OLD | NEW |