root/ui/views/controls/image_view.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GetBitmapPixels
  2. focus_painter_
  3. SetImage
  4. SetImage
  5. GetImage
  6. SetImageSize
  7. GetImageSize
  8. GetImageBounds
  9. ResetImageSize
  10. SetFocusPainter
  11. GetPreferredSize
  12. IsImageEqual
  13. ComputeImageOrigin
  14. OnFocus
  15. OnBlur
  16. OnPaint
  17. GetAccessibleState
  18. SetHorizontalAlignment
  19. GetHorizontalAlignment
  20. SetVerticalAlignment
  21. GetVerticalAlignment
  22. SetTooltipText
  23. GetTooltipText
  24. GetTooltipText
  25. HitTestRect
  26. OnPaintImage

// 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/views/controls/image_view.h"

#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "ui/accessibility/ax_view_state.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/insets.h"
#include "ui/views/painter.h"

namespace views {

namespace {

// Returns the pixels for the bitmap in |image| at scale |image_scale|.
void* GetBitmapPixels(const gfx::ImageSkia& img, float image_scale) {
  DCHECK_NE(0.0f, image_scale);
  const SkBitmap& bitmap = img.GetRepresentation(image_scale).sk_bitmap();
  SkAutoLockPixels pixel_lock(bitmap);
  return bitmap.getPixels();
}

}  // namespace

ImageView::ImageView()
    : image_size_set_(false),
      horiz_alignment_(CENTER),
      vert_alignment_(CENTER),
      interactive_(true),
      last_paint_scale_(0.f),
      last_painted_bitmap_pixels_(NULL),
      focus_painter_(Painter::CreateDashedFocusPainter()) {
}

ImageView::~ImageView() {
}

void ImageView::SetImage(const gfx::ImageSkia& img) {
  if (IsImageEqual(img))
    return;

  last_painted_bitmap_pixels_ = NULL;
  gfx::Size pref_size(GetPreferredSize());
  image_ = img;
  if (pref_size != GetPreferredSize())
    PreferredSizeChanged();
  SchedulePaint();
}

void ImageView::SetImage(const gfx::ImageSkia* image_skia) {
  if (image_skia) {
    SetImage(*image_skia);
  } else {
    gfx::ImageSkia t;
    SetImage(t);
  }
}

const gfx::ImageSkia& ImageView::GetImage() {
  return image_;
}

void ImageView::SetImageSize(const gfx::Size& image_size) {
  image_size_set_ = true;
  image_size_ = image_size;
  PreferredSizeChanged();
}

bool ImageView::GetImageSize(gfx::Size* image_size) {
  DCHECK(image_size);
  if (image_size_set_)
    *image_size = image_size_;
  return image_size_set_;
}

gfx::Rect ImageView::GetImageBounds() const {
  gfx::Size image_size(image_size_set_ ?
    image_size_ : gfx::Size(image_.width(), image_.height()));
  return gfx::Rect(ComputeImageOrigin(image_size), image_size);
}

void ImageView::ResetImageSize() {
  image_size_set_ = false;
}

void ImageView::SetFocusPainter(scoped_ptr<Painter> focus_painter) {
  focus_painter_ = focus_painter.Pass();
}

gfx::Size ImageView::GetPreferredSize() {
  gfx::Insets insets = GetInsets();
  if (image_size_set_) {
    gfx::Size image_size;
    GetImageSize(&image_size);
    image_size.Enlarge(insets.width(), insets.height());
    return image_size;
  }
  return gfx::Size(image_.width() + insets.width(),
                   image_.height() + insets.height());
}

bool ImageView::IsImageEqual(const gfx::ImageSkia& img) const {
  // Even though we copy ImageSkia in SetImage() the backing store
  // (ImageSkiaStorage) is not copied and may have changed since the last call
  // to SetImage(). The expectation is that SetImage() with different pixels is
  // treated as though the image changed. For this reason we compare not only
  // the backing store but also the pixels of the last image we painted.
  return image_.BackedBySameObjectAs(img) &&
      last_paint_scale_ != 0.0f &&
      last_painted_bitmap_pixels_ == GetBitmapPixels(img, last_paint_scale_);
}

gfx::Point ImageView::ComputeImageOrigin(const gfx::Size& image_size) const {
  gfx::Insets insets = GetInsets();

  int x;
  // In order to properly handle alignment of images in RTL locales, we need
  // to flip the meaning of trailing and leading. For example, if the
  // horizontal alignment is set to trailing, then we'll use left alignment for
  // the image instead of right alignment if the UI layout is RTL.
  Alignment actual_horiz_alignment = horiz_alignment_;
  if (base::i18n::IsRTL() && (horiz_alignment_ != CENTER))
    actual_horiz_alignment = (horiz_alignment_ == LEADING) ? TRAILING : LEADING;
  switch (actual_horiz_alignment) {
    case LEADING:  x = insets.left();                                 break;
    case TRAILING: x = width() - insets.right() - image_size.width(); break;
    case CENTER:   x = (width() - image_size.width()) / 2;            break;
    default:       NOTREACHED(); x = 0;                               break;
  }

  int y;
  switch (vert_alignment_) {
    case LEADING:  y = insets.top();                                     break;
    case TRAILING: y = height() - insets.bottom() - image_size.height(); break;
    case CENTER:   y = (height() - image_size.height()) / 2;             break;
    default:       NOTREACHED(); y = 0;                                  break;
  }

  return gfx::Point(x, y);
}

void ImageView::OnFocus() {
  View::OnFocus();
  if (focus_painter_.get())
    SchedulePaint();
}

void ImageView::OnBlur() {
  View::OnBlur();
  if (focus_painter_.get())
    SchedulePaint();
}

void ImageView::OnPaint(gfx::Canvas* canvas) {
  View::OnPaint(canvas);
  OnPaintImage(canvas);
  Painter::PaintFocusPainter(this, canvas, focus_painter_.get());
}

void ImageView::GetAccessibleState(ui::AXViewState* state) {
  state->role = ui::AX_ROLE_IMAGE;
  state->name = tooltip_text_;
}

void ImageView::SetHorizontalAlignment(Alignment ha) {
  if (ha != horiz_alignment_) {
    horiz_alignment_ = ha;
    SchedulePaint();
  }
}

ImageView::Alignment ImageView::GetHorizontalAlignment() const {
  return horiz_alignment_;
}

void ImageView::SetVerticalAlignment(Alignment va) {
  if (va != vert_alignment_) {
    vert_alignment_ = va;
    SchedulePaint();
  }
}

ImageView::Alignment ImageView::GetVerticalAlignment() const {
  return vert_alignment_;
}

void ImageView::SetTooltipText(const base::string16& tooltip) {
  tooltip_text_ = tooltip;
}

base::string16 ImageView::GetTooltipText() const {
  return tooltip_text_;
}

bool ImageView::GetTooltipText(const gfx::Point& p,
                               base::string16* tooltip) const {
  if (tooltip_text_.empty())
    return false;

  *tooltip = GetTooltipText();
  return true;
}

bool ImageView::HitTestRect(const gfx::Rect& rect) const {
  return interactive_ ? View::HitTestRect(rect) : false;
}


void ImageView::OnPaintImage(gfx::Canvas* canvas) {
  last_paint_scale_ = canvas->image_scale();
  last_painted_bitmap_pixels_ = NULL;

  if (image_.isNull())
    return;

  gfx::Rect image_bounds(GetImageBounds());
  if (image_bounds.IsEmpty())
    return;

  if (image_bounds.size() != gfx::Size(image_.width(), image_.height())) {
    // Resize case
    SkPaint paint;
    paint.setFilterBitmap(true);
    canvas->DrawImageInt(image_, 0, 0, image_.width(), image_.height(),
        image_bounds.x(), image_bounds.y(), image_bounds.width(),
        image_bounds.height(), true, paint);
  } else {
    canvas->DrawImageInt(image_, image_bounds.x(), image_bounds.y());
  }
  last_painted_bitmap_pixels_ = GetBitmapPixels(image_, last_paint_scale_);
}

}  // namespace views

/* [<][>][^][v][top][bottom][index][help] */