OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h" | 5 #include "chrome/browser/ui/views/location_bar/content_setting_image_view.h" |
6 | 6 |
7 #include "base/utf_string_conversions.h" | 7 #include "base/utf_string_conversions.h" |
8 #include "chrome/browser/content_settings/tab_specific_content_settings.h" | 8 #include "chrome/browser/content_settings/tab_specific_content_settings.h" |
9 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.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" | 10 #include "chrome/browser/ui/content_settings/content_setting_image_model.h" |
11 #include "chrome/browser/ui/views/content_setting_bubble_contents.h" | 11 #include "chrome/browser/ui/views/content_setting_bubble_contents.h" |
12 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" | 12 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" |
13 #include "content/public/browser/web_contents.h" | |
14 #include "third_party/skia/include/core/SkShader.h" | |
15 #include "ui/base/animation/slide_animation.h" | |
16 #include "ui/base/animation/tween.h" | |
17 #include "ui/base/l10n/l10n_util.h" | 13 #include "ui/base/l10n/l10n_util.h" |
18 #include "ui/base/resource/resource_bundle.h" | 14 #include "ui/base/resource/resource_bundle.h" |
19 #include "ui/gfx/canvas.h" | |
20 #include "ui/gfx/skia_util.h" | |
21 #include "ui/views/border.h" | |
22 #include "ui/views/controls/image_view.h" | 15 #include "ui/views/controls/image_view.h" |
23 #include "ui/views/controls/label.h" | 16 #include "ui/views/controls/label.h" |
24 #include "ui/views/layout/box_layout.h" | 17 #include "ui/views/layout/box_layout.h" |
25 #include "ui/views/widget/widget.h" | 18 #include "ui/views/widget/widget.h" |
26 | 19 |
27 using content::WebContents; | |
28 | |
29 | 20 |
30 namespace { | 21 namespace { |
31 // Animation parameters. | 22 const int kStayOpenTimeMS = 3200; // Time spent with animation fully open. |
32 const int kFrameRateHz = 60; | |
33 const int kOpenTimeMs = 150; | |
34 const int kFullOpenedTimeMs = 3200; | |
35 const int kMoveTimeMs = kFullOpenedTimeMs + 2 * kOpenTimeMs; | |
36 | |
37 // The fraction of the animation we'll spend animating the string into view, and | |
38 // then again animating it closed - total animation (slide out, show, then | |
39 // slide in) is 1.0. | |
40 const double kAnimatingFraction = kOpenTimeMs * 1.0 / kMoveTimeMs; | |
41 | 23 |
42 // Margins for animated box (pixels). | 24 // Margins for animated box (pixels). |
43 const int kHorizMargin = 4; | 25 const int kHorizMargin = 4; |
44 const int kIconLabelSpacing = 4; | 26 const int kIconLabelSpacing = 4; |
45 } | 27 } |
46 | 28 |
47 | 29 |
| 30 // static |
| 31 const int ContentSettingImageView::kOpenTimeMS = 150; |
| 32 const int ContentSettingImageView::kAnimationDurationMS = |
| 33 (kOpenTimeMS * 2) + kStayOpenTimeMS; |
| 34 |
48 ContentSettingImageView::ContentSettingImageView( | 35 ContentSettingImageView::ContentSettingImageView( |
49 ContentSettingsType content_type, | 36 ContentSettingsType content_type, |
50 const int background_images[], | 37 const int background_images[], |
51 LocationBarView* parent, | 38 LocationBarView* parent, |
52 const gfx::Font& font, | 39 const gfx::Font& font, |
53 int font_y_offset, | 40 int font_y_offset, |
54 SkColor font_color) | 41 SkColor font_color) |
55 : parent_(parent), | 42 : parent_(parent), |
56 content_setting_image_model_( | 43 content_setting_image_model_( |
57 ContentSettingImageModel::CreateContentSettingImageModel( | 44 ContentSettingImageModel::CreateContentSettingImageModel( |
58 content_type)), | 45 content_type)), |
59 background_painter_(background_images), | 46 background_painter_(new views::HorizontalPainter(background_images)), |
60 icon_(new views::ImageView), | 47 icon_(new views::ImageView), |
61 text_label_(NULL), | 48 text_label_(NULL), |
62 slide_animator_(this), | 49 slide_animator_(this), |
63 pause_animation_(false), | 50 pause_animation_(false), |
64 pause_animation_state_(0.0), | 51 pause_animation_state_(0.0), |
65 bubble_widget_(NULL), | 52 bubble_widget_(NULL), |
66 font_(font), | 53 font_(font), |
67 text_size_(0), | 54 text_size_(0) { |
68 visible_text_size_(0) { | |
69 SetLayoutManager(new views::BoxLayout( | 55 SetLayoutManager(new views::BoxLayout( |
70 views::BoxLayout::kHorizontal, 0, 0, 0)); | 56 views::BoxLayout::kHorizontal, 0, 0, 0)); |
71 icon_->SetHorizontalAlignment(views::ImageView::LEADING); | 57 icon_->SetHorizontalAlignment(views::ImageView::LEADING); |
72 AddChildView(icon_); | 58 AddChildView(icon_); |
73 TouchableLocationBarView::Init(this); | 59 TouchableLocationBarView::Init(this); |
74 | 60 |
75 slide_animator_.SetSlideDuration(kMoveTimeMs); | 61 slide_animator_.SetSlideDuration(kAnimationDurationMS); |
76 slide_animator_.SetTweenType(ui::Tween::LINEAR); | 62 slide_animator_.SetTweenType(ui::Tween::LINEAR); |
77 } | 63 } |
78 | 64 |
79 ContentSettingImageView::~ContentSettingImageView() { | 65 ContentSettingImageView::~ContentSettingImageView() { |
80 if (bubble_widget_) { | 66 if (bubble_widget_) |
81 bubble_widget_->RemoveObserver(this); | 67 bubble_widget_->RemoveObserver(this); |
82 bubble_widget_ = NULL; | |
83 } | |
84 } | 68 } |
85 | 69 |
86 int ContentSettingImageView::GetBuiltInHorizontalPadding() const { | 70 int ContentSettingImageView::GetBuiltInHorizontalPadding() const { |
87 return GetBuiltInHorizontalPaddingImpl(); | 71 return GetBuiltInHorizontalPaddingImpl(); |
88 } | 72 } |
89 | 73 |
90 void ContentSettingImageView::Update(WebContents* web_contents) { | 74 void ContentSettingImageView::Update(content::WebContents* web_contents) { |
91 if (web_contents) { | 75 if (web_contents) |
92 content_setting_image_model_->UpdateFromWebContents(web_contents); | 76 content_setting_image_model_->UpdateFromWebContents(web_contents); |
93 } | 77 |
94 if (!content_setting_image_model_->is_visible()) { | 78 if (!content_setting_image_model_->is_visible()) { |
95 SetVisible(false); | 79 SetVisible(false); |
96 return; | 80 return; |
97 } | 81 } |
| 82 |
98 icon_->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( | 83 icon_->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
99 content_setting_image_model_->get_icon())); | 84 content_setting_image_model_->get_icon())); |
100 icon_->SetTooltipText( | 85 icon_->SetTooltipText( |
101 UTF8ToUTF16(content_setting_image_model_->get_tooltip())); | 86 UTF8ToUTF16(content_setting_image_model_->get_tooltip())); |
102 SetVisible(true); | 87 SetVisible(true); |
103 | 88 |
104 TabSpecificContentSettings* content_settings = NULL; | 89 // If the content blockage should be indicated to the user, start the |
105 if (web_contents) { | 90 // animation and record that we indicated the blockage. |
106 content_settings = | 91 TabSpecificContentSettings* content_settings = web_contents ? |
107 TabSpecificContentSettings::FromWebContents(web_contents); | 92 TabSpecificContentSettings::FromWebContents(web_contents) : NULL; |
108 } | |
109 | |
110 if (!content_settings || content_settings->IsBlockageIndicated( | 93 if (!content_settings || content_settings->IsBlockageIndicated( |
111 content_setting_image_model_->get_content_settings_type())) | 94 content_setting_image_model_->get_content_settings_type())) |
112 return; | 95 return; |
113 | 96 |
114 // The content blockage was not yet indicated to the user. Start indication | 97 // We just ignore this blockage if we're already showing some other string to |
115 // animation and clear "not yet shown" flag. | 98 // the user. If this becomes a problem, we could design some sort of queueing |
116 content_settings->SetBlockageHasBeenIndicated( | 99 // mechanism to show one after the other, but it doesn't seem important now. |
117 content_setting_image_model_->get_content_settings_type()); | 100 int string_id = content_setting_image_model_->explanatory_string_id(); |
118 | 101 if (string_id && !background_showing()) { |
119 int animated_string_id = | |
120 content_setting_image_model_->explanatory_string_id(); | |
121 // Check if the string for animation is available. | |
122 if (!animated_string_id) | |
123 return; | |
124 | |
125 // Do not start animation if already in progress. | |
126 if (!slide_animator_.is_animating()) { | |
127 // Initialize animated string. It will be cleared when animation is | 102 // Initialize animated string. It will be cleared when animation is |
128 // completed. | 103 // completed. |
129 if (!text_label_) { | 104 if (!text_label_) { |
130 text_label_ = new views::Label; | 105 text_label_ = new views::Label; |
131 text_label_->SetElideBehavior(views::Label::NO_ELIDE); | 106 text_label_->SetElideBehavior(views::Label::NO_ELIDE); |
132 text_label_->SetFont(font_); | 107 text_label_->SetFont(font_); |
133 SetLayoutManager(new views::BoxLayout( | 108 SetLayoutManager(new views::BoxLayout( |
134 views::BoxLayout::kHorizontal, kHorizMargin, 0, kIconLabelSpacing)); | 109 views::BoxLayout::kHorizontal, kHorizMargin, 0, kIconLabelSpacing)); |
135 AddChildView(text_label_); | 110 AddChildView(text_label_); |
136 } | 111 } |
137 text_label_->SetText(l10n_util::GetStringUTF16(animated_string_id)); | 112 text_label_->SetText(l10n_util::GetStringUTF16(string_id)); |
138 text_size_ = font_.GetStringWidth(text_label_->text()); | 113 text_size_ = font_.GetStringWidth(text_label_->text()); |
139 text_size_ += kHorizMargin; | 114 text_size_ += kHorizMargin; |
140 slide_animator_.Show(); | 115 slide_animator_.Show(); |
141 } | 116 } |
| 117 |
| 118 content_settings->SetBlockageHasBeenIndicated( |
| 119 content_setting_image_model_->get_content_settings_type()); |
142 } | 120 } |
143 | 121 |
144 void ContentSettingImageView::AnimationEnded(const ui::Animation* animation) { | 122 void ContentSettingImageView::AnimationEnded(const ui::Animation* animation) { |
| 123 slide_animator_.Reset(); |
145 if (!pause_animation_) { | 124 if (!pause_animation_) { |
146 SetLayoutManager(new views::BoxLayout( | 125 SetLayoutManager(new views::BoxLayout( |
147 views::BoxLayout::kHorizontal, 0, 0, 0)); | 126 views::BoxLayout::kHorizontal, 0, 0, 0)); |
148 RemoveChildView(text_label_); // will also delete the view. | 127 RemoveChildView(text_label_); // will also delete the view. |
149 text_label_ = NULL; | 128 text_label_ = NULL; |
150 parent_->Layout(); | 129 parent_->Layout(); |
151 parent_->SchedulePaint(); | 130 parent_->SchedulePaint(); |
152 } | 131 } |
153 slide_animator_.Reset(); | |
154 } | 132 } |
155 | 133 |
156 void ContentSettingImageView::AnimationProgressed( | 134 void ContentSettingImageView::AnimationProgressed( |
157 const ui::Animation* animation) { | 135 const ui::Animation* animation) { |
158 if (pause_animation_) | 136 if (!pause_animation_) { |
159 return; | 137 parent_->Layout(); |
160 | 138 parent_->SchedulePaint(); |
161 visible_text_size_ = GetTextAnimationSize(slide_animator_.GetCurrentValue(), | 139 } |
162 text_size_); | |
163 | |
164 parent_->Layout(); | |
165 parent_->SchedulePaint(); | |
166 } | 140 } |
167 | 141 |
168 void ContentSettingImageView::AnimationCanceled( | 142 void ContentSettingImageView::AnimationCanceled( |
169 const ui::Animation* animation) { | 143 const ui::Animation* animation) { |
170 AnimationEnded(animation); | 144 AnimationEnded(animation); |
171 } | 145 } |
172 | 146 |
173 gfx::Size ContentSettingImageView::GetPreferredSize() { | 147 gfx::Size ContentSettingImageView::GetPreferredSize() { |
174 // Height will be ignored by the LocationBarView. | 148 // Height will be ignored by the LocationBarView. |
175 gfx::Size preferred_size(views::View::GetPreferredSize()); | 149 gfx::Size preferred_size(views::View::GetPreferredSize()); |
176 int non_label_width = preferred_size.width() - | 150 int non_label_width = preferred_size.width() - |
177 (text_label_ ? text_label_->GetPreferredSize().width() : 0); | 151 (text_label_ ? text_label_->GetPreferredSize().width() : 0); |
178 // When view is animated |visible_text_size_| > 0, it is 0 otherwise. | 152 |
179 preferred_size.set_width(non_label_width + visible_text_size_); | 153 int visible_text_size = 0; |
| 154 if (background_showing()) { |
| 155 double state = slide_animator_.GetCurrentValue(); |
| 156 // The fraction of the animation we'll spend animating the string into view, |
| 157 // which is also the fraction we'll spend animating it closed; total |
| 158 // animation (slide out, show, then slide in) is 1.0. |
| 159 const double kOpenFraction = |
| 160 static_cast<double>(kOpenTimeMS) / kAnimationDurationMS; |
| 161 double size_fraction = 1.0; |
| 162 if (state < kOpenFraction) |
| 163 size_fraction = state / kOpenFraction; |
| 164 if (state > (1.0 - kOpenFraction)) |
| 165 size_fraction = (1.0 - state) / kOpenFraction; |
| 166 visible_text_size = size_fraction * text_size_; |
| 167 } |
| 168 |
| 169 preferred_size.set_width(non_label_width + visible_text_size); |
180 return preferred_size; | 170 return preferred_size; |
181 } | 171 } |
182 | 172 |
183 bool ContentSettingImageView::OnMousePressed(const ui::MouseEvent& event) { | 173 bool ContentSettingImageView::OnMousePressed(const ui::MouseEvent& event) { |
184 // We want to show the bubble on mouse release; that is the standard behavior | 174 // We want to show the bubble on mouse release; that is the standard behavior |
185 // for buttons. | 175 // for buttons. |
186 return true; | 176 return true; |
187 } | 177 } |
188 | 178 |
189 void ContentSettingImageView::OnMouseReleased(const ui::MouseEvent& event) { | 179 void ContentSettingImageView::OnMouseReleased(const ui::MouseEvent& event) { |
190 if (!HitTestPoint(event.location())) | 180 if (HitTestPoint(event.location())) |
191 return; | 181 OnClick(); |
192 | |
193 OnClick(parent_); | |
194 } | 182 } |
195 | 183 |
196 void ContentSettingImageView::OnGestureEvent(ui::GestureEvent* event) { | 184 void ContentSettingImageView::OnGestureEvent(ui::GestureEvent* event) { |
197 if (event->type() == ui::ET_GESTURE_TAP) { | 185 if (event->type() == ui::ET_GESTURE_TAP) |
198 OnClick(parent_); | 186 OnClick(); |
| 187 if ((event->type() == ui::ET_GESTURE_TAP) || |
| 188 (event->type() == ui::ET_GESTURE_TAP_DOWN)) |
199 event->SetHandled(); | 189 event->SetHandled(); |
200 } else if (event->type() == ui::ET_GESTURE_TAP_DOWN) { | 190 } |
201 event->SetHandled(); | 191 |
| 192 void ContentSettingImageView::OnPaintBackground(gfx::Canvas* canvas) { |
| 193 if (background_showing()) |
| 194 background_painter_->Paint(canvas, size()); |
| 195 } |
| 196 |
| 197 void ContentSettingImageView::OnWidgetDestroying(views::Widget* widget) { |
| 198 DCHECK_EQ(bubble_widget_, widget); |
| 199 bubble_widget_->RemoveObserver(this); |
| 200 bubble_widget_ = NULL; |
| 201 |
| 202 if (pause_animation_) { |
| 203 slide_animator_.Reset(pause_animation_state_); |
| 204 pause_animation_ = false; |
| 205 slide_animator_.Show(); |
202 } | 206 } |
203 } | 207 } |
204 | 208 |
205 void ContentSettingImageView::OnPaintBackground(gfx::Canvas* canvas) { | 209 void ContentSettingImageView::OnClick() { |
206 if (slide_animator_.is_animating() || pause_animation_) | |
207 background_painter_.Paint(canvas, size()); | |
208 } | |
209 | |
210 void ContentSettingImageView::OnWidgetDestroying(views::Widget* widget) { | |
211 if (bubble_widget_) { | |
212 bubble_widget_->RemoveObserver(this); | |
213 bubble_widget_ = NULL; | |
214 } | |
215 | |
216 if (!pause_animation_) | |
217 return; | |
218 | |
219 slide_animator_.Reset(pause_animation_state_); | |
220 pause_animation_ = false; | |
221 slide_animator_.Show(); | |
222 } | |
223 | |
224 void ContentSettingImageView::OnClick(LocationBarView* parent) { | |
225 // Stop animation. | |
226 if (slide_animator_.is_animating()) { | 210 if (slide_animator_.is_animating()) { |
227 if (!pause_animation_) { | 211 if (!pause_animation_) { |
228 pause_animation_ = true; | 212 pause_animation_ = true; |
229 pause_animation_state_ = slide_animator_.GetCurrentValue(); | 213 pause_animation_state_ = slide_animator_.GetCurrentValue(); |
230 } | 214 } |
231 slide_animator_.Reset(); | 215 slide_animator_.Reset(); |
232 } | 216 } |
233 | 217 |
234 WebContents* web_contents = parent->GetWebContents(); | 218 content::WebContents* web_contents = parent_->GetWebContents(); |
235 if (!web_contents) | 219 if (web_contents && !bubble_widget_) { |
236 return; | 220 bubble_widget_ = |
237 if (bubble_widget_) | 221 parent_->delegate()->CreateViewsBubble(new ContentSettingBubbleContents( |
238 return; | 222 ContentSettingBubbleModel::CreateContentSettingBubbleModel( |
239 | 223 parent_->delegate()->GetContentSettingBubbleModelDelegate(), |
240 Profile* profile = parent->profile(); | 224 web_contents, parent_->profile(), |
241 ContentSettingBubbleContents* bubble = new ContentSettingBubbleContents( | 225 content_setting_image_model_->get_content_settings_type()), |
242 ContentSettingBubbleModel::CreateContentSettingBubbleModel( | 226 web_contents, this, views::BubbleBorder::TOP_RIGHT)); |
243 parent->delegate()->GetContentSettingBubbleModelDelegate(), | 227 bubble_widget_->AddObserver(this); |
244 web_contents, | 228 bubble_widget_->Show(); |
245 profile, | |
246 content_setting_image_model_->get_content_settings_type()), | |
247 web_contents, | |
248 this, | |
249 views::BubbleBorder::TOP_RIGHT); | |
250 bubble_widget_ = parent->delegate()->CreateViewsBubble(bubble); | |
251 bubble_widget_->AddObserver(this); | |
252 bubble->GetWidget()->Show(); | |
253 } | |
254 | |
255 int ContentSettingImageView::GetTextAnimationSize(double state, | |
256 int text_size) { | |
257 if (state >= 1.0) { | |
258 // Animaton is over, clear the variables. | |
259 return 0; | |
260 } else if (state < kAnimatingFraction) { | |
261 return static_cast<int>(text_size * state / kAnimatingFraction); | |
262 } else if (state > (1.0 - kAnimatingFraction)) { | |
263 return static_cast<int>(text_size * (1.0 - state) / kAnimatingFraction); | |
264 } else { | |
265 return text_size; | |
266 } | 229 } |
267 } | 230 } |
OLD | NEW |