| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/gfx/image/image_skia_operations.h" |
| |
| #include <stddef.h> |
| #include <memory> |
| |
| #include "base/command_line.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "skia/ext/image_operations.h" |
| #include "third_party/skia/include/core/SkClipOp.h" |
| #include "third_party/skia/include/core/SkDrawLooper.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/color_palette.h" |
| #include "ui/gfx/geometry/insets.h" |
| #include "ui/gfx/geometry/point.h" |
| #include "ui/gfx/geometry/point_conversions.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/rect_conversions.h" |
| #include "ui/gfx/geometry/size.h" |
| #include "ui/gfx/geometry/size_conversions.h" |
| #include "ui/gfx/geometry/skia_conversions.h" |
| #include "ui/gfx/image/canvas_image_source.h" |
| #include "ui/gfx/image/image_skia.h" |
| #include "ui/gfx/image/image_skia_rep.h" |
| #include "ui/gfx/image/image_skia_source.h" |
| #include "ui/gfx/skbitmap_operations.h" |
| #include "ui/gfx/skia_paint_util.h" |
| |
| namespace gfx { |
| namespace { |
| |
| gfx::Size DIPToPixelSize(gfx::Size dip_size, float scale) { |
| return ScaleToCeiledSize(dip_size, scale); |
| } |
| |
| gfx::Rect DIPToPixelBounds(gfx::Rect dip_bounds, float scale) { |
| return gfx::Rect(ScaleToFlooredPoint(dip_bounds.origin(), scale), |
| DIPToPixelSize(dip_bounds.size(), scale)); |
| } |
| |
| // Returns an image rep for the ImageSkiaSource to return to visually indicate |
| // an error. |
| ImageSkiaRep GetErrorImageRep(float scale, const gfx::Size& pixel_size) { |
| SkBitmap bitmap; |
| bitmap.allocN32Pixels(pixel_size.width(), pixel_size.height()); |
| bitmap.eraseColor(kPlaceholderColor); |
| return gfx::ImageSkiaRep(bitmap, scale); |
| } |
| |
| // A base image source class that creates an image from two source images. |
| // This class guarantees that two ImageSkiaReps have have the same pixel size. |
| class BinaryImageSource : public gfx::ImageSkiaSource { |
| protected: |
| BinaryImageSource(const ImageSkia& first, |
| const ImageSkia& second, |
| const char* source_name) |
| : first_(first), |
| second_(second), |
| source_name_(source_name) { |
| } |
| |
| BinaryImageSource(const BinaryImageSource&) = delete; |
| BinaryImageSource& operator=(const BinaryImageSource&) = delete; |
| |
| ~BinaryImageSource() override {} |
| |
| // gfx::ImageSkiaSource overrides: |
| ImageSkiaRep GetImageForScale(float scale) override { |
| ImageSkiaRep first_rep = first_.GetRepresentation(scale); |
| if (first_rep.is_null()) |
| return first_rep; |
| ImageSkiaRep second_rep = second_.GetRepresentation(scale); |
| if (second_rep.is_null()) |
| return second_rep; |
| |
| if (first_rep.pixel_size() != second_rep.pixel_size()) { |
| DCHECK_NE(first_rep.scale(), second_rep.scale()); |
| if (first_rep.scale() == second_rep.scale()) { |
| LOG(ERROR) << "ImageSkiaRep size mismatch in " << source_name_; |
| return GetErrorImageRep(first_rep.scale(),first_rep.pixel_size()); |
| } |
| first_rep = first_.GetRepresentation(1.0f); |
| second_rep = second_.GetRepresentation(1.0f); |
| DCHECK_EQ(first_rep.pixel_width(), second_rep.pixel_width()); |
| DCHECK_EQ(first_rep.pixel_height(), second_rep.pixel_height()); |
| if (first_rep.pixel_size() != second_rep.pixel_size()) { |
| LOG(ERROR) << "ImageSkiaRep size mismatch in " << source_name_; |
| return GetErrorImageRep(first_rep.scale(), first_rep.pixel_size()); |
| } |
| } else { |
| DCHECK_EQ(first_rep.scale(), second_rep.scale()); |
| } |
| return CreateImageSkiaRep(first_rep, second_rep); |
| } |
| |
| // Creates a final image from two ImageSkiaReps. The pixel size of |
| // the two images are guaranteed to be the same. |
| virtual ImageSkiaRep CreateImageSkiaRep( |
| const ImageSkiaRep& first_rep, |
| const ImageSkiaRep& second_rep) const = 0; |
| |
| private: |
| const ImageSkia first_; |
| const ImageSkia second_; |
| // The name of a class that implements the BinaryImageSource. |
| // The subclass is responsible for managing the memory. |
| const char* source_name_; |
| }; |
| |
| class BlendingImageSource : public BinaryImageSource { |
| public: |
| BlendingImageSource(const ImageSkia& first, |
| const ImageSkia& second, |
| double alpha) |
| : BinaryImageSource(first, second, "BlendingImageSource"), |
| alpha_(alpha) { |
| } |
| |
| BlendingImageSource(const BlendingImageSource&) = delete; |
| BlendingImageSource& operator=(const BlendingImageSource&) = delete; |
| |
| ~BlendingImageSource() override {} |
| |
| // BinaryImageSource overrides: |
| ImageSkiaRep CreateImageSkiaRep( |
| const ImageSkiaRep& first_rep, |
| const ImageSkiaRep& second_rep) const override { |
| SkBitmap blended = SkBitmapOperations::CreateBlendedBitmap( |
| first_rep.GetBitmap(), second_rep.GetBitmap(), alpha_); |
| return ImageSkiaRep(blended, first_rep.scale()); |
| } |
| |
| private: |
| double alpha_; |
| }; |
| |
| class SuperimposedImageSource : public gfx::CanvasImageSource { |
| public: |
| SuperimposedImageSource(const ImageSkia& first, const ImageSkia& second) |
| : gfx::CanvasImageSource(first.size()), first_(first), second_(second) {} |
| |
| SuperimposedImageSource(const SuperimposedImageSource&) = delete; |
| SuperimposedImageSource& operator=(const SuperimposedImageSource&) = delete; |
| |
| ~SuperimposedImageSource() override {} |
| |
| // gfx::CanvasImageSource override. |
| void Draw(Canvas* canvas) override { |
| canvas->DrawImageInt(first_, 0, 0); |
| canvas->DrawImageInt(second_, |
| (first_.width() - second_.width()) / 2, |
| (first_.height() - second_.height()) / 2); |
| } |
| |
| private: |
| const ImageSkia first_; |
| const ImageSkia second_; |
| }; |
| |
| class TransparentImageSource : public gfx::ImageSkiaSource { |
| public: |
| TransparentImageSource(const ImageSkia& image, double alpha) |
| : image_(image), |
| alpha_(alpha) { |
| } |
| |
| TransparentImageSource(const TransparentImageSource&) = delete; |
| TransparentImageSource& operator=(const TransparentImageSource&) = delete; |
| |
| ~TransparentImageSource() override {} |
| |
| private: |
| // gfx::ImageSkiaSource overrides: |
| ImageSkiaRep GetImageForScale(float scale) override { |
| ImageSkiaRep image_rep = image_.GetRepresentation(scale); |
| if (image_rep.is_null()) |
| return image_rep; |
| |
| SkBitmap alpha; |
| alpha.allocN32Pixels(image_rep.pixel_width(), |
| image_rep.pixel_height()); |
| alpha.eraseColor(SkColorSetA(SK_ColorBLACK, SK_AlphaOPAQUE * alpha_)); |
| return ImageSkiaRep( |
| SkBitmapOperations::CreateMaskedBitmap(image_rep.GetBitmap(), alpha), |
| image_rep.scale()); |
| } |
| |
| ImageSkia image_; |
| double alpha_; |
| }; |
| |
| class MaskedImageSource : public BinaryImageSource { |
| public: |
| MaskedImageSource(const ImageSkia& rgb, const ImageSkia& alpha) |
| : BinaryImageSource(rgb, alpha, "MaskedImageSource") { |
| } |
| |
| MaskedImageSource(const MaskedImageSource&) = delete; |
| MaskedImageSource& operator=(const MaskedImageSource&) = delete; |
| |
| ~MaskedImageSource() override {} |
| |
| // BinaryImageSource overrides: |
| ImageSkiaRep CreateImageSkiaRep( |
| const ImageSkiaRep& first_rep, |
| const ImageSkiaRep& second_rep) const override { |
| return ImageSkiaRep(SkBitmapOperations::CreateMaskedBitmap( |
| first_rep.GetBitmap(), second_rep.GetBitmap()), |
| first_rep.scale()); |
| } |
| }; |
| |
| class TiledImageSource : public gfx::ImageSkiaSource { |
| public: |
| TiledImageSource(const ImageSkia& source, |
| int src_x, int src_y, |
| int dst_w, int dst_h) |
| : source_(source), |
| src_x_(src_x), |
| src_y_(src_y), |
| dst_w_(dst_w), |
| dst_h_(dst_h) { |
| } |
| |
| TiledImageSource(const TiledImageSource&) = delete; |
| TiledImageSource& operator=(const TiledImageSource&) = delete; |
| |
| ~TiledImageSource() override {} |
| |
| // gfx::ImageSkiaSource overrides: |
| ImageSkiaRep GetImageForScale(float scale) override { |
| ImageSkiaRep source_rep = source_.GetRepresentation(scale); |
| if (source_rep.is_null()) |
| return source_rep; |
| |
| gfx::Rect bounds = DIPToPixelBounds(gfx::Rect(src_x_, src_y_, dst_w_, |
| dst_h_), source_rep.scale()); |
| return ImageSkiaRep(SkBitmapOperations::CreateTiledBitmap( |
| source_rep.GetBitmap(), bounds.x(), bounds.y(), |
| bounds.width(), bounds.height()), |
| source_rep.scale()); |
| } |
| |
| private: |
| const ImageSkia source_; |
| const int src_x_; |
| const int src_y_; |
| const int dst_w_; |
| const int dst_h_; |
| }; |
| |
| class HSLImageSource : public gfx::ImageSkiaSource { |
| public: |
| HSLImageSource(const ImageSkia& image, |
| const color_utils::HSL& hsl_shift) |
| : image_(image), |
| hsl_shift_(hsl_shift) { |
| } |
| |
| HSLImageSource(const HSLImageSource&) = delete; |
| HSLImageSource& operator=(const HSLImageSource&) = delete; |
| |
| ~HSLImageSource() override {} |
| |
| // gfx::ImageSkiaSource overrides: |
| ImageSkiaRep GetImageForScale(float scale) override { |
| ImageSkiaRep image_rep = image_.GetRepresentation(scale); |
| if (image_rep.is_null()) |
| return image_rep; |
| |
| return gfx::ImageSkiaRep(SkBitmapOperations::CreateHSLShiftedBitmap( |
| image_rep.GetBitmap(), hsl_shift_), |
| image_rep.scale()); |
| } |
| |
| private: |
| const gfx::ImageSkia image_; |
| const color_utils::HSL hsl_shift_; |
| }; |
| |
| // ImageSkiaSource which uses SkBitmapOperations::CreateButtonBackground |
| // to generate image reps for the target image. The image and mask can be |
| // diferent sizes (crbug.com/171725). |
| class ButtonImageSource: public gfx::ImageSkiaSource { |
| public: |
| ButtonImageSource(SkColor color, |
| const ImageSkia& image, |
| const ImageSkia& mask) |
| : color_(color), |
| image_(image), |
| mask_(mask) { |
| } |
| |
| ButtonImageSource(const ButtonImageSource&) = delete; |
| ButtonImageSource& operator=(const ButtonImageSource&) = delete; |
| |
| ~ButtonImageSource() override {} |
| |
| // gfx::ImageSkiaSource overrides: |
| ImageSkiaRep GetImageForScale(float scale) override { |
| ImageSkiaRep image_rep = image_.GetRepresentation(scale); |
| if (image_rep.is_null()) |
| return image_rep; |
| ImageSkiaRep mask_rep = mask_.GetRepresentation(scale); |
| if (mask_rep.is_null()) |
| return image_rep; |
| |
| if (image_rep.scale() != mask_rep.scale()) { |
| image_rep = image_.GetRepresentation(1.0f); |
| mask_rep = mask_.GetRepresentation(1.0f); |
| } |
| return gfx::ImageSkiaRep( |
| SkBitmapOperations::CreateButtonBackground( |
| color_, image_rep.GetBitmap(), mask_rep.GetBitmap()), |
| image_rep.scale()); |
| } |
| |
| private: |
| const SkColor color_; |
| const ImageSkia image_; |
| const ImageSkia mask_; |
| }; |
| |
| // ImageSkiaSource which uses SkBitmap::extractSubset to generate image reps |
| // for the target image. |
| class ExtractSubsetImageSource: public gfx::ImageSkiaSource { |
| public: |
| ExtractSubsetImageSource(const gfx::ImageSkia& image, |
| const gfx::Rect& subset_bounds) |
| : image_(image), |
| subset_bounds_(subset_bounds) { |
| } |
| |
| ExtractSubsetImageSource(const ExtractSubsetImageSource&) = delete; |
| ExtractSubsetImageSource& operator=(const ExtractSubsetImageSource&) = delete; |
| |
| ~ExtractSubsetImageSource() override {} |
| |
| // gfx::ImageSkiaSource overrides: |
| ImageSkiaRep GetImageForScale(float scale) override { |
| ImageSkiaRep image_rep = image_.GetRepresentation(scale); |
| if (image_rep.is_null()) |
| return image_rep; |
| |
| SkIRect subset_bounds_in_pixel = RectToSkIRect( |
| DIPToPixelBounds(subset_bounds_, image_rep.scale())); |
| SkBitmap dst; |
| bool success = |
| image_rep.GetBitmap().extractSubset(&dst, subset_bounds_in_pixel); |
| DCHECK(success); |
| return gfx::ImageSkiaRep(dst, image_rep.scale()); |
| } |
| |
| private: |
| const gfx::ImageSkia image_; |
| const gfx::Rect subset_bounds_; |
| }; |
| |
| // ResizeSource resizes relevant image reps in |source| to |target_dip_size| |
| // for requested scale factors. |
| class ResizeSource : public ImageSkiaSource { |
| public: |
| ResizeSource(const ImageSkia& source, |
| skia::ImageOperations::ResizeMethod method, |
| const Size& target_dip_size) |
| : source_(source), |
| resize_method_(method), |
| target_dip_size_(target_dip_size) { |
| } |
| |
| ResizeSource(const ResizeSource&) = delete; |
| ResizeSource& operator=(const ResizeSource&) = delete; |
| |
| ~ResizeSource() override {} |
| |
| // gfx::ImageSkiaSource overrides: |
| ImageSkiaRep GetImageForScale(float scale) override { |
| const ImageSkiaRep& image_rep = source_.GetRepresentation(scale); |
| if (image_rep.is_null()) |
| return image_rep; |
| if (image_rep.GetWidth() == target_dip_size_.width() && |
| image_rep.GetHeight() == target_dip_size_.height()) |
| return image_rep; |
| |
| const Size target_pixel_size = DIPToPixelSize(target_dip_size_, scale); |
| const SkBitmap resized = skia::ImageOperations::Resize( |
| image_rep.GetBitmap(), resize_method_, target_pixel_size.width(), |
| target_pixel_size.height()); |
| if (resized.colorType() == kUnknown_SkColorType) |
| return ImageSkiaRep(); |
| return ImageSkiaRep(resized, scale); |
| } |
| |
| private: |
| const ImageSkia source_; |
| skia::ImageOperations::ResizeMethod resize_method_; |
| const Size target_dip_size_; |
| }; |
| |
| // DropShadowSource generates image reps with drop shadow for image reps in |
| // |source| that represent requested scale factors. |
| class DropShadowSource : public ImageSkiaSource { |
| public: |
| DropShadowSource(const ImageSkia& source, const ShadowValues& shadows_in_dip) |
| : source_(source), shadows_in_dip_(shadows_in_dip) {} |
| |
| DropShadowSource(const DropShadowSource&) = delete; |
| DropShadowSource& operator=(const DropShadowSource&) = delete; |
| |
| ~DropShadowSource() override {} |
| |
| // gfx::ImageSkiaSource overrides: |
| ImageSkiaRep GetImageForScale(float scale) override { |
| const ImageSkiaRep& image_rep = source_.GetRepresentation(scale); |
| if (image_rep.is_null()) |
| return image_rep; |
| |
| ShadowValues shadows_in_pixel; |
| for (size_t i = 0; i < shadows_in_dip_.size(); ++i) |
| shadows_in_pixel.push_back(shadows_in_dip_[i].Scale(scale)); |
| |
| const SkBitmap shadow_bitmap = SkBitmapOperations::CreateDropShadow( |
| image_rep.GetBitmap(), shadows_in_pixel); |
| return ImageSkiaRep(shadow_bitmap, image_rep.scale()); |
| } |
| |
| private: |
| const ImageSkia source_; |
| const ShadowValues shadows_in_dip_; |
| }; |
| |
| // An image source that is 1px wide, suitable for tiling horizontally. |
| class HorizontalShadowSource : public CanvasImageSource { |
| public: |
| HorizontalShadowSource(const std::vector<ShadowValue>& shadows, |
| bool fades_down) |
| : CanvasImageSource(Size(1, GetHeightForShadows(shadows))), |
| shadows_(shadows), |
| fades_down_(fades_down) {} |
| |
| HorizontalShadowSource(const HorizontalShadowSource&) = delete; |
| HorizontalShadowSource& operator=(const HorizontalShadowSource&) = delete; |
| |
| ~HorizontalShadowSource() override {} |
| |
| // CanvasImageSource overrides: |
| void Draw(Canvas* canvas) override { |
| cc::PaintFlags flags; |
| flags.setLooper(CreateShadowDrawLooper(shadows_)); |
| canvas->DrawRect(RectF(0, fades_down_ ? -1 : size().height(), 1, 1), flags); |
| } |
| |
| private: |
| static int GetHeightForShadows(const std::vector<ShadowValue>& shadows) { |
| int height = 0; |
| for (const auto& shadow : shadows) { |
| height = |
| std::max(height, shadow.y() + base::ClampCeil(shadow.blur() / 2)); |
| } |
| return height; |
| } |
| |
| const std::vector<ShadowValue> shadows_; |
| |
| // The orientation of the shadow (true for shadows that emanate downwards). |
| bool fades_down_; |
| }; |
| |
| // RotatedSource generates image reps that are rotations of those in |
| // |source| that represent requested scale factors. |
| class RotatedSource : public ImageSkiaSource { |
| public: |
| RotatedSource(const ImageSkia& source, |
| SkBitmapOperations::RotationAmount rotation) |
| : source_(source), |
| rotation_(rotation) { |
| } |
| |
| RotatedSource(const RotatedSource&) = delete; |
| RotatedSource& operator=(const RotatedSource&) = delete; |
| |
| ~RotatedSource() override {} |
| |
| // gfx::ImageSkiaSource overrides: |
| ImageSkiaRep GetImageForScale(float scale) override { |
| const ImageSkiaRep& image_rep = source_.GetRepresentation(scale); |
| if (image_rep.is_null()) |
| return image_rep; |
| |
| const SkBitmap rotated_bitmap = |
| SkBitmapOperations::Rotate(image_rep.GetBitmap(), rotation_); |
| return ImageSkiaRep(rotated_bitmap, image_rep.scale()); |
| } |
| |
| private: |
| const ImageSkia source_; |
| const SkBitmapOperations::RotationAmount rotation_; |
| }; |
| |
| class IconWithBadgeSource : public gfx::CanvasImageSource { |
| public: |
| IconWithBadgeSource(const ImageSkia& icon, const ImageSkia& badge) |
| : gfx::CanvasImageSource(icon.size()), icon_(icon), badge_(badge) {} |
| |
| IconWithBadgeSource(const IconWithBadgeSource&) = delete; |
| IconWithBadgeSource& operator=(const IconWithBadgeSource&) = delete; |
| |
| ~IconWithBadgeSource() override {} |
| |
| // gfx::CanvasImageSource override. |
| void Draw(Canvas* canvas) override { |
| canvas->DrawImageInt(icon_, 0, 0); |
| canvas->DrawImageInt(badge_, (icon_.width() - badge_.width()), |
| (icon_.height() - badge_.height())); |
| } |
| |
| private: |
| const ImageSkia icon_; |
| const ImageSkia badge_; |
| }; |
| |
| // ImageSkiaSource which uses SkBitmapOperations::CreateColorMask |
| // to generate image reps for the target image. |
| class ColorMaskSource : public gfx::ImageSkiaSource { |
| public: |
| ColorMaskSource(const ImageSkia& image, SkColor color) |
| : image_(image), color_(color) {} |
| |
| ColorMaskSource(const ColorMaskSource&) = delete; |
| ColorMaskSource& operator=(const ColorMaskSource&) = delete; |
| |
| ~ColorMaskSource() override {} |
| |
| // gfx::ImageSkiaSource overrides: |
| ImageSkiaRep GetImageForScale(float scale) override { |
| ImageSkiaRep image_rep = image_.GetRepresentation(scale); |
| if (image_rep.is_null()) |
| return image_rep; |
| |
| return ImageSkiaRep( |
| SkBitmapOperations::CreateColorMask(image_rep.GetBitmap(), color_), |
| image_rep.scale()); |
| } |
| |
| private: |
| const ImageSkia image_; |
| const SkColor color_; |
| }; |
| |
| // Image source to create an image with a circle background. |
| class ImageWithCircleBackgroundSource : public gfx::CanvasImageSource { |
| public: |
| ImageWithCircleBackgroundSource(int radius, |
| SkColor color, |
| const gfx::ImageSkia& image) |
| : gfx::CanvasImageSource(gfx::Size(radius * 2, radius * 2)), |
| radius_(radius), |
| color_(color), |
| image_(image) {} |
| |
| ImageWithCircleBackgroundSource(const ImageWithCircleBackgroundSource&) = |
| delete; |
| ImageWithCircleBackgroundSource& operator=( |
| const ImageWithCircleBackgroundSource&) = delete; |
| |
| ~ImageWithCircleBackgroundSource() override = default; |
| |
| // gfx::CanvasImageSource: |
| void Draw(gfx::Canvas* canvas) override { |
| cc::PaintFlags flags; |
| flags.setAntiAlias(true); |
| flags.setStyle(cc::PaintFlags::kFill_Style); |
| flags.setColor(color_); |
| canvas->DrawCircle(gfx::Point(radius_, radius_), radius_, flags); |
| const int x = radius_ - image_.width() / 2; |
| const int y = radius_ - image_.height() / 2; |
| canvas->DrawImageInt(image_, x, y); |
| } |
| |
| private: |
| const int radius_; |
| const SkColor color_; |
| const gfx::ImageSkia image_; |
| }; |
| } // namespace |
| |
| // static |
| ImageSkia ImageSkiaOperations::CreateBlendedImage(const ImageSkia& first, |
| const ImageSkia& second, |
| double alpha) { |
| if (first.isNull() || second.isNull()) |
| return ImageSkia(); |
| |
| return ImageSkia(std::make_unique<BlendingImageSource>(first, second, alpha), |
| first.size()); |
| } |
| |
| // static |
| ImageSkia ImageSkiaOperations::CreateSuperimposedImage( |
| const ImageSkia& first, |
| const ImageSkia& second) { |
| if (first.isNull() || second.isNull()) |
| return ImageSkia(); |
| |
| return ImageSkia(std::make_unique<SuperimposedImageSource>(first, second), |
| first.size()); |
| } |
| |
| // static |
| ImageSkia ImageSkiaOperations::CreateTransparentImage(const ImageSkia& image, |
| double alpha) { |
| if (image.isNull()) |
| return ImageSkia(); |
| |
| return ImageSkia(std::make_unique<TransparentImageSource>(image, alpha), |
| image.size()); |
| } |
| |
| // static |
| ImageSkia ImageSkiaOperations::CreateMaskedImage(const ImageSkia& rgb, |
| const ImageSkia& alpha) { |
| if (rgb.isNull() || alpha.isNull()) |
| return ImageSkia(); |
| |
| return ImageSkia(std::make_unique<MaskedImageSource>(rgb, alpha), rgb.size()); |
| } |
| |
| // static |
| ImageSkia ImageSkiaOperations::CreateTiledImage(const ImageSkia& source, |
| int src_x, int src_y, |
| int dst_w, int dst_h) { |
| if (source.isNull()) |
| return ImageSkia(); |
| |
| return ImageSkia( |
| std::make_unique<TiledImageSource>(source, src_x, src_y, dst_w, dst_h), |
| gfx::Size(dst_w, dst_h)); |
| } |
| |
| // static |
| ImageSkia ImageSkiaOperations::CreateHSLShiftedImage( |
| const ImageSkia& image, |
| const color_utils::HSL& hsl_shift) { |
| if (image.isNull()) |
| return ImageSkia(); |
| |
| return ImageSkia(std::make_unique<HSLImageSource>(image, hsl_shift), |
| image.size()); |
| } |
| |
| // static |
| ImageSkia ImageSkiaOperations::CreateButtonBackground(SkColor color, |
| const ImageSkia& image, |
| const ImageSkia& mask) { |
| if (image.isNull() || mask.isNull()) |
| return ImageSkia(); |
| |
| return ImageSkia(std::make_unique<ButtonImageSource>(color, image, mask), |
| mask.size()); |
| } |
| |
| // static |
| ImageSkia ImageSkiaOperations::ExtractSubset(const ImageSkia& image, |
| const Rect& subset_bounds) { |
| gfx::Rect clipped_bounds = |
| gfx::IntersectRects(subset_bounds, gfx::Rect(image.size())); |
| if (image.isNull() || clipped_bounds.IsEmpty()) |
| return ImageSkia(); |
| if (clipped_bounds == gfx::Rect(image.size())) |
| return image; |
| |
| return ImageSkia( |
| std::make_unique<ExtractSubsetImageSource>(image, clipped_bounds), |
| clipped_bounds.size()); |
| } |
| |
| // static |
| ImageSkia ImageSkiaOperations::CreateResizedImage( |
| const ImageSkia& source, |
| skia::ImageOperations::ResizeMethod method, |
| const Size& target_dip_size) { |
| if (source.isNull()) |
| return ImageSkia(); |
| if (source.size() == target_dip_size) |
| return source; |
| |
| return ImageSkia( |
| std::make_unique<ResizeSource>(source, method, target_dip_size), |
| target_dip_size); |
| } |
| |
| // static |
| ImageSkia ImageSkiaOperations::CreateImageWithDropShadow( |
| const ImageSkia& source, |
| const ShadowValues& shadows) { |
| if (source.isNull()) |
| return ImageSkia(); |
| |
| const gfx::Insets shadow_padding = -gfx::ShadowValue::GetMargin(shadows); |
| gfx::Size shadow_image_size = source.size(); |
| shadow_image_size.Enlarge(shadow_padding.width(), |
| shadow_padding.height()); |
| return ImageSkia(std::make_unique<DropShadowSource>(source, shadows), |
| shadow_image_size); |
| } |
| |
| // static |
| ImageSkia ImageSkiaOperations::CreateHorizontalShadow( |
| const std::vector<ShadowValue>& shadows, |
| bool fades_down) { |
| auto* source = new HorizontalShadowSource(shadows, fades_down); |
| return ImageSkia(base::WrapUnique(source), source->size()); |
| } |
| |
| // static |
| ImageSkia ImageSkiaOperations::CreateRotatedImage( |
| const ImageSkia& source, |
| SkBitmapOperations::RotationAmount rotation) { |
| if (source.isNull()) |
| return ImageSkia(); |
| |
| return ImageSkia(std::make_unique<RotatedSource>(source, rotation), |
| SkBitmapOperations::ROTATION_180_CW == rotation |
| ? source.size() |
| : gfx::Size(source.height(), source.width())); |
| } |
| |
| // static |
| ImageSkia ImageSkiaOperations::CreateIconWithBadge(const ImageSkia& icon, |
| const ImageSkia& badge) { |
| if (icon.isNull()) |
| return ImageSkia(); |
| |
| if (badge.isNull()) |
| return icon; |
| |
| return ImageSkia(std::make_unique<IconWithBadgeSource>(icon, badge), |
| icon.size()); |
| } |
| |
| // static |
| ImageSkia ImageSkiaOperations::CreateColorMask(const ImageSkia& image, |
| SkColor color) { |
| if (image.isNull()) |
| return ImageSkia(); |
| |
| return ImageSkia(std::make_unique<ColorMaskSource>(image, color), |
| image.size()); |
| } |
| |
| ImageSkia ImageSkiaOperations::CreateImageWithCircleBackground( |
| int radius, |
| SkColor color, |
| const ImageSkia& image) { |
| DCHECK_GE(radius * 2, image.width()); |
| DCHECK_GE(radius * 2, image.height()); |
| return gfx::CanvasImageSource::MakeImageSkia<ImageWithCircleBackgroundSource>( |
| radius, color, image); |
| } |
| } // namespace gfx |