Chromium Code Reviews| Index: chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc |
| diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc |
| index 4081c797931e5b7cd46e6de01e46e00e3d736746..cf50226743e6a48ab6b0a9976016cc77bcfcf009 100644 |
| --- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc |
| +++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc |
| @@ -6,6 +6,7 @@ |
| #include <algorithm> |
| +#include "base/lazy_instance.h" |
| #include "base/macros.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/search/search.h" |
| @@ -14,22 +15,65 @@ |
| #include "chrome/browser/ui/views/location_bar/location_bar_view.h" |
| #include "chrome/browser/ui/views/omnibox/omnibox_result_view.h" |
| #include "chrome/browser/ui/views/theme_copying_widget.h" |
| -#include "chrome/grit/theme_resources.h" |
| #include "components/omnibox/browser/omnibox_view.h" |
| -#include "ui/base/material_design/material_design_controller.h" |
| -#include "ui/base/resource/resource_bundle.h" |
| +#include "third_party/skia/include/core/SkDrawLooper.h" |
| #include "ui/base/theme_provider.h" |
| #include "ui/compositor/clip_recorder.h" |
| #include "ui/compositor/paint_recorder.h" |
| #include "ui/gfx/canvas.h" |
| +#include "ui/gfx/image/canvas_image_source.h" |
| #include "ui/gfx/image/image.h" |
| #include "ui/gfx/path.h" |
| +#include "ui/gfx/shadow_value.h" |
| +#include "ui/gfx/skia_util.h" |
| #include "ui/views/controls/image_view.h" |
| -#include "ui/views/resources/grit/views_resources.h" |
| #include "ui/views/view_targeter.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/views/window/non_client_view.h" |
| +namespace { |
| + |
| +// This creates a shadow image that is 1dp wide, suitable for tiling along the |
| +// top or bottom edge of the omnibox popup. |
| +class ShadowImageSource : public gfx::CanvasImageSource { |
| + public: |
| + ShadowImageSource(const std::vector<gfx::ShadowValue>& shadows, bool bottom) |
| + : gfx::CanvasImageSource(gfx::Size(1, GetHeightForShadows(shadows)), |
| + false), |
| + shadows_(shadows), |
| + bottom_(bottom) {} |
| + ~ShadowImageSource() override {} |
| + |
| + void Draw(gfx::Canvas* canvas) override { |
| + SkPaint paint; |
| + paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadows_)); |
| + canvas->DrawRect(gfx::RectF(0, bottom_ ? -1 : size().height(), 1, 1), |
| + paint); |
| + } |
| + |
| + private: |
| + static int GetHeightForShadows(const std::vector<gfx::ShadowValue>& shadows) { |
| + int height = 0; |
| + for (const auto& shadow : shadows) { |
| + height = |
| + std::max(height, shadow.y() + static_cast<int>(shadow.blur()) / 2); |
|
Peter Kasting
2016/09/23 19:38:44
Functionally, shouldn't this be more like "ceil(bl
Evan Stade
2016/09/26 18:11:42
the blur value should always be even, but I've upd
|
| + } |
| + return height; |
| + } |
| + |
| + const std::vector<gfx::ShadowValue> shadows_; |
| + bool bottom_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ShadowImageSource); |
| +}; |
| + |
| +// Cache the shadow images so that potentially expensive shadow drawing isn't |
| +// repeated. |
| +base::LazyInstance<gfx::ImageSkia> g_top_shadow = LAZY_INSTANCE_INITIALIZER; |
| +base::LazyInstance<gfx::ImageSkia> g_bottom_shadow = LAZY_INSTANCE_INITIALIZER; |
| + |
| +} // namespace |
| + |
| class OmniboxPopupContentsView::AutocompletePopupWidget |
| : public ThemeCopyingWidget, |
| public base::SupportsWeakPtr<AutocompletePopupWidget> { |
| @@ -73,12 +117,30 @@ OmniboxPopupContentsView::OmniboxPopupContentsView( |
| // The contents is owned by the LocationBarView. |
| set_owned_by_client(); |
| - ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); |
| - if (ui::MaterialDesignController::IsModeMaterial()) { |
| - top_shadow_ = rb->GetImageSkiaNamed(IDR_OMNIBOX_DROPDOWN_SHADOW_TOP); |
| - bottom_shadow_ = rb->GetImageSkiaNamed(IDR_OMNIBOX_DROPDOWN_SHADOW_BOTTOM); |
| - } else { |
| - bottom_shadow_ = rb->GetImageSkiaNamed(IDR_BUBBLE_B); |
| + if (g_top_shadow.Get().isNull()) { |
| + std::vector<gfx::ShadowValue> shadows; |
| + // Blur by 1dp. See comment below about blur accounting. |
|
Peter Kasting
2016/09/23 19:38:44
Argument for another day: It sure is weird to me t
Evan Stade
2016/09/26 18:11:42
that works better when there's no bookmark bar ---
Peter Kasting
2016/09/26 19:57:34
Yeah, we'd have to draw it ourselves, I just think
|
| + shadows.emplace_back(gfx::Vector2d(), 2, SK_ColorBLACK); |
| + |
| + auto source = new ShadowImageSource(shadows, false); |
| + g_top_shadow.Get() = gfx::ImageSkia(source, source->size()); |
|
Peter Kasting
2016/09/23 19:38:44
Musing: Wow, we really should fix https://bugs.chr
|
| + } |
| + if (g_bottom_shadow.Get().isNull()) { |
| + const int kSmallShadowBlur = 3; |
| + const int kLargeShadowBlur = 8; |
| + const int kLargeShadowYOffset = 3; |
| + |
| + std::vector<gfx::ShadowValue> shadows; |
| + // gfx::ShadowValue counts blur pixels both inside and outside the shape, |
| + // whereas these blur values only describe the outside portion, hence they |
| + // must be doubled. |
| + shadows.emplace_back(gfx::Vector2d(0, 0), 2 * kSmallShadowBlur, |
|
Peter Kasting
2016/09/23 19:38:44
Nit: Omit 0, 0
Evan Stade
2016/09/26 18:11:42
Done.
|
| + SK_ColorBLACK); |
| + shadows.emplace_back(gfx::Vector2d(0, kLargeShadowYOffset), |
| + 2 * kLargeShadowBlur, SK_ColorBLACK); |
| + |
| + auto source = new ShadowImageSource(shadows, true); |
| + g_bottom_shadow.Get() = gfx::ImageSkia(source, source->size()); |
| } |
| SetEventTargeter( |
| @@ -121,9 +183,8 @@ gfx::Rect OmniboxPopupContentsView::GetPopupBounds() const { |
| void OmniboxPopupContentsView::LayoutChildren() { |
| gfx::Rect contents_rect = GetContentsBounds(); |
| contents_rect.Inset(GetLayoutInsets(OMNIBOX_DROPDOWN)); |
| - contents_rect.Inset(start_margin_, |
| - views::NonClientFrameView::kClientEdgeThickness, |
| - end_margin_, 0); |
| + contents_rect.Inset(start_margin_, g_top_shadow.Get().height(), end_margin_, |
| + 0); |
| int top = contents_rect.y(); |
| for (size_t i = 0; i < AutocompleteResult::kMaxMatches; ++i) { |
| @@ -197,24 +258,12 @@ void OmniboxPopupContentsView::UpdatePopupAppearance() { |
| for (size_t i = result_size; i < AutocompleteResult::kMaxMatches; ++i) |
| child_at(i)->SetVisible(false); |
| - // In non-material mode, we want the popup to appear as if it's overlaying |
| - // the top of the page content, i.e., is flush against the client edge at the |
| - // bottom of the toolbar. However, if the bookmarks bar is attached, we want |
| - // to draw over it (so as not to push the results below it), but that means |
| - // the toolbar won't be drawing a client edge separating itself from the |
| - // popup. So we unconditionally overlap the toolbar by the thickness of the |
| - // client edge and draw our own edge (see OnPaint()), which fixes the |
| - // attached bookmark bar case without breaking the other case. |
| - int top_edge_overlap = views::NonClientFrameView::kClientEdgeThickness; |
| - if (ui::MaterialDesignController::IsModeMaterial()) { |
| - // In material mode, we cover the bookmark bar similarly, but instead of |
| - // appearing below the client edge, we want the popup to appear to overlay |
| - // the bottom of the toolbar. So instead of drawing a client edge atop the |
| - // popup, we shift the popup to completely cover the client edge, and then |
| - // draw an additional semitransparent shadow above that. So the total |
| - // overlap necessary is the client edge thickness plus the shadow height. |
| - top_edge_overlap += top_shadow_->height(); |
| - } |
| + // We want the popup to appear to overlay the bottom of the toolbar. So we |
| + // shift the popup to completely cover the client edge, and then draw an |
| + // additional semitransparent shadow above that. So the total overlap |
| + // necessary is the client edge thickness plus the shadow height. |
|
Peter Kasting
2016/09/23 19:38:44
Nit: Wondering if the last sentence just restates
Evan Stade
2016/09/26 18:11:42
Done.
|
| + int top_edge_overlap = views::NonClientFrameView::kClientEdgeThickness + |
| + g_top_shadow.Get().height(); |
| gfx::Point top_left_screen_coord; |
| int width; |
| @@ -421,10 +470,8 @@ int OmniboxPopupContentsView::CalculatePopupHeight() { |
| // Add enough space on the top and bottom so it looks like there is the same |
| // amount of space between the text and the popup border as there is in the |
| // interior between each row of text. |
| - return popup_height + views::NonClientFrameView::kClientEdgeThickness + |
| - GetLayoutInsets(OMNIBOX_DROPDOWN).height() + |
| - bottom_shadow_->height() - |
| - GetLayoutConstant(OMNIBOX_DROPDOWN_BORDER_INTERIOR); |
| + return popup_height + GetLayoutInsets(OMNIBOX_DROPDOWN).height() + |
| + g_top_shadow.Get().height() + g_bottom_shadow.Get().height(); |
| } |
| OmniboxResultView* OmniboxPopupContentsView::CreateResultView( |
| @@ -442,26 +489,17 @@ const char* OmniboxPopupContentsView::GetClassName() const { |
| } |
| void OmniboxPopupContentsView::OnPaint(gfx::Canvas* canvas) { |
| - // Top border. |
| - if (ui::MaterialDesignController::IsModeMaterial()) { |
| - canvas->TileImageInt(*top_shadow_, 0, 0, width(), top_shadow_->height()); |
| - } else { |
| - canvas->FillRect(gfx::Rect(0, 0, width(), |
| - views::NonClientFrameView::kClientEdgeThickness), |
| - location_bar_view_->GetThemeProvider()->GetColor( |
| - ThemeProperties::COLOR_TOOLBAR_BOTTOM_SEPARATOR)); |
| - } |
| - |
| - // Bottom border. |
| - canvas->TileImageInt(*bottom_shadow_, 0, height() - bottom_shadow_->height(), |
| - width(), bottom_shadow_->height()); |
| + canvas->TileImageInt(g_top_shadow.Get(), 0, 0, width(), |
| + g_top_shadow.Get().height()); |
| + canvas->TileImageInt(g_bottom_shadow.Get(), 0, |
| + height() - g_bottom_shadow.Get().height(), width(), |
| + g_bottom_shadow.Get().height()); |
| } |
| void OmniboxPopupContentsView::PaintChildren(const ui::PaintContext& context) { |
| gfx::Rect contents_bounds = GetContentsBounds(); |
| - const int interior = GetLayoutConstant(OMNIBOX_DROPDOWN_BORDER_INTERIOR); |
| - contents_bounds.Inset(0, views::NonClientFrameView::kClientEdgeThickness, 0, |
| - bottom_shadow_->height() - interior); |
| + contents_bounds.Inset(0, g_top_shadow.Get().height(), 0, |
| + g_bottom_shadow.Get().height()); |
| ui::ClipRecorder clip_recorder(context); |
| clip_recorder.ClipRect(contents_bounds); |