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

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

Issue 12730010: Fix rounding rules for skia operations to work with non-integer scaling factors. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Update sizes. Created 7 years, 9 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 | « ui/gfx/canvas.cc ('k') | 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_operations.h" 5 #include "ui/gfx/image/image_skia_operations.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "skia/ext/image_operations.h" 9 #include "skia/ext/image_operations.h"
10 #include "ui/base/layout.h" 10 #include "ui/base/layout.h"
11 #include "ui/gfx/canvas.h" 11 #include "ui/gfx/canvas.h"
12 #include "ui/gfx/image/canvas_image_source.h" 12 #include "ui/gfx/image/canvas_image_source.h"
13 #include "ui/gfx/image/image_skia.h" 13 #include "ui/gfx/image/image_skia.h"
14 #include "ui/gfx/image/image_skia_rep.h" 14 #include "ui/gfx/image/image_skia_rep.h"
15 #include "ui/gfx/image/image_skia_source.h" 15 #include "ui/gfx/image/image_skia_source.h"
16 #include "ui/gfx/insets.h" 16 #include "ui/gfx/insets.h"
17 #include "ui/gfx/point.h"
18 #include "ui/gfx/point_conversions.h"
17 #include "ui/gfx/rect.h" 19 #include "ui/gfx/rect.h"
18 #include "ui/gfx/rect_conversions.h" 20 #include "ui/gfx/rect_conversions.h"
19 #include "ui/gfx/size.h" 21 #include "ui/gfx/size.h"
20 #include "ui/gfx/size_conversions.h" 22 #include "ui/gfx/size_conversions.h"
21 #include "ui/gfx/skbitmap_operations.h" 23 #include "ui/gfx/skbitmap_operations.h"
22 #include "ui/gfx/skia_util.h" 24 #include "ui/gfx/skia_util.h"
23 25
24 namespace gfx { 26 namespace gfx {
25 namespace { 27 namespace {
26 28
29 gfx::Rect DIPToPixelBounds(gfx::Rect dip_bounds, float scale) {
30 return ToEnclosingRect(ScaleRect(dip_bounds, scale));
31 }
32
33 gfx::Size DIPToPixelSize(gfx::Size dip_size, float scale) {
34 return ToCeiledSize(ScaleSize(dip_size, scale));
35 }
36
37 ImageSkiaRep CropBitmap(ImageSkiaRep& source, gfx::Rect& bounds) {
pkotwicz 2013/03/13 04:03:48 Nit: Rename to CropImageSkiaRep Rename |bound
kevers 2013/03/13 14:36:59 Done.
38 SkBitmap result;
39 bool success = source.sk_bitmap().extractSubset(&result,
40 RectToSkIRect(bounds));
41 DCHECK(success);
42 return ImageSkiaRep(result, source.scale_factor());
43 }
44
27 // Returns an image rep for the ImageSkiaSource to return to visually indicate 45 // Returns an image rep for the ImageSkiaSource to return to visually indicate
28 // an error. 46 // an error.
29 ImageSkiaRep GetErrorImageRep(ui::ScaleFactor scale_factor, 47 ImageSkiaRep GetErrorImageRep(ui::ScaleFactor scale_factor,
30 const gfx::Size& pixel_size) { 48 const gfx::Size& pixel_size) {
31 SkBitmap bitmap; 49 SkBitmap bitmap;
32 bitmap.setConfig( 50 bitmap.setConfig(
33 SkBitmap::kARGB_8888_Config, pixel_size.width(), pixel_size.height()); 51 SkBitmap::kARGB_8888_Config, pixel_size.width(), pixel_size.height());
34 bitmap.allocPixels(); 52 bitmap.allocPixels();
35 bitmap.eraseColor(SK_ColorRED); 53 bitmap.eraseColor(SK_ColorRED);
36 return gfx::ImageSkiaRep(bitmap, scale_factor); 54 return gfx::ImageSkiaRep(bitmap, scale_factor);
(...skipping 10 matching lines...) Expand all
47 second_(second), 65 second_(second),
48 source_name_(source_name) { 66 source_name_(source_name) {
49 } 67 }
50 virtual ~BinaryImageSource() { 68 virtual ~BinaryImageSource() {
51 } 69 }
52 70
53 // gfx::ImageSkiaSource overrides: 71 // gfx::ImageSkiaSource overrides:
54 virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { 72 virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE {
55 ImageSkiaRep first_rep = first_.GetRepresentation(scale_factor); 73 ImageSkiaRep first_rep = first_.GetRepresentation(scale_factor);
56 ImageSkiaRep second_rep = second_.GetRepresentation(scale_factor); 74 ImageSkiaRep second_rep = second_.GetRepresentation(scale_factor);
57 if (first_rep.pixel_size() != second_rep.pixel_size()) { 75 gfx::Size first_size = first_rep.pixel_size();
76 gfx::Size second_size = second_rep.pixel_size();
77 // Allow for maximum of 1 pixel mismatch due to rounding errors.
pkotwicz 2013/03/13 04:03:48 Nit: "due to rounding errors because of a fraction
kevers 2013/03/13 14:36:59 Done.
78 int dw = first_size.width() - second_size.width();
79 int dh = first_size.height() - second_size.height();
80 if (abs(dw) > 1 || abs(dh) > 1) {
58 DCHECK_NE(first_rep.scale_factor(), second_rep.scale_factor()); 81 DCHECK_NE(first_rep.scale_factor(), second_rep.scale_factor());
59 if (first_rep.scale_factor() == second_rep.scale_factor()) { 82 if (first_rep.scale_factor() == second_rep.scale_factor()) {
60 LOG(ERROR) << "ImageSkiaRep size mismatch in " << source_name_; 83 LOG(ERROR) << "ImageSkiaRep size mismatch in " << source_name_;
61 return GetErrorImageRep(first_rep.scale_factor(), 84 return GetErrorImageRep(first_rep.scale_factor(),
62 first_rep.pixel_size()); 85 first_rep.pixel_size());
63 } 86 }
64 first_rep = first_.GetRepresentation(ui::SCALE_FACTOR_100P); 87 first_rep = first_.GetRepresentation(ui::SCALE_FACTOR_100P);
65 second_rep = second_.GetRepresentation(ui::SCALE_FACTOR_100P); 88 second_rep = second_.GetRepresentation(ui::SCALE_FACTOR_100P);
66 DCHECK_EQ(first_rep.pixel_width(), second_rep.pixel_width()); 89 first_size = first_rep.pixel_size();
67 DCHECK_EQ(first_rep.pixel_height(), second_rep.pixel_height()); 90 second_size = second_rep.pixel_size();
68 if (first_rep.pixel_size() != second_rep.pixel_size()) { 91 dw = first_size.width() - second_size.width();
92 dh = first_size.height() - second_size.height();
pkotwicz 2013/03/13 04:03:48 Use ImageSkiaRep::pixel_width() and ImageSkiaRep::
kevers 2013/03/13 14:36:59 Done.
93 DCHECK_LE(abs(dw), 1);
94 DCHECK_LE(abs(dh), 1);
95 if (abs(dw) > 1 || abs(dh) > 1) {
69 LOG(ERROR) << "ImageSkiaRep size mismatch in " << source_name_; 96 LOG(ERROR) << "ImageSkiaRep size mismatch in " << source_name_;
70 return GetErrorImageRep(first_rep.scale_factor(), 97 return GetErrorImageRep(first_rep.scale_factor(),
71 first_rep.pixel_size()); 98 first_rep.pixel_size());
72 } 99 }
73 } else { 100 } else {
74 DCHECK_EQ(first_rep.scale_factor(), second_rep.scale_factor()); 101 DCHECK_EQ(first_rep.scale_factor(), second_rep.scale_factor());
75 } 102 }
103 if (dw || dh) {
104 gfx::Rect bounds = IntersectRects(Rect(first_size), Rect(second_size));
105 first_rep = CropBitmap(first_rep, bounds);
106 second_rep = CropBitmap(second_rep, bounds);
107 }
76 return CreateImageSkiaRep(first_rep, second_rep); 108 return CreateImageSkiaRep(first_rep, second_rep);
77 } 109 }
78 110
79 // Creates a final image from two ImageSkiaReps. The pixel size of 111 // Creates a final image from two ImageSkiaReps. The pixel size of
80 // the two images are guaranteed to be the same. 112 // the two images are guaranteed to be the same.
81 virtual ImageSkiaRep CreateImageSkiaRep( 113 virtual ImageSkiaRep CreateImageSkiaRep(
82 const ImageSkiaRep& first_rep, 114 const ImageSkiaRep& first_rep,
83 const ImageSkiaRep& second_rep) const = 0; 115 const ImageSkiaRep& second_rep) const = 0;
84 116
85 private: 117 private:
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 dst_h_(dst_h) { 241 dst_h_(dst_h) {
210 } 242 }
211 243
212 virtual ~TiledImageSource() { 244 virtual ~TiledImageSource() {
213 } 245 }
214 246
215 // gfx::ImageSkiaSource overrides: 247 // gfx::ImageSkiaSource overrides:
216 virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { 248 virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE {
217 ImageSkiaRep source_rep = source_.GetRepresentation(scale_factor); 249 ImageSkiaRep source_rep = source_.GetRepresentation(scale_factor);
218 float scale = ui::GetScaleFactorScale(source_rep.scale_factor()); 250 float scale = ui::GetScaleFactorScale(source_rep.scale_factor());
251 gfx::Rect bounds = DIPToPixelBounds(gfx::Rect(src_x_, src_y_, dst_w_,
252 dst_h_), scale);
pkotwicz 2013/03/13 04:03:48 ToEnclosingRect() does something different than us
kevers 2013/03/13 14:36:59 The size resulting from using ToEnclosingRect is a
219 return ImageSkiaRep( 253 return ImageSkiaRep(
220 SkBitmapOperations::CreateTiledBitmap( 254 SkBitmapOperations::CreateTiledBitmap(
221 source_rep.sk_bitmap(), 255 source_rep.sk_bitmap(),
222 src_x_ * scale, src_y_ * scale, dst_w_ * scale, dst_h_ * scale), 256 bounds.x(), bounds.y(), bounds.width(), bounds.height()),
223 source_rep.scale_factor()); 257 source_rep.scale_factor());
224 } 258 }
225 259
226 private: 260 private:
227 const ImageSkia source_; 261 const ImageSkia source_;
228 const int src_x_; 262 const int src_x_;
229 const int src_y_; 263 const int src_y_;
230 const int dst_w_; 264 const int dst_w_;
231 const int dst_h_; 265 const int dst_h_;
232 266
(...skipping 20 matching lines...) Expand all
253 } 287 }
254 288
255 private: 289 private:
256 const gfx::ImageSkia image_; 290 const gfx::ImageSkia image_;
257 const color_utils::HSL hsl_shift_; 291 const color_utils::HSL hsl_shift_;
258 DISALLOW_COPY_AND_ASSIGN(HSLImageSource); 292 DISALLOW_COPY_AND_ASSIGN(HSLImageSource);
259 }; 293 };
260 294
261 // ImageSkiaSource which uses SkBitmapOperations::CreateButtonBackground 295 // ImageSkiaSource which uses SkBitmapOperations::CreateButtonBackground
262 // to generate image reps for the target image. 296 // to generate image reps for the target image.
263 class ButtonImageSource: public gfx::ImageSkiaSource { 297 class ButtonImageSource: public BinaryImageSource {
264 public: 298 public:
265 ButtonImageSource(SkColor color, 299 ButtonImageSource(SkColor color,
266 const ImageSkia& image, 300 const ImageSkia& image,
267 const ImageSkia& mask) 301 const ImageSkia& mask)
268 : color_(color), 302 : BinaryImageSource(image, mask, "ButtonImageSource"),
269 image_(image), 303 color_(color) {
270 mask_(mask) {
271 } 304 }
272 305
273 virtual ~ButtonImageSource() { 306 virtual ~ButtonImageSource() {
274 } 307 }
275 308
276 // gfx::ImageSkiaSource overrides: 309 // BinaryImageSource overrides:
277 virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { 310 virtual ImageSkiaRep CreateImageSkiaRep(
278 ImageSkiaRep image_rep = image_.GetRepresentation(scale_factor); 311 const ImageSkiaRep& first_rep,
279 ImageSkiaRep mask_rep = mask_.GetRepresentation(scale_factor); 312 const ImageSkiaRep& second_rep) const OVERRIDE {
280 if (image_rep.scale_factor() != mask_rep.scale_factor()) {
281 image_rep = image_.GetRepresentation(ui::SCALE_FACTOR_100P);
282 mask_rep = mask_.GetRepresentation(ui::SCALE_FACTOR_100P);
283 }
284 return gfx::ImageSkiaRep( 313 return gfx::ImageSkiaRep(
285 SkBitmapOperations::CreateButtonBackground(color_, 314 SkBitmapOperations::CreateButtonBackground(color_,
286 image_rep.sk_bitmap(), mask_rep.sk_bitmap()), 315 first_rep.sk_bitmap(), second_rep.sk_bitmap()),
287 image_rep.scale_factor()); 316 first_rep.scale_factor());
288 } 317 }
289 318
290 private: 319 private:
291 const SkColor color_; 320 const SkColor color_;
292 const ImageSkia image_;
293 const ImageSkia mask_;
294 321
295 DISALLOW_COPY_AND_ASSIGN(ButtonImageSource); 322 DISALLOW_COPY_AND_ASSIGN(ButtonImageSource);
296 }; 323 };
297 324
298 // ImageSkiaSource which uses SkBitmap::extractSubset to generate image reps 325 // ImageSkiaSource which uses SkBitmap::extractSubset to generate image reps
299 // for the target image. 326 // for the target image.
300 class ExtractSubsetImageSource: public gfx::ImageSkiaSource { 327 class ExtractSubsetImageSource: public gfx::ImageSkiaSource {
301 public: 328 public:
302 ExtractSubsetImageSource(const gfx::ImageSkia& image, 329 ExtractSubsetImageSource(const gfx::ImageSkia& image,
303 const gfx::Rect& subset_bounds) 330 const gfx::Rect& subset_bounds)
304 : image_(image), 331 : image_(image),
305 subset_bounds_(subset_bounds) { 332 subset_bounds_(subset_bounds) {
306 } 333 }
307 334
308 virtual ~ExtractSubsetImageSource() { 335 virtual ~ExtractSubsetImageSource() {
309 } 336 }
310 337
311 // gfx::ImageSkiaSource overrides: 338 // gfx::ImageSkiaSource overrides:
312 virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { 339 virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE {
313 ImageSkiaRep image_rep = image_.GetRepresentation(scale_factor); 340 ImageSkiaRep image_rep = image_.GetRepresentation(scale_factor);
314 float scale_to_pixel = ui::GetScaleFactorScale(image_rep.scale_factor()); 341 float scale_to_pixel = ui::GetScaleFactorScale(image_rep.scale_factor());
315 SkIRect subset_bounds_in_pixel = RectToSkIRect(ToFlooredRectDeprecated( 342 Rect subset_bounds_in_pixel = DIPToPixelBounds(subset_bounds_,
316 gfx::ScaleRect(subset_bounds_, scale_to_pixel))); 343 scale_to_pixel);
317 SkBitmap dst; 344 return CropBitmap(image_rep, subset_bounds_in_pixel);
318 bool success = image_rep.sk_bitmap().extractSubset(&dst,
319 subset_bounds_in_pixel);
320 DCHECK(success);
321 return gfx::ImageSkiaRep(dst, image_rep.scale_factor());
322 } 345 }
323 346
324 private: 347 private:
325 const gfx::ImageSkia image_; 348 const gfx::ImageSkia image_;
326 const gfx::Rect subset_bounds_; 349 const gfx::Rect subset_bounds_;
327 350
328 DISALLOW_COPY_AND_ASSIGN(ExtractSubsetImageSource); 351 DISALLOW_COPY_AND_ASSIGN(ExtractSubsetImageSource);
329 }; 352 };
330 353
331 // ResizeSource resizes relevant image reps in |source| to |target_dip_size| 354 // ResizeSource resizes relevant image reps in |source| to |target_dip_size|
(...skipping 10 matching lines...) Expand all
342 virtual ~ResizeSource() {} 365 virtual ~ResizeSource() {}
343 366
344 // gfx::ImageSkiaSource overrides: 367 // gfx::ImageSkiaSource overrides:
345 virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { 368 virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE {
346 const ImageSkiaRep& image_rep = source_.GetRepresentation(scale_factor); 369 const ImageSkiaRep& image_rep = source_.GetRepresentation(scale_factor);
347 if (image_rep.GetWidth() == target_dip_size_.width() && 370 if (image_rep.GetWidth() == target_dip_size_.width() &&
348 image_rep.GetHeight() == target_dip_size_.height()) 371 image_rep.GetHeight() == target_dip_size_.height())
349 return image_rep; 372 return image_rep;
350 373
351 const float scale = ui::GetScaleFactorScale(scale_factor); 374 const float scale = ui::GetScaleFactorScale(scale_factor);
352 const Size target_pixel_size = gfx::ToFlooredSize( 375 const Size target_pixel_size = DIPToPixelSize(target_dip_size_, scale);
353 gfx::ScaleSize(target_dip_size_, scale));
354 const SkBitmap resized = skia::ImageOperations::Resize( 376 const SkBitmap resized = skia::ImageOperations::Resize(
355 image_rep.sk_bitmap(), 377 image_rep.sk_bitmap(),
356 resize_method_, 378 resize_method_,
357 target_pixel_size.width(), 379 target_pixel_size.width(),
358 target_pixel_size.height()); 380 target_pixel_size.height());
359 return ImageSkiaRep(resized, scale_factor); 381 return ImageSkiaRep(resized, scale_factor);
360 } 382 }
361 383
362 private: 384 private:
363 const ImageSkia source_; 385 const ImageSkia source_;
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
545 return ImageSkia(); 567 return ImageSkia();
546 568
547 return ImageSkia(new RotatedSource(source, rotation), 569 return ImageSkia(new RotatedSource(source, rotation),
548 SkBitmapOperations::ROTATION_180_CW == rotation ? 570 SkBitmapOperations::ROTATION_180_CW == rotation ?
549 source.size() : 571 source.size() :
550 gfx::Size(source.height(), source.width())); 572 gfx::Size(source.height(), source.width()));
551 573
552 } 574 }
553 575
554 } // namespace gfx 576 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/canvas.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698