icon_label_bubble_view.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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.
4
5#include "chrome/browser/ui/views/location_bar/icon_label_bubble_view.h"
6
7#include "base/strings/utf_string_conversions.h"
8#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
9#include "grit/theme_resources.h"
10#include "ui/base/resource/resource_bundle.h"
11#include "ui/gfx/canvas.h"
12#include "ui/gfx/color_utils.h"
13#include "ui/views/controls/image_view.h"
14#include "ui/views/painter.h"
15
16
17IconLabelBubbleView::IconLabelBubbleView(const int background_images[],
18                                         const int hover_background_images[],
19                                         int contained_image,
20                                         const gfx::FontList& font_list,
21                                         SkColor text_color,
22                                         SkColor parent_background_color,
23                                         bool elide_in_middle)
24    : background_painter_(
25          views::Painter::CreateImageGridPainter(background_images)),
26      image_(new views::ImageView()),
27      label_(new views::Label(base::string16(), font_list)),
28      is_extension_icon_(false),
29      in_hover_(false) {
30  image_->SetImage(
31      ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
32          contained_image));
33
34  // Disable separate hit testing for |image_|.  This prevents views treating
35  // |image_| as a separate mouse hover region from |this|.
36  image_->set_interactive(false);
37  AddChildView(image_);
38
39  if (hover_background_images) {
40    hover_background_painter_.reset(
41        views::Painter::CreateImageGridPainter(hover_background_images));
42  }
43
44  label_->SetEnabledColor(text_color);
45  // Calculate the actual background color for the label.  The background images
46  // are painted atop |parent_background_color|.  We grab the color of the
47  // middle pixel of the middle image of the background, which we treat as the
48  // representative color of the entire background (reasonable, given the
49  // current appearance of these images).  Then we alpha-blend it over the
50  // parent background color to determine the actual color the label text will
51  // sit atop.
52  const SkBitmap& bitmap(
53      ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
54          background_images[4])->GetRepresentation(1.0f).sk_bitmap());
55  SkAutoLockPixels pixel_lock(bitmap);
56  SkColor background_image_color =
57      bitmap.getColor(bitmap.width() / 2, bitmap.height() / 2);
58  // Tricky bit: We alpha blend an opaque version of |background_image_color|
59  // against |parent_background_color| using the original image grid color's
60  // alpha. This is because AlphaBlend(a, b, 255) always returns |a| unchanged
61  // even if |a| is a color with non-255 alpha.
62  label_->SetBackgroundColor(
63      color_utils::AlphaBlend(SkColorSetA(background_image_color, 255),
64                              parent_background_color,
65                              SkColorGetA(background_image_color)));
66  if (elide_in_middle)
67    label_->SetElideBehavior(views::Label::ELIDE_IN_MIDDLE);
68  AddChildView(label_);
69}
70
71IconLabelBubbleView::~IconLabelBubbleView() {
72}
73
74void IconLabelBubbleView::SetLabel(const base::string16& label) {
75  label_->SetText(label);
76}
77
78void IconLabelBubbleView::SetImage(const gfx::ImageSkia& image_skia) {
79  image_->SetImage(image_skia);
80}
81
82gfx::Size IconLabelBubbleView::GetPreferredSize() const {
83  // Height will be ignored by the LocationBarView.
84  return GetSizeForLabelWidth(label_->GetPreferredSize().width());
85}
86
87void IconLabelBubbleView::Layout() {
88  image_->SetBounds(GetBubbleOuterPadding(!is_extension_icon_), 0,
89                    image_->GetPreferredSize().width(), height());
90  const int pre_label_width = GetPreLabelWidth();
91  label_->SetBounds(pre_label_width, 0,
92                    width() - pre_label_width - GetBubbleOuterPadding(false),
93                    height());
94}
95
96gfx::Size IconLabelBubbleView::GetSizeForLabelWidth(int width) const {
97  gfx::Size size(GetPreLabelWidth() + width + GetBubbleOuterPadding(false), 0);
98  size.SetToMax(background_painter_->GetMinimumSize());
99  return size;
100}
101
102void IconLabelBubbleView::OnMouseEntered(const ui::MouseEvent& event) {
103  in_hover_ = true;
104  if (hover_background_painter_.get())
105    SchedulePaint();
106}
107
108void IconLabelBubbleView::OnMouseExited(const ui::MouseEvent& event) {
109  in_hover_ = false;
110  if (hover_background_painter_.get())
111    SchedulePaint();
112}
113
114// static
115int IconLabelBubbleView::GetBubbleOuterPadding(bool by_icon) {
116  return LocationBarView::kItemPadding - LocationBarView::kBubblePadding +
117      (by_icon ? 0 : LocationBarView::kIconInternalPadding);
118}
119
120void IconLabelBubbleView::OnPaint(gfx::Canvas* canvas) {
121  views::Painter* painter = (in_hover_ && hover_background_painter_) ?
122      hover_background_painter_.get() : background_painter_.get();
123  painter->Paint(canvas, size());
124}
125
126int IconLabelBubbleView::GetPreLabelWidth() const {
127  const int image_width = image_->GetPreferredSize().width();
128  return GetBubbleOuterPadding(true) +
129      (image_width ? (image_width + LocationBarView::kItemPadding) : 0);
130}
131