| 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 |