| 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/icon_label_bubble_view.h" | 5 #include "chrome/browser/ui/views/location_bar/icon_label_bubble_view.h" |
| 6 | 6 |
| 7 #include "base/strings/utf_string_conversions.h" | 7 #include "base/strings/utf_string_conversions.h" |
| 8 #include "chrome/browser/ui/layout_constants.h" | 8 #include "chrome/browser/ui/layout_constants.h" |
| 9 #include "chrome/browser/ui/views/location_bar/background_with_1_px_border.h" | 9 #include "chrome/browser/ui/views/location_bar/background_with_1_px_border.h" |
| 10 #include "ui/base/material_design/material_design_controller.h" | 10 #include "ui/base/material_design/material_design_controller.h" |
| 11 #include "ui/base/resource/resource_bundle.h" | 11 #include "ui/base/resource/resource_bundle.h" |
| 12 #include "ui/gfx/canvas.h" | 12 #include "ui/gfx/canvas.h" |
| 13 #include "ui/gfx/color_utils.h" | 13 #include "ui/gfx/color_utils.h" |
| 14 #include "ui/gfx/image/image_util.h" | 14 #include "ui/gfx/image/image_util.h" |
| 15 #include "ui/gfx/scoped_canvas.h" | 15 #include "ui/gfx/scoped_canvas.h" |
| 16 #include "ui/native_theme/native_theme.h" | 16 #include "ui/native_theme/native_theme.h" |
| 17 #include "ui/views/animation/ink_drop_highlight.h" | 17 #include "ui/views/animation/ink_drop_highlight.h" |
| 18 #include "ui/views/border.h" | 18 #include "ui/views/border.h" |
| 19 #include "ui/views/controls/image_view.h" | 19 #include "ui/views/controls/image_view.h" |
| 20 #include "ui/views/controls/textfield/textfield.h" | 20 #include "ui/views/controls/textfield/textfield.h" |
| 21 #include "ui/views/painter.h" | 21 #include "ui/views/painter.h" |
| 22 #include "ui/views/widget/widget.h" |
| 22 | 23 |
| 23 namespace { | 24 namespace { |
| 24 | 25 |
| 25 // Extra padding to place at the end of the chip when the label is showing. | 26 // Amount of space on either side of the separator that appears after the label. |
| 26 const int kExtraTrailingPadding = 7; | 27 constexpr int kSpaceBesideSeparator = 8; |
| 27 | 28 |
| 28 SkColor CalculateImageColor(gfx::ImageSkia* image) { | 29 SkColor CalculateImageColor(gfx::ImageSkia* image) { |
| 29 // We grab the color of the middle pixel of the image, which we treat as | 30 // We grab the color of the middle pixel of the image, which we treat as |
| 30 // the representative color of the entire image (reasonable, given the current | 31 // the representative color of the entire image (reasonable, given the current |
| 31 // appearance of these assets). | 32 // appearance of these assets). |
| 32 const SkBitmap& bitmap(image->GetRepresentation(1.0f).sk_bitmap()); | 33 const SkBitmap& bitmap(image->GetRepresentation(1.0f).sk_bitmap()); |
| 33 SkAutoLockPixels pixel_lock(bitmap); | 34 SkAutoLockPixels pixel_lock(bitmap); |
| 34 return bitmap.getColor(bitmap.width() / 2, bitmap.height() / 2); | 35 return bitmap.getColor(bitmap.width() / 2, bitmap.height() / 2); |
| 35 } | 36 } |
| 36 | 37 |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 } | 223 } |
| 223 | 224 |
| 224 gfx::Size IconLabelBubbleView::GetSizeForLabelWidth(int label_width) const { | 225 gfx::Size IconLabelBubbleView::GetSizeForLabelWidth(int label_width) const { |
| 225 gfx::Size size(image_->GetPreferredSize()); | 226 gfx::Size size(image_->GetPreferredSize()); |
| 226 const bool shrinking = IsShrinking(); | 227 const bool shrinking = IsShrinking(); |
| 227 // Animation continues for the last few pixels even after the label is not | 228 // Animation continues for the last few pixels even after the label is not |
| 228 // visible in order to slide the icon into its final position. Therefore it | 229 // visible in order to slide the icon into its final position. Therefore it |
| 229 // is necessary to animate |total_width| even when the background is hidden | 230 // is necessary to animate |total_width| even when the background is hidden |
| 230 // as long as the animation is still shrinking. | 231 // as long as the animation is still shrinking. |
| 231 if (ShouldShowBackground() || shrinking) { | 232 if (ShouldShowBackground() || shrinking) { |
| 232 const int extra_trailing_padding = | 233 // On scale factors < 2, we reserve 1 DIP for the 1 px separator. For |
| 233 ui::MaterialDesignController::IsModeMaterial() ? kExtraTrailingPadding | 234 // higher scale factors, we simply take the separator px out of the |
| 234 : 0; | 235 // kSpaceBesideSeparator region before the separator, as that results in a |
| 236 // width closer to the desired gap than if we added a whole DIP for the |
| 237 // separator px. (For scale 2, the two methods have equal error: 1 px.) |
| 238 const views::Widget* widget = GetWidget(); |
| 239 // There may be no widget in tests. |
| 240 const int separator_width = |
| 241 (widget && widget->GetCompositor()->device_scale_factor() >= 2) ? 0 : 1; |
| 242 const int post_label_width = ui::MaterialDesignController::IsModeMaterial() |
| 243 ? (kSpaceBesideSeparator + separator_width + GetPostSeparatorPadding()) |
| 244 : GetOuterPadding(false); |
| 245 |
| 235 // |multiplier| grows from zero to one, stays equal to one and then shrinks | 246 // |multiplier| grows from zero to one, stays equal to one and then shrinks |
| 236 // to zero again. The view width should correspondingly grow from zero to | 247 // to zero again. The view width should correspondingly grow from zero to |
| 237 // fully showing both label and icon, stay there, then shrink to just large | 248 // fully showing both label and icon, stay there, then shrink to just large |
| 238 // enough to show the icon. We don't want to shrink all the way back to | 249 // enough to show the icon. We don't want to shrink all the way back to |
| 239 // zero, since this would mean the view would completely disappear and then | 250 // zero, since this would mean the view would completely disappear and then |
| 240 // pop back to an icon after the animation finishes. | 251 // pop back to an icon after the animation finishes. |
| 241 const int max_width = MinimumWidthForImageWithBackgroundShown() + | 252 const int max_width = GetImageTrailingEdge() + GetInternalSpacing() + |
| 242 GetInternalSpacing() + label_width + | 253 label_width + post_label_width; |
| 243 extra_trailing_padding; | |
| 244 const int current_width = WidthMultiplier() * max_width; | 254 const int current_width = WidthMultiplier() * max_width; |
| 245 size.set_width(shrinking ? std::max(current_width, size.width()) | 255 size.set_width(shrinking ? std::max(current_width, size.width()) |
| 246 : current_width); | 256 : current_width); |
| 247 } | 257 } |
| 248 return size; | 258 return size; |
| 249 } | 259 } |
| 250 | 260 |
| 251 int IconLabelBubbleView::MinimumWidthForImageWithBackgroundShown() const { | 261 int IconLabelBubbleView::MinimumWidthForImageWithBackgroundShown() const { |
| 252 return GetOuterPadding(true) + image_->GetPreferredSize().width() + | 262 return GetImageTrailingEdge() + GetOuterPadding(false); |
| 253 GetOuterPadding(false); | |
| 254 } | 263 } |
| 255 | 264 |
| 256 void IconLabelBubbleView::SetLabelBackgroundColor( | 265 void IconLabelBubbleView::SetLabelBackgroundColor( |
| 257 SkColor chip_background_color) { | 266 SkColor chip_background_color) { |
| 258 // The background images are painted atop |parent_background_color_|. | 267 // The background images are painted atop |parent_background_color_|. |
| 259 // Alpha-blend |chip_background_color| with |parent_background_color_| to | 268 // Alpha-blend |chip_background_color| with |parent_background_color_| to |
| 260 // determine the actual color the label text will sit atop. | 269 // determine the actual color the label text will sit atop. |
| 261 // Tricky bit: We alpha blend an opaque version of |chip_background_color| | 270 // Tricky bit: We alpha blend an opaque version of |chip_background_color| |
| 262 // against |parent_background_color_| using the original image grid color's | 271 // against |parent_background_color_| using the original image grid color's |
| 263 // alpha. This is because AlphaBlend(a, b, 255) always returns |a| unchanged | 272 // alpha. This is because AlphaBlend(a, b, 255) always returns |a| unchanged |
| 264 // even if |a| is a color with non-255 alpha. | 273 // even if |a| is a color with non-255 alpha. |
| 265 label_->SetBackgroundColor(color_utils::AlphaBlend( | 274 label_->SetBackgroundColor(color_utils::AlphaBlend( |
| 266 SkColorSetA(chip_background_color, 255), GetParentBackgroundColor(), | 275 SkColorSetA(chip_background_color, 255), GetParentBackgroundColor(), |
| 267 SkColorGetA(chip_background_color))); | 276 SkColorGetA(chip_background_color))); |
| 268 } | 277 } |
| 269 | 278 |
| 270 int IconLabelBubbleView::GetOuterPadding(bool leading) const { | 279 int IconLabelBubbleView::GetOuterPadding(bool leading) const { |
| 271 if (ui::MaterialDesignController::IsModeMaterial()) | 280 if (ui::MaterialDesignController::IsModeMaterial()) |
| 272 return GetLayoutConstant(LOCATION_BAR_HORIZONTAL_PADDING); | 281 return GetLayoutConstant(LOCATION_BAR_HORIZONTAL_PADDING); |
| 273 | 282 |
| 274 return GetLayoutConstant(LOCATION_BAR_HORIZONTAL_PADDING) - | 283 return GetLayoutConstant(LOCATION_BAR_HORIZONTAL_PADDING) - |
| 275 GetLayoutConstant(LOCATION_BAR_BUBBLE_HORIZONTAL_PADDING) + | 284 GetLayoutConstant(LOCATION_BAR_BUBBLE_HORIZONTAL_PADDING) + |
| 276 (leading ? 0 : kTrailingPaddingPreMd); | 285 (leading ? 0 : kTrailingPaddingPreMd); |
| 277 } | 286 } |
| 278 | 287 |
| 288 int IconLabelBubbleView::GetImageTrailingEdge() const { |
| 289 return GetOuterPadding(true) + image_->GetPreferredSize().width(); |
| 290 } |
| 291 |
| 279 int IconLabelBubbleView::GetInternalSpacing() const { | 292 int IconLabelBubbleView::GetInternalSpacing() const { |
| 280 return image_->GetPreferredSize().IsEmpty() | 293 return image_->GetPreferredSize().IsEmpty() |
| 281 ? 0 | 294 ? 0 |
| 282 : GetLayoutConstant(LOCATION_BAR_HORIZONTAL_PADDING); | 295 : GetLayoutConstant(LOCATION_BAR_HORIZONTAL_PADDING); |
| 283 } | 296 } |
| 284 | 297 |
| 298 int IconLabelBubbleView::GetPostSeparatorPadding() const { |
| 299 // The location bar will add LOCATION_BAR_HORIZONTAL_PADDING after us. |
| 300 return kSpaceBesideSeparator - |
| 301 GetLayoutConstant(LOCATION_BAR_HORIZONTAL_PADDING); |
| 302 } |
| 303 |
| 285 const char* IconLabelBubbleView::GetClassName() const { | 304 const char* IconLabelBubbleView::GetClassName() const { |
| 286 return "IconLabelBubbleView"; | 305 return "IconLabelBubbleView"; |
| 287 } | 306 } |
| 288 | 307 |
| 289 void IconLabelBubbleView::OnPaint(gfx::Canvas* canvas) { | 308 void IconLabelBubbleView::OnPaint(gfx::Canvas* canvas) { |
| 290 if (!ShouldShowBackground()) | 309 if (!ShouldShowBackground()) |
| 291 return; | 310 return; |
| 292 if (background_painter_) { | 311 if (background_painter_) { |
| 293 views::Painter::PaintPainterAt(canvas, background_painter_.get(), | 312 views::Painter::PaintPainterAt(canvas, background_painter_.get(), |
| 294 GetContentsBounds()); | 313 GetContentsBounds()); |
| 295 } | 314 } |
| 296 | 315 |
| 297 // In MD, draw a separator and not a background. | 316 // In MD, draw a separator and not a background. |
| 298 if (ui::MaterialDesignController::IsModeMaterial()) { | 317 if (ui::MaterialDesignController::IsModeMaterial()) { |
| 299 const SkColor plain_text_color = GetNativeTheme()->GetSystemColor( | 318 const SkColor plain_text_color = GetNativeTheme()->GetSystemColor( |
| 300 ui::NativeTheme::kColorId_TextfieldDefaultColor); | 319 ui::NativeTheme::kColorId_TextfieldDefaultColor); |
| 301 const SkColor separator_color = SkColorSetA( | 320 const SkColor separator_color = SkColorSetA( |
| 302 plain_text_color, color_utils::IsDark(plain_text_color) ? 0x59 : 0xCC); | 321 plain_text_color, color_utils::IsDark(plain_text_color) ? 0x59 : 0xCC); |
| 303 | 322 |
| 304 // Amount of padding that is built into the whatever view comes after this | 323 gfx::Rect bounds(GetLocalBounds()); |
| 305 // one in the location bar (e.g. omnibox textfield). | |
| 306 int post_chip_spacing = | |
| 307 GetLayoutConstant(LOCATION_BAR_HORIZONTAL_PADDING); | |
| 308 // Amount of space to leave after the separator (dp). | |
| 309 const int kPostSeparatorSpacing = | |
| 310 (GetLayoutConstant(LOCATION_BAR_HORIZONTAL_PADDING) + | |
| 311 kExtraTrailingPadding + post_chip_spacing) / | |
| 312 2 - | |
| 313 post_chip_spacing; | |
| 314 // Height of the separator (dp). | |
| 315 const int kSeparatorHeight = 16; | 324 const int kSeparatorHeight = 16; |
| 316 gfx::Rect bounds(GetLocalBounds()); | 325 bounds.Inset(GetPostSeparatorPadding(), |
| 317 bounds.Inset(kPostSeparatorSpacing, | |
| 318 (bounds.height() - kSeparatorHeight) / 2); | 326 (bounds.height() - kSeparatorHeight) / 2); |
| 319 | 327 |
| 320 // 1px at all scale factors. | 328 // Draw the 1 px separator. |
| 321 gfx::ScopedCanvas scoped_canvas(canvas); | 329 gfx::ScopedCanvas scoped_canvas(canvas); |
| 322 const float scale = canvas->UndoDeviceScaleFactor(); | 330 const float scale = canvas->UndoDeviceScaleFactor(); |
| 331 // Keep the separator aligned on a pixel center. |
| 323 const gfx::RectF pixel_aligned_bounds = | 332 const gfx::RectF pixel_aligned_bounds = |
| 324 gfx::ScaleRect(gfx::RectF(bounds), scale) - gfx::Vector2dF(0.5f, 0); | 333 gfx::ScaleRect(gfx::RectF(bounds), scale) - gfx::Vector2dF(0.5f, 0); |
| 325 canvas->DrawLine(pixel_aligned_bounds.top_right(), | 334 canvas->DrawLine(pixel_aligned_bounds.top_right(), |
| 326 pixel_aligned_bounds.bottom_right(), separator_color); | 335 pixel_aligned_bounds.bottom_right(), separator_color); |
| 327 } | 336 } |
| 328 } | 337 } |
| OLD | NEW |