Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / views / location_bar / content_setting_image_view.cc
blob3a9a4d5dc91f200994bba957d4ca5948311f59eb
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 "chrome/browser/ui/views/location_bar/content_setting_image_view.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
9 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
10 #include "chrome/browser/ui/content_settings/content_setting_image_model.h"
11 #include "chrome/browser/ui/views/content_setting_bubble_contents.h"
12 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
13 #include "grit/theme_resources.h"
14 #include "ui/base/l10n/l10n_util.h"
15 #include "ui/base/resource/resource_bundle.h"
16 #include "ui/gfx/color_utils.h"
17 #include "ui/views/controls/image_view.h"
18 #include "ui/views/controls/label.h"
19 #include "ui/views/widget/widget.h"
22 namespace {
23 const int kBackgroundImages[] = IMAGE_GRID(IDR_OMNIBOX_CONTENT_SETTING_BUBBLE);
24 const int kStayOpenTimeMS = 3200; // Time spent with animation fully open.
28 // static
29 const int ContentSettingImageView::kOpenTimeMS = 150;
30 const int ContentSettingImageView::kAnimationDurationMS =
31 (kOpenTimeMS * 2) + kStayOpenTimeMS;
33 ContentSettingImageView::ContentSettingImageView(
34 ContentSettingsType content_type,
35 LocationBarView* parent,
36 const gfx::FontList& font_list,
37 SkColor text_color,
38 SkColor parent_background_color)
39 : parent_(parent),
40 content_setting_image_model_(
41 ContentSettingImageModel::CreateContentSettingImageModel(
42 content_type)),
43 background_painter_(
44 views::Painter::CreateImageGridPainter(kBackgroundImages)),
45 icon_(new views::ImageView),
46 text_label_(new views::Label(base::string16(), font_list)),
47 slide_animator_(this),
48 pause_animation_(false),
49 pause_animation_state_(0.0),
50 bubble_widget_(NULL) {
51 icon_->SetHorizontalAlignment(views::ImageView::LEADING);
52 AddChildView(icon_);
54 text_label_->SetVisible(false);
55 text_label_->SetEnabledColor(text_color);
56 // Calculate the actual background color for the label. The background images
57 // are painted atop |parent_background_color|. We grab the color of the
58 // middle pixel of the middle image of the background, which we treat as the
59 // representative color of the entire background (reasonable, given the
60 // current appearance of these images). Then we alpha-blend it over the
61 // parent background color to determine the actual color the label text will
62 // sit atop.
63 const SkBitmap& bitmap(
64 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
65 kBackgroundImages[4])->GetRepresentation(1.0f).sk_bitmap());
66 SkAutoLockPixels pixel_lock(bitmap);
67 SkColor background_image_color =
68 bitmap.getColor(bitmap.width() / 2, bitmap.height() / 2);
69 // Tricky bit: We alpha blend an opaque version of |background_image_color|
70 // against |parent_background_color| using the original image grid color's
71 // alpha. This is because AlphaBlend(a, b, 255) always returns |a| unchanged
72 // even if |a| is a color with non-255 alpha.
73 text_label_->SetBackgroundColor(
74 color_utils::AlphaBlend(SkColorSetA(background_image_color, 255),
75 parent_background_color,
76 SkColorGetA(background_image_color)));
77 text_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
78 text_label_->SetElideBehavior(views::Label::NO_ELIDE);
79 AddChildView(text_label_);
81 LocationBarView::InitTouchableLocationBarChildView(this);
83 slide_animator_.SetSlideDuration(kAnimationDurationMS);
84 slide_animator_.SetTweenType(gfx::Tween::LINEAR);
87 ContentSettingImageView::~ContentSettingImageView() {
88 if (bubble_widget_)
89 bubble_widget_->RemoveObserver(this);
92 void ContentSettingImageView::Update(content::WebContents* web_contents) {
93 // Note: We explicitly want to call this even if |web_contents| is NULL, so we
94 // get hidden properly while the user is editing the omnibox.
95 content_setting_image_model_->UpdateFromWebContents(web_contents);
97 if (!content_setting_image_model_->is_visible()) {
98 SetVisible(false);
99 return;
102 icon_->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
103 content_setting_image_model_->get_icon()));
104 icon_->SetTooltipText(
105 base::UTF8ToUTF16(content_setting_image_model_->get_tooltip()));
106 SetVisible(true);
108 // If the content blockage should be indicated to the user, start the
109 // animation and record that we indicated the blockage.
110 TabSpecificContentSettings* content_settings = web_contents ?
111 TabSpecificContentSettings::FromWebContents(web_contents) : NULL;
112 if (!content_settings || content_settings->IsBlockageIndicated(
113 content_setting_image_model_->get_content_settings_type()))
114 return;
116 // We just ignore this blockage if we're already showing some other string to
117 // the user. If this becomes a problem, we could design some sort of queueing
118 // mechanism to show one after the other, but it doesn't seem important now.
119 int string_id = content_setting_image_model_->explanatory_string_id();
120 if (string_id && !background_showing()) {
121 text_label_->SetText(l10n_util::GetStringUTF16(string_id));
122 text_label_->SetVisible(true);
123 slide_animator_.Show();
126 content_settings->SetBlockageHasBeenIndicated(
127 content_setting_image_model_->get_content_settings_type());
130 // static
131 int ContentSettingImageView::GetBubbleOuterPadding(bool by_icon) {
132 return LocationBarView::GetItemPadding() - LocationBarView::kBubblePadding +
133 (by_icon ? 0 : LocationBarView::kIconInternalPadding);
136 void ContentSettingImageView::AnimationEnded(const gfx::Animation* animation) {
137 slide_animator_.Reset();
138 if (!pause_animation_) {
139 text_label_->SetVisible(false);
140 parent_->Layout();
141 parent_->SchedulePaint();
145 void ContentSettingImageView::AnimationProgressed(
146 const gfx::Animation* animation) {
147 if (!pause_animation_) {
148 parent_->Layout();
149 parent_->SchedulePaint();
153 void ContentSettingImageView::AnimationCanceled(
154 const gfx::Animation* animation) {
155 AnimationEnded(animation);
158 gfx::Size ContentSettingImageView::GetPreferredSize() {
159 // Height will be ignored by the LocationBarView.
160 gfx::Size size(icon_->GetPreferredSize());
161 if (background_showing()) {
162 double state = slide_animator_.GetCurrentValue();
163 // The fraction of the animation we'll spend animating the string into view,
164 // which is also the fraction we'll spend animating it closed; total
165 // animation (slide out, show, then slide in) is 1.0.
166 const double kOpenFraction =
167 static_cast<double>(kOpenTimeMS) / kAnimationDurationMS;
168 double size_fraction = 1.0;
169 if (state < kOpenFraction)
170 size_fraction = state / kOpenFraction;
171 if (state > (1.0 - kOpenFraction))
172 size_fraction = (1.0 - state) / kOpenFraction;
173 size.Enlarge(
174 size_fraction * (text_label_->GetPreferredSize().width() +
175 GetTotalSpacingWhileAnimating()), 0);
176 size.SetToMax(background_painter_->GetMinimumSize());
178 return size;
181 void ContentSettingImageView::Layout() {
182 const int icon_width = icon_->GetPreferredSize().width();
183 icon_->SetBounds(
184 std::min((width() - icon_width) / 2, GetBubbleOuterPadding(true)), 0,
185 icon_width, height());
186 text_label_->SetBounds(
187 icon_->bounds().right() + LocationBarView::GetItemPadding(), 0,
188 std::max(width() - GetTotalSpacingWhileAnimating() - icon_width, 0),
189 height());
192 bool ContentSettingImageView::OnMousePressed(const ui::MouseEvent& event) {
193 // We want to show the bubble on mouse release; that is the standard behavior
194 // for buttons.
195 return true;
198 void ContentSettingImageView::OnMouseReleased(const ui::MouseEvent& event) {
199 if (HitTestPoint(event.location()))
200 OnClick();
203 void ContentSettingImageView::OnGestureEvent(ui::GestureEvent* event) {
204 if (event->type() == ui::ET_GESTURE_TAP)
205 OnClick();
206 if ((event->type() == ui::ET_GESTURE_TAP) ||
207 (event->type() == ui::ET_GESTURE_TAP_DOWN))
208 event->SetHandled();
211 void ContentSettingImageView::OnPaintBackground(gfx::Canvas* canvas) {
212 if (background_showing())
213 background_painter_->Paint(canvas, size());
216 void ContentSettingImageView::OnWidgetDestroying(views::Widget* widget) {
217 DCHECK_EQ(bubble_widget_, widget);
218 bubble_widget_->RemoveObserver(this);
219 bubble_widget_ = NULL;
221 if (pause_animation_) {
222 slide_animator_.Reset(pause_animation_state_);
223 pause_animation_ = false;
224 slide_animator_.Show();
228 int ContentSettingImageView::GetTotalSpacingWhileAnimating() const {
229 return GetBubbleOuterPadding(true) + LocationBarView::GetItemPadding() +
230 GetBubbleOuterPadding(false);
233 void ContentSettingImageView::OnClick() {
234 if (slide_animator_.is_animating()) {
235 if (!pause_animation_) {
236 pause_animation_ = true;
237 pause_animation_state_ = slide_animator_.GetCurrentValue();
239 slide_animator_.Reset();
242 content::WebContents* web_contents = parent_->GetWebContents();
243 if (web_contents && !bubble_widget_) {
244 bubble_widget_ =
245 parent_->delegate()->CreateViewsBubble(new ContentSettingBubbleContents(
246 ContentSettingBubbleModel::CreateContentSettingBubbleModel(
247 parent_->delegate()->GetContentSettingBubbleModelDelegate(),
248 web_contents, parent_->profile(),
249 content_setting_image_model_->get_content_settings_type()),
250 this, views::BubbleBorder::TOP_RIGHT));
251 bubble_widget_->AddObserver(this);
252 bubble_widget_->Show();