Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ui / gfx / image / image_skia_operations.cc
blobc7e0eecf8d5ab23a6287b94c032a06311dd85f08
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
3 // found in the LICENSE file.
5 #include "ui/gfx/image/image_skia_operations.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "skia/ext/image_operations.h"
10 #include "ui/gfx/canvas.h"
11 #include "ui/gfx/image/canvas_image_source.h"
12 #include "ui/gfx/image/image_skia.h"
13 #include "ui/gfx/image/image_skia_rep.h"
14 #include "ui/gfx/image/image_skia_source.h"
15 #include "ui/gfx/insets.h"
16 #include "ui/gfx/point.h"
17 #include "ui/gfx/point_conversions.h"
18 #include "ui/gfx/rect.h"
19 #include "ui/gfx/rect_conversions.h"
20 #include "ui/gfx/size.h"
21 #include "ui/gfx/size_conversions.h"
22 #include "ui/gfx/skbitmap_operations.h"
23 #include "ui/gfx/skia_util.h"
25 namespace gfx {
26 namespace {
28 gfx::Size DIPToPixelSize(gfx::Size dip_size, float scale) {
29 return ToCeiledSize(ScaleSize(dip_size, scale));
32 gfx::Rect DIPToPixelBounds(gfx::Rect dip_bounds, float scale) {
33 return gfx::Rect(ToFlooredPoint(ScalePoint(dip_bounds.origin(), scale)),
34 DIPToPixelSize(dip_bounds.size(), scale));
37 // Returns an image rep for the ImageSkiaSource to return to visually indicate
38 // an error.
39 ImageSkiaRep GetErrorImageRep(float scale, const gfx::Size& pixel_size) {
40 SkBitmap bitmap;
41 bitmap.allocN32Pixels(pixel_size.width(), pixel_size.height());
42 bitmap.eraseColor(SK_ColorRED);
43 return gfx::ImageSkiaRep(bitmap, scale);
46 // A base image source class that creates an image from two source images.
47 // This class guarantees that two ImageSkiaReps have have the same pixel size.
48 class BinaryImageSource : public gfx::ImageSkiaSource {
49 protected:
50 BinaryImageSource(const ImageSkia& first,
51 const ImageSkia& second,
52 const char* source_name)
53 : first_(first),
54 second_(second),
55 source_name_(source_name) {
57 virtual ~BinaryImageSource() {
60 // gfx::ImageSkiaSource overrides:
61 virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
62 ImageSkiaRep first_rep = first_.GetRepresentation(scale);
63 ImageSkiaRep second_rep = second_.GetRepresentation(scale);
64 if (first_rep.pixel_size() != second_rep.pixel_size()) {
65 DCHECK_NE(first_rep.scale(), second_rep.scale());
66 if (first_rep.scale() == second_rep.scale()) {
67 LOG(ERROR) << "ImageSkiaRep size mismatch in " << source_name_;
68 return GetErrorImageRep(first_rep.scale(),first_rep.pixel_size());
70 first_rep = first_.GetRepresentation(1.0f);
71 second_rep = second_.GetRepresentation(1.0f);
72 DCHECK_EQ(first_rep.pixel_width(), second_rep.pixel_width());
73 DCHECK_EQ(first_rep.pixel_height(), second_rep.pixel_height());
74 if (first_rep.pixel_size() != second_rep.pixel_size()) {
75 LOG(ERROR) << "ImageSkiaRep size mismatch in " << source_name_;
76 return GetErrorImageRep(first_rep.scale(), first_rep.pixel_size());
78 } else {
79 DCHECK_EQ(first_rep.scale(), second_rep.scale());
81 return CreateImageSkiaRep(first_rep, second_rep);
84 // Creates a final image from two ImageSkiaReps. The pixel size of
85 // the two images are guaranteed to be the same.
86 virtual ImageSkiaRep CreateImageSkiaRep(
87 const ImageSkiaRep& first_rep,
88 const ImageSkiaRep& second_rep) const = 0;
90 private:
91 const ImageSkia first_;
92 const ImageSkia second_;
93 // The name of a class that implements the BinaryImageSource.
94 // The subclass is responsible for managing the memory.
95 const char* source_name_;
97 DISALLOW_COPY_AND_ASSIGN(BinaryImageSource);
100 class BlendingImageSource : public BinaryImageSource {
101 public:
102 BlendingImageSource(const ImageSkia& first,
103 const ImageSkia& second,
104 double alpha)
105 : BinaryImageSource(first, second, "BlendingImageSource"),
106 alpha_(alpha) {
109 virtual ~BlendingImageSource() {
112 // BinaryImageSource overrides:
113 virtual ImageSkiaRep CreateImageSkiaRep(
114 const ImageSkiaRep& first_rep,
115 const ImageSkiaRep& second_rep) const OVERRIDE {
116 SkBitmap blended = SkBitmapOperations::CreateBlendedBitmap(
117 first_rep.sk_bitmap(), second_rep.sk_bitmap(), alpha_);
118 return ImageSkiaRep(blended, first_rep.scale());
121 private:
122 double alpha_;
124 DISALLOW_COPY_AND_ASSIGN(BlendingImageSource);
127 class SuperimposedImageSource : public gfx::CanvasImageSource {
128 public:
129 SuperimposedImageSource(const ImageSkia& first,
130 const ImageSkia& second)
131 : gfx::CanvasImageSource(first.size(), false /* is opaque */),
132 first_(first),
133 second_(second) {
136 virtual ~SuperimposedImageSource() {}
138 // gfx::CanvasImageSource override.
139 virtual void Draw(Canvas* canvas) OVERRIDE {
140 canvas->DrawImageInt(first_, 0, 0);
141 canvas->DrawImageInt(second_,
142 (first_.width() - second_.width()) / 2,
143 (first_.height() - second_.height()) / 2);
146 private:
147 const ImageSkia first_;
148 const ImageSkia second_;
150 DISALLOW_COPY_AND_ASSIGN(SuperimposedImageSource);
153 class TransparentImageSource : public gfx::ImageSkiaSource {
154 public:
155 TransparentImageSource(const ImageSkia& image, double alpha)
156 : image_(image),
157 alpha_(alpha) {
160 virtual ~TransparentImageSource() {}
162 private:
163 // gfx::ImageSkiaSource overrides:
164 virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
165 ImageSkiaRep image_rep = image_.GetRepresentation(scale);
166 SkBitmap alpha;
167 alpha.allocN32Pixels(image_rep.pixel_width(),
168 image_rep.pixel_height());
169 alpha.eraseColor(SkColorSetARGB(alpha_ * 255, 0, 0, 0));
170 return ImageSkiaRep(
171 SkBitmapOperations::CreateMaskedBitmap(image_rep.sk_bitmap(), alpha),
172 image_rep.scale());
175 ImageSkia image_;
176 double alpha_;
178 DISALLOW_COPY_AND_ASSIGN(TransparentImageSource);
181 class MaskedImageSource : public BinaryImageSource {
182 public:
183 MaskedImageSource(const ImageSkia& rgb, const ImageSkia& alpha)
184 : BinaryImageSource(rgb, alpha, "MaskedImageSource") {
187 virtual ~MaskedImageSource() {
190 // BinaryImageSource overrides:
191 virtual ImageSkiaRep CreateImageSkiaRep(
192 const ImageSkiaRep& first_rep,
193 const ImageSkiaRep& second_rep) const OVERRIDE {
194 return ImageSkiaRep(SkBitmapOperations::CreateMaskedBitmap(
195 first_rep.sk_bitmap(), second_rep.sk_bitmap()),
196 first_rep.scale());
199 private:
200 DISALLOW_COPY_AND_ASSIGN(MaskedImageSource);
203 class TiledImageSource : public gfx::ImageSkiaSource {
204 public:
205 TiledImageSource(const ImageSkia& source,
206 int src_x, int src_y,
207 int dst_w, int dst_h)
208 : source_(source),
209 src_x_(src_x),
210 src_y_(src_y),
211 dst_w_(dst_w),
212 dst_h_(dst_h) {
215 virtual ~TiledImageSource() {
218 // gfx::ImageSkiaSource overrides:
219 virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
220 ImageSkiaRep source_rep = source_.GetRepresentation(scale);
221 gfx::Rect bounds = DIPToPixelBounds(gfx::Rect(src_x_, src_y_, dst_w_,
222 dst_h_), source_rep.scale());
223 return ImageSkiaRep(
224 SkBitmapOperations::CreateTiledBitmap(
225 source_rep.sk_bitmap(),
226 bounds.x(), bounds.y(), bounds.width(), bounds.height()),
227 source_rep.scale());
230 private:
231 const ImageSkia source_;
232 const int src_x_;
233 const int src_y_;
234 const int dst_w_;
235 const int dst_h_;
237 DISALLOW_COPY_AND_ASSIGN(TiledImageSource);
240 class HSLImageSource : public gfx::ImageSkiaSource {
241 public:
242 HSLImageSource(const ImageSkia& image,
243 const color_utils::HSL& hsl_shift)
244 : image_(image),
245 hsl_shift_(hsl_shift) {
248 virtual ~HSLImageSource() {
251 // gfx::ImageSkiaSource overrides:
252 virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
253 ImageSkiaRep image_rep = image_.GetRepresentation(scale);
254 return gfx::ImageSkiaRep(
255 SkBitmapOperations::CreateHSLShiftedBitmap(image_rep.sk_bitmap(),
256 hsl_shift_), image_rep.scale());
259 private:
260 const gfx::ImageSkia image_;
261 const color_utils::HSL hsl_shift_;
262 DISALLOW_COPY_AND_ASSIGN(HSLImageSource);
265 // ImageSkiaSource which uses SkBitmapOperations::CreateButtonBackground
266 // to generate image reps for the target image. The image and mask can be
267 // diferent sizes (crbug.com/171725).
268 class ButtonImageSource: public gfx::ImageSkiaSource {
269 public:
270 ButtonImageSource(SkColor color,
271 const ImageSkia& image,
272 const ImageSkia& mask)
273 : color_(color),
274 image_(image),
275 mask_(mask) {
278 virtual ~ButtonImageSource() {
281 // gfx::ImageSkiaSource overrides:
282 virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
283 ImageSkiaRep image_rep = image_.GetRepresentation(scale);
284 ImageSkiaRep mask_rep = mask_.GetRepresentation(scale);
285 if (image_rep.scale() != mask_rep.scale()) {
286 image_rep = image_.GetRepresentation(1.0f);
287 mask_rep = mask_.GetRepresentation(1.0f);
289 return gfx::ImageSkiaRep(
290 SkBitmapOperations::CreateButtonBackground(color_,
291 image_rep.sk_bitmap(), mask_rep.sk_bitmap()),
292 image_rep.scale());
295 private:
296 const SkColor color_;
297 const ImageSkia image_;
298 const ImageSkia mask_;
300 DISALLOW_COPY_AND_ASSIGN(ButtonImageSource);
303 // ImageSkiaSource which uses SkBitmap::extractSubset to generate image reps
304 // for the target image.
305 class ExtractSubsetImageSource: public gfx::ImageSkiaSource {
306 public:
307 ExtractSubsetImageSource(const gfx::ImageSkia& image,
308 const gfx::Rect& subset_bounds)
309 : image_(image),
310 subset_bounds_(subset_bounds) {
313 virtual ~ExtractSubsetImageSource() {
316 // gfx::ImageSkiaSource overrides:
317 virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
318 ImageSkiaRep image_rep = image_.GetRepresentation(scale);
319 SkIRect subset_bounds_in_pixel = RectToSkIRect(
320 DIPToPixelBounds(subset_bounds_, image_rep.scale()));
321 SkBitmap dst;
322 bool success = image_rep.sk_bitmap().extractSubset(&dst,
323 subset_bounds_in_pixel);
324 DCHECK(success);
325 return gfx::ImageSkiaRep(dst, image_rep.scale());
328 private:
329 const gfx::ImageSkia image_;
330 const gfx::Rect subset_bounds_;
332 DISALLOW_COPY_AND_ASSIGN(ExtractSubsetImageSource);
335 // ResizeSource resizes relevant image reps in |source| to |target_dip_size|
336 // for requested scale factors.
337 class ResizeSource : public ImageSkiaSource {
338 public:
339 ResizeSource(const ImageSkia& source,
340 skia::ImageOperations::ResizeMethod method,
341 const Size& target_dip_size)
342 : source_(source),
343 resize_method_(method),
344 target_dip_size_(target_dip_size) {
346 virtual ~ResizeSource() {}
348 // gfx::ImageSkiaSource overrides:
349 virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
350 const ImageSkiaRep& image_rep = source_.GetRepresentation(scale);
351 if (image_rep.GetWidth() == target_dip_size_.width() &&
352 image_rep.GetHeight() == target_dip_size_.height())
353 return image_rep;
355 const Size target_pixel_size = DIPToPixelSize(target_dip_size_, scale);
356 const SkBitmap resized = skia::ImageOperations::Resize(
357 image_rep.sk_bitmap(),
358 resize_method_,
359 target_pixel_size.width(),
360 target_pixel_size.height());
361 return ImageSkiaRep(resized, scale);
364 private:
365 const ImageSkia source_;
366 skia::ImageOperations::ResizeMethod resize_method_;
367 const Size target_dip_size_;
369 DISALLOW_COPY_AND_ASSIGN(ResizeSource);
372 // DropShadowSource generates image reps with drop shadow for image reps in
373 // |source| that represent requested scale factors.
374 class DropShadowSource : public ImageSkiaSource {
375 public:
376 DropShadowSource(const ImageSkia& source,
377 const ShadowValues& shadows_in_dip)
378 : source_(source),
379 shaodws_in_dip_(shadows_in_dip) {
381 virtual ~DropShadowSource() {}
383 // gfx::ImageSkiaSource overrides:
384 virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
385 const ImageSkiaRep& image_rep = source_.GetRepresentation(scale);
387 ShadowValues shadows_in_pixel;
388 for (size_t i = 0; i < shaodws_in_dip_.size(); ++i)
389 shadows_in_pixel.push_back(shaodws_in_dip_[i].Scale(scale));
391 const SkBitmap shadow_bitmap = SkBitmapOperations::CreateDropShadow(
392 image_rep.sk_bitmap(),
393 shadows_in_pixel);
394 return ImageSkiaRep(shadow_bitmap, image_rep.scale());
397 private:
398 const ImageSkia source_;
399 const ShadowValues shaodws_in_dip_;
401 DISALLOW_COPY_AND_ASSIGN(DropShadowSource);
404 // RotatedSource generates image reps that are rotations of those in
405 // |source| that represent requested scale factors.
406 class RotatedSource : public ImageSkiaSource {
407 public:
408 RotatedSource(const ImageSkia& source,
409 SkBitmapOperations::RotationAmount rotation)
410 : source_(source),
411 rotation_(rotation) {
413 virtual ~RotatedSource() {}
415 // gfx::ImageSkiaSource overrides:
416 virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
417 const ImageSkiaRep& image_rep = source_.GetRepresentation(scale);
418 const SkBitmap rotated_bitmap =
419 SkBitmapOperations::Rotate(image_rep.sk_bitmap(), rotation_);
420 return ImageSkiaRep(rotated_bitmap, image_rep.scale());
423 private:
424 const ImageSkia source_;
425 const SkBitmapOperations::RotationAmount rotation_;
427 DISALLOW_COPY_AND_ASSIGN(RotatedSource);
431 } // namespace
433 // static
434 ImageSkia ImageSkiaOperations::CreateBlendedImage(const ImageSkia& first,
435 const ImageSkia& second,
436 double alpha) {
437 if (first.isNull() || second.isNull())
438 return ImageSkia();
440 return ImageSkia(new BlendingImageSource(first, second, alpha), first.size());
443 // static
444 ImageSkia ImageSkiaOperations::CreateSuperimposedImage(
445 const ImageSkia& first,
446 const ImageSkia& second) {
447 if (first.isNull() || second.isNull())
448 return ImageSkia();
450 return ImageSkia(new SuperimposedImageSource(first, second), first.size());
453 // static
454 ImageSkia ImageSkiaOperations::CreateTransparentImage(const ImageSkia& image,
455 double alpha) {
456 if (image.isNull())
457 return ImageSkia();
459 return ImageSkia(new TransparentImageSource(image, alpha), image.size());
462 // static
463 ImageSkia ImageSkiaOperations::CreateMaskedImage(const ImageSkia& rgb,
464 const ImageSkia& alpha) {
465 if (rgb.isNull() || alpha.isNull())
466 return ImageSkia();
468 return ImageSkia(new MaskedImageSource(rgb, alpha), rgb.size());
471 // static
472 ImageSkia ImageSkiaOperations::CreateTiledImage(const ImageSkia& source,
473 int src_x, int src_y,
474 int dst_w, int dst_h) {
475 if (source.isNull())
476 return ImageSkia();
478 return ImageSkia(new TiledImageSource(source, src_x, src_y, dst_w, dst_h),
479 gfx::Size(dst_w, dst_h));
482 // static
483 ImageSkia ImageSkiaOperations::CreateHSLShiftedImage(
484 const ImageSkia& image,
485 const color_utils::HSL& hsl_shift) {
486 if (image.isNull())
487 return ImageSkia();
489 return ImageSkia(new HSLImageSource(image, hsl_shift), image.size());
492 // static
493 ImageSkia ImageSkiaOperations::CreateButtonBackground(SkColor color,
494 const ImageSkia& image,
495 const ImageSkia& mask) {
496 if (image.isNull() || mask.isNull())
497 return ImageSkia();
499 return ImageSkia(new ButtonImageSource(color, image, mask), mask.size());
502 // static
503 ImageSkia ImageSkiaOperations::ExtractSubset(const ImageSkia& image,
504 const Rect& subset_bounds) {
505 gfx::Rect clipped_bounds =
506 gfx::IntersectRects(subset_bounds, gfx::Rect(image.size()));
507 if (image.isNull() || clipped_bounds.IsEmpty()) {
508 return ImageSkia();
511 return ImageSkia(new ExtractSubsetImageSource(image, clipped_bounds),
512 clipped_bounds.size());
515 // static
516 ImageSkia ImageSkiaOperations::CreateResizedImage(
517 const ImageSkia& source,
518 skia::ImageOperations::ResizeMethod method,
519 const Size& target_dip_size) {
520 if (source.isNull())
521 return ImageSkia();
523 return ImageSkia(new ResizeSource(source, method, target_dip_size),
524 target_dip_size);
527 // static
528 ImageSkia ImageSkiaOperations::CreateImageWithDropShadow(
529 const ImageSkia& source,
530 const ShadowValues& shadows) {
531 if (source.isNull())
532 return ImageSkia();
534 const gfx::Insets shadow_padding = -gfx::ShadowValue::GetMargin(shadows);
535 gfx::Size shadow_image_size = source.size();
536 shadow_image_size.Enlarge(shadow_padding.width(),
537 shadow_padding.height());
538 return ImageSkia(new DropShadowSource(source, shadows), shadow_image_size);
541 // static
542 ImageSkia ImageSkiaOperations::CreateRotatedImage(
543 const ImageSkia& source,
544 SkBitmapOperations::RotationAmount rotation) {
545 if (source.isNull())
546 return ImageSkia();
548 return ImageSkia(new RotatedSource(source, rotation),
549 SkBitmapOperations::ROTATION_180_CW == rotation ?
550 source.size() :
551 gfx::Size(source.height(), source.width()));
555 } // namespace gfx