Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: ui/gfx/image/image_skia.cc

Issue 1841343002: Deinline body of ImageSkiaStorage. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove added bit Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/image/image_skia.h" 5 #include "ui/gfx/image/image_skia.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <cmath> 10 #include <cmath>
(...skipping 27 matching lines...) Expand all
38 // larger one. For example, assume 1.20 is requested but only 1.0 and 2.0 are 38 // larger one. For example, assume 1.20 is requested but only 1.0 and 2.0 are
39 // supported. In that case, not fall back to 2.0 but 1.0, and then expand 39 // supported. In that case, not fall back to 2.0 but 1.0, and then expand
40 // the image to 1.25. 40 // the image to 1.25.
41 const float kFallbackToSmallerScaleDiff = 0.20f; 41 const float kFallbackToSmallerScaleDiff = 0.20f;
42 42
43 } // namespace 43 } // namespace
44 44
45 namespace internal { 45 namespace internal {
46 namespace { 46 namespace {
47 47
48 class Matcher {
49 public:
50 explicit Matcher(float scale) : scale_(scale) {
51 }
52
53 bool operator()(const ImageSkiaRep& rep) const {
54 return rep.scale() == scale_;
55 }
56
57 private:
58 float scale_;
59 };
60
61 ImageSkiaRep ScaleImageSkiaRep(const ImageSkiaRep& rep, float target_scale) { 48 ImageSkiaRep ScaleImageSkiaRep(const ImageSkiaRep& rep, float target_scale) {
62 if (rep.is_null() || rep.scale() == target_scale) 49 if (rep.is_null() || rep.scale() == target_scale)
63 return rep; 50 return rep;
64 51
65 gfx::Size scaled_size = 52 gfx::Size scaled_size =
66 gfx::ScaleToCeiledSize(rep.pixel_size(), target_scale / rep.scale()); 53 gfx::ScaleToCeiledSize(rep.pixel_size(), target_scale / rep.scale());
67 return ImageSkiaRep(skia::ImageOperations::Resize( 54 return ImageSkiaRep(skia::ImageOperations::Resize(
68 rep.sk_bitmap(), 55 rep.sk_bitmap(),
69 skia::ImageOperations::RESIZE_LANCZOS3, 56 skia::ImageOperations::RESIZE_LANCZOS3,
70 scaled_size.width(), 57 scaled_size.width(),
71 scaled_size.height()), target_scale); 58 scaled_size.height()), target_scale);
72 } 59 }
73 60
74 } // namespace 61 } // namespace
75 62
76 // A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a 63 // A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a
77 // refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's 64 // refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's
78 // information. Having both |base::RefCountedThreadSafe| and 65 // information. Having both |base::RefCountedThreadSafe| and
79 // |base::NonThreadSafe| may sounds strange but necessary to turn 66 // |base::NonThreadSafe| may sound strange but is necessary to turn
80 // the 'thread-non-safe modifiable ImageSkiaStorage' into 67 // the 'thread-non-safe modifiable ImageSkiaStorage' into
81 // the 'thread-safe read-only ImageSkiaStorage'. 68 // the 'thread-safe read-only ImageSkiaStorage'.
82 class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>, 69 class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>,
83 public base::NonThreadSafe { 70 public base::NonThreadSafe {
84 public: 71 public:
85 ImageSkiaStorage(ImageSkiaSource* source, const gfx::Size& size) 72 ImageSkiaStorage(ImageSkiaSource* source, const gfx::Size& size);
86 : source_(source), 73 ImageSkiaStorage(ImageSkiaSource* source, float scale);
87 size_(size),
88 read_only_(false) {
89 }
90 74
91 ImageSkiaStorage(ImageSkiaSource* source, float scale) 75 bool has_source() const { return source_ != nullptr; }
92 : source_(source),
93 read_only_(false) {
94 ImageSkia::ImageSkiaReps::iterator it = FindRepresentation(scale, true);
95 if (it == image_reps_.end() || it->is_null())
96 source_.reset();
97 else
98 size_.SetSize(it->GetWidth(), it->GetHeight());
99 }
100
101 bool has_source() const { return source_.get() != NULL; }
102
103 std::vector<gfx::ImageSkiaRep>& image_reps() { return image_reps_; } 76 std::vector<gfx::ImageSkiaRep>& image_reps() { return image_reps_; }
104
105 const gfx::Size& size() const { return size_; } 77 const gfx::Size& size() const { return size_; }
106
107 bool read_only() const { return read_only_; } 78 bool read_only() const { return read_only_; }
108 79
109 void DeleteSource() { 80 void DeleteSource();
110 source_.reset(); 81 void SetReadOnly();
111 } 82 void DetachFromThread();
112
113 void SetReadOnly() {
114 read_only_ = true;
115 }
116
117 void DetachFromThread() {
118 base::NonThreadSafe::DetachFromThread();
119 }
120 83
121 // Checks if the current thread can safely modify the storage. 84 // Checks if the current thread can safely modify the storage.
122 bool CanModify() const { 85 bool CanModify() const;
123 return !read_only_ && CalledOnValidThread();
124 }
125 86
126 // Checks if the current thread can safely read the storage. 87 // Checks if the current thread can safely read the storage.
127 bool CanRead() const { 88 bool CanRead() const;
128 return (read_only_ && !source_.get()) || CalledOnValidThread();
129 }
130 89
131 // Add a new representation. This checks if the scale of the added image 90 // Add a new representation. This checks if the scale of the added image
132 // is not 1.0f, and mark the existing rep as scaled to make 91 // is not 1.0f, and mark the existing rep as scaled to make
133 // the image high DPI aware. 92 // the image high DPI aware.
134 void AddRepresentation(const ImageSkiaRep& image) { 93 void AddRepresentation(const ImageSkiaRep& image);
135 if (image.scale() != 1.0f) {
136 for (ImageSkia::ImageSkiaReps::iterator it = image_reps_.begin();
137 it < image_reps_.end();
138 ++it) {
139 if (it->unscaled()) {
140 DCHECK_EQ(1.0f, it->scale());
141 it->SetScaled();
142 break;
143 }
144 }
145 }
146 image_reps_.push_back(image);
147 }
148 94
149 // Returns the iterator of the image rep whose density best matches 95 // Returns the iterator of the image rep whose density best matches
150 // |scale|. If the image for the |scale| doesn't exist in the storage and 96 // |scale|. If the image for the |scale| doesn't exist in the storage and
151 // |storage| is set, it fetches new image by calling 97 // |storage| is set, it fetches new image by calling
152 // |ImageSkiaSource::GetImageForScale|. There are two modes to deal with 98 // |ImageSkiaSource::GetImageForScale|. There are two modes to deal with
153 // arbitrary scale factors. 99 // arbitrary scale factors.
154 // 1: Invoke GetImageForScale with requested scale and if the source 100 // 1: Invoke GetImageForScale with requested scale and if the source
155 // returns the image with different scale (if the image doesn't exist in 101 // returns the image with different scale (if the image doesn't exist in
156 // resource, for example), it will fallback to closest image rep. 102 // resource, for example), it will fallback to closest image rep.
157 // 2: Invoke GetImageForScale with the closest known scale to the requested 103 // 2: Invoke GetImageForScale with the closest known scale to the requested
158 // one and rescale the image. 104 // one and rescale the image.
159 // Right now only Windows uses 2 and other platforms use 1 by default. 105 // Right now only Windows uses 2 and other platforms use 1 by default.
160 // TODO(mukai, oshima): abandon 1 code path and use 2 for every platforms. 106 // TODO(mukai, oshima): abandon 1 code path and use 2 for every platforms.
161 std::vector<ImageSkiaRep>::iterator FindRepresentation( 107 std::vector<ImageSkiaRep>::iterator FindRepresentation(
162 float scale, bool fetch_new_image) const { 108 float scale,
163 ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this); 109 bool fetch_new_image) const;
164
165 ImageSkia::ImageSkiaReps::iterator closest_iter =
166 non_const->image_reps().end();
167 ImageSkia::ImageSkiaReps::iterator exact_iter =
168 non_const->image_reps().end();
169 float smallest_diff = std::numeric_limits<float>::max();
170 for (ImageSkia::ImageSkiaReps::iterator it =
171 non_const->image_reps().begin();
172 it < image_reps_.end(); ++it) {
173 if (it->scale() == scale) {
174 // found exact match
175 fetch_new_image = false;
176 if (it->is_null())
177 continue;
178 exact_iter = it;
179 break;
180 }
181 float diff = std::abs(it->scale() - scale);
182 if (diff < smallest_diff && !it->is_null()) {
183 closest_iter = it;
184 smallest_diff = diff;
185 }
186 }
187
188 if (fetch_new_image && source_.get()) {
189 DCHECK(CalledOnValidThread()) <<
190 "An ImageSkia with the source must be accessed by the same thread.";
191
192 ImageSkiaRep image;
193 float resource_scale = scale;
194 if (g_supported_scales) {
195 if (g_supported_scales->back() <= scale) {
196 resource_scale = g_supported_scales->back();
197 } else {
198 for (size_t i = 0; i < g_supported_scales->size(); ++i) {
199 if ((*g_supported_scales)[i] + kFallbackToSmallerScaleDiff >=
200 scale) {
201 resource_scale = (*g_supported_scales)[i];
202 break;
203 }
204 }
205 }
206 }
207 if (scale != resource_scale) {
208 std::vector<ImageSkiaRep>::iterator iter = FindRepresentation(
209 resource_scale, fetch_new_image);
210 DCHECK(iter != image_reps_.end());
211 image = iter->unscaled() ? (*iter) : ScaleImageSkiaRep(*iter, scale);
212 } else {
213 image = source_->GetImageForScale(scale);
214 // Image may be missing for the specified scale in some cases, such like
215 // looking up 2x resources but the 2x resource pack is missing. Falls
216 // back to 1x and re-scale it.
217 if (image.is_null() && scale != 1.0f)
218 image = ScaleImageSkiaRep(source_->GetImageForScale(1.0f), scale);
219 }
220
221 // If the source returned the new image, store it.
222 if (!image.is_null() &&
223 std::find_if(image_reps_.begin(), image_reps_.end(),
224 Matcher(image.scale())) == image_reps_.end()) {
225 non_const->image_reps().push_back(image);
226 }
227
228 // If the result image's scale isn't same as the expected scale, create
229 // null ImageSkiaRep with the |scale| so that the next lookup will
230 // fallback to the closest scale.
231 if (image.is_null() || image.scale() != scale) {
232 non_const->image_reps().push_back(ImageSkiaRep(SkBitmap(), scale));
233 }
234
235 // image_reps_ must have the exact much now, so find again.
236 return FindRepresentation(scale, false);
237 }
238 return exact_iter != image_reps_.end() ? exact_iter : closest_iter;
239 }
240 110
241 private: 111 private:
242 virtual ~ImageSkiaStorage() { 112 friend class base::RefCountedThreadSafe<ImageSkiaStorage>;
243 // We only care if the storage is modified by the same thread. 113
244 // Don't blow up even if someone else deleted the ImageSkia. 114 virtual ~ImageSkiaStorage();
245 DetachFromThread();
246 }
247 115
248 // Vector of bitmaps and their associated scale. 116 // Vector of bitmaps and their associated scale.
249 std::vector<gfx::ImageSkiaRep> image_reps_; 117 std::vector<gfx::ImageSkiaRep> image_reps_;
250 118
251 scoped_ptr<ImageSkiaSource> source_; 119 scoped_ptr<ImageSkiaSource> source_;
252 120
253 // Size of the image in DIP. 121 // Size of the image in DIP.
254 gfx::Size size_; 122 gfx::Size size_;
255 123
256 bool read_only_; 124 bool read_only_;
257 125
258 friend class base::RefCountedThreadSafe<ImageSkiaStorage>; 126 DISALLOW_COPY_AND_ASSIGN(ImageSkiaStorage);
259 }; 127 };
260 128
129 ImageSkiaStorage::ImageSkiaStorage(ImageSkiaSource* source,
130 const gfx::Size& size)
131 : source_(source), size_(size), read_only_(false) {}
132
133 ImageSkiaStorage::ImageSkiaStorage(ImageSkiaSource* source, float scale)
134 : source_(source), read_only_(false) {
135 ImageSkia::ImageSkiaReps::iterator it = FindRepresentation(scale, true);
136 if (it == image_reps_.end() || it->is_null())
137 source_.reset();
138 else
139 size_.SetSize(it->GetWidth(), it->GetHeight());
140 }
141
142 void ImageSkiaStorage::DeleteSource() {
143 source_.reset();
144 }
145
146 void ImageSkiaStorage::SetReadOnly() {
147 read_only_ = true;
148 }
149
150 void ImageSkiaStorage::DetachFromThread() {
151 base::NonThreadSafe::DetachFromThread();
152 }
153
154 bool ImageSkiaStorage::CanModify() const {
155 return !read_only_ && CalledOnValidThread();
156 }
157
158 bool ImageSkiaStorage::CanRead() const {
159 return (read_only_ && !source_) || CalledOnValidThread();
160 }
161
162 void ImageSkiaStorage::AddRepresentation(const ImageSkiaRep& image) {
163 if (image.scale() != 1.0f) {
164 for (ImageSkia::ImageSkiaReps::iterator it = image_reps_.begin();
165 it < image_reps_.end(); ++it) {
166 if (it->unscaled()) {
167 DCHECK_EQ(1.0f, it->scale());
168 it->SetScaled();
169 break;
170 }
171 }
172 }
173 image_reps_.push_back(image);
174 }
175
176 std::vector<ImageSkiaRep>::iterator ImageSkiaStorage::FindRepresentation(
177 float scale,
178 bool fetch_new_image) const {
179 ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this);
180
181 ImageSkia::ImageSkiaReps::iterator closest_iter =
182 non_const->image_reps().end();
183 ImageSkia::ImageSkiaReps::iterator exact_iter = non_const->image_reps().end();
184 float smallest_diff = std::numeric_limits<float>::max();
185 for (ImageSkia::ImageSkiaReps::iterator it = non_const->image_reps().begin();
186 it < image_reps_.end(); ++it) {
187 if (it->scale() == scale) {
188 // found exact match
189 fetch_new_image = false;
190 if (it->is_null())
191 continue;
192 exact_iter = it;
193 break;
194 }
195 float diff = std::abs(it->scale() - scale);
196 if (diff < smallest_diff && !it->is_null()) {
197 closest_iter = it;
198 smallest_diff = diff;
199 }
200 }
201
202 if (fetch_new_image && source_.get()) {
203 DCHECK(CalledOnValidThread())
204 << "An ImageSkia with the source must be accessed by the same thread.";
205
206 ImageSkiaRep image;
207 float resource_scale = scale;
208 if (g_supported_scales) {
209 if (g_supported_scales->back() <= scale) {
210 resource_scale = g_supported_scales->back();
211 } else {
212 for (size_t i = 0; i < g_supported_scales->size(); ++i) {
213 if ((*g_supported_scales)[i] + kFallbackToSmallerScaleDiff >= scale) {
214 resource_scale = (*g_supported_scales)[i];
215 break;
216 }
217 }
218 }
219 }
220 if (scale != resource_scale) {
221 std::vector<ImageSkiaRep>::iterator iter =
222 FindRepresentation(resource_scale, fetch_new_image);
223 DCHECK(iter != image_reps_.end());
224 image = iter->unscaled() ? (*iter) : ScaleImageSkiaRep(*iter, scale);
225 } else {
226 image = source_->GetImageForScale(scale);
227 // Image may be missing for the specified scale in some cases, such like
228 // looking up 2x resources but the 2x resource pack is missing. Fall back
229 // to 1x and re-scale it.
230 if (image.is_null() && scale != 1.0f)
231 image = ScaleImageSkiaRep(source_->GetImageForScale(1.0f), scale);
232 }
233
234 // If the source returned the new image, store it.
235 if (!image.is_null() &&
236 std::find_if(image_reps_.begin(), image_reps_.end(),
237 [&image](const ImageSkiaRep& rep) {
238 return rep.scale() == image.scale();
239 }) == image_reps_.end()) {
240 non_const->image_reps().push_back(image);
241 }
242
243 // If the result image's scale isn't same as the expected scale, create a
244 // null ImageSkiaRep with the |scale| so that the next lookup will fall back
245 // to the closest scale.
246 if (image.is_null() || image.scale() != scale) {
247 non_const->image_reps().push_back(ImageSkiaRep(SkBitmap(), scale));
248 }
249
250 // image_reps_ must have the exact much now, so find again.
251 return FindRepresentation(scale, false);
252 }
253 return exact_iter != image_reps_.end() ? exact_iter : closest_iter;
254 }
255
256 ImageSkiaStorage::~ImageSkiaStorage() {
257 // We only care if the storage is modified by the same thread. Don't blow up
258 // even if someone else deleted the ImageSkia.
259 DetachFromThread();
260 }
261
261 } // internal 262 } // internal
262 263
263 ImageSkia::ImageSkia() : storage_(NULL) { 264 ImageSkia::ImageSkia() : storage_(NULL) {
264 } 265 }
265 266
266 ImageSkia::ImageSkia(ImageSkiaSource* source, const gfx::Size& size) 267 ImageSkia::ImageSkia(ImageSkiaSource* source, const gfx::Size& size)
267 : storage_(new internal::ImageSkiaStorage(source, size)) { 268 : storage_(new internal::ImageSkiaStorage(source, size)) {
268 DCHECK(source); 269 DCHECK(source);
269 // No other thread has reference to this, so it's safe to detach the thread. 270 // No other thread has reference to this, so it's safe to detach the thread.
270 DetachStorageFromThread(); 271 DetachStorageFromThread();
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
495 bool ImageSkia::CanModify() const { 496 bool ImageSkia::CanModify() const {
496 return !storage_.get() || storage_->CanModify(); 497 return !storage_.get() || storage_->CanModify();
497 } 498 }
498 499
499 void ImageSkia::DetachStorageFromThread() { 500 void ImageSkia::DetachStorageFromThread() {
500 if (storage_.get()) 501 if (storage_.get())
501 storage_->DetachFromThread(); 502 storage_->DetachFromThread();
502 } 503 }
503 504
504 } // namespace gfx 505 } // namespace gfx
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698