#include "ui/views/controls/image_view.h"
#include <utility>
#include "base/check_op.h"
#include "base/i18n/rtl.h"
#include "base/numerics/safe_conversions.h"
#include "base/trace_event/trace_event.h"
#include "cc/paint/paint_flags.h"
#include "skia/ext/image_operations.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/themed_vector_icon.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/paint_vector_icon.h"
namespace views {
namespace {
void* GetBitmapPixels(const gfx::ImageSkia& image, float image_scale) {
DCHECK_NE(0.0f, image_scale);
return image.GetRepresentation(image_scale).GetBitmap().getPixels();
}
}
ImageView::ImageView() = default;
ImageView::ImageView(const ui::ImageModel& image_model) {
SetImage(image_model);
}
ImageView::~ImageView() = default;
void ImageView::SetImage(const ui::ImageModel& image_model) {
if (IsImageEqual(image_model))
return;
const gfx::Size pref_size = GetPreferredSize();
image_model_ = image_model;
scaled_image_ = gfx::ImageSkia();
if (pref_size != GetPreferredSize())
PreferredSizeChanged();
SchedulePaint();
}
gfx::ImageSkia ImageView::GetImage() const {
return image_model_.Rasterize(GetColorProvider());
}
ui::ImageModel ImageView::GetImageModel() const {
return image_model_;
}
bool ImageView::IsImageEqual(const ui::ImageModel& image_model) const {
if (image_model != image_model_)
return false;
if (image_model.IsImageGenerator())
return false;
if (!image_model.IsImage())
return true;
return last_paint_scale_ != 0.0f &&
last_painted_bitmap_pixels_ ==
GetBitmapPixels(image_model.GetImage().AsImageSkia(),
last_paint_scale_);
}
gfx::Size ImageView::GetImageSize() const {
return image_size_.value_or(image_model_.Size());
}
void ImageView::OnPaint(gfx::Canvas* canvas) {
TRACE_EVENT1("views", "ImageView::OnPaint", "class", GetClassName());
OnPaintBackground(canvas);
OnPaintImage(canvas);
OnPaintBorder(canvas);
}
void ImageView::OnThemeChanged() {
View::OnThemeChanged();
if (image_model_.IsImageGenerator() ||
(image_model_.IsVectorIcon() &&
!image_model_.GetVectorIcon().has_color())) {
scaled_image_ = gfx::ImageSkia();
SchedulePaint();
}
}
void ImageView::OnPaintImage(gfx::Canvas* canvas) {
last_paint_scale_ = canvas->image_scale();
last_painted_bitmap_pixels_ = nullptr;
gfx::ImageSkia image = GetPaintImage(last_paint_scale_);
if (image.isNull())
return;
gfx::Rect image_bounds(GetImageBounds());
if (image_bounds.IsEmpty())
return;
if (image_bounds.size() != gfx::Size(image.width(), image.height())) {
cc::PaintFlags flags;
flags.setFilterQuality(cc::PaintFlags::FilterQuality::kLow);
canvas->DrawImageInt(image, 0, 0, image.width(), image.height(),
image_bounds.x(), image_bounds.y(),
image_bounds.width(), image_bounds.height(), true,
flags);
} else {
canvas->DrawImageInt(image, image_bounds.x(), image_bounds.y());
}
last_painted_bitmap_pixels_ = GetBitmapPixels(image, last_paint_scale_);
}
gfx::ImageSkia ImageView::GetPaintImage(float scale) {
if (image_model_.IsEmpty())
return gfx::ImageSkia();
if (image_model_.IsImage() || image_model_.IsImageGenerator()) {
const gfx::ImageSkia image = image_model_.Rasterize(GetColorProvider());
if (image.isNull())
return image;
const gfx::ImageSkiaRep& rep = image.GetRepresentation(scale);
if (rep.scale() == scale || rep.unscaled())
return image;
if (scaled_image_.HasRepresentation(scale))
return scaled_image_;
scaled_image_ = gfx::ImageSkia();
gfx::Size scaled_size =
gfx::ScaleToCeiledSize(rep.pixel_size(), scale / rep.scale());
scaled_image_.AddRepresentation(gfx::ImageSkiaRep(
skia::ImageOperations::Resize(
rep.GetBitmap(), skia::ImageOperations::RESIZE_BEST,
scaled_size.width(), scaled_size.height()),
scale));
} else if (scaled_image_.isNull()) {
scaled_image_ = image_model_.Rasterize(GetColorProvider());
}
return scaled_image_;
}
BEGIN_METADATA(ImageView, ImageViewBase)
END_METADATA
}