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..26297c76167f4abe6b5dd32450ed7cc4fe1a21c2 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,66 @@ |
#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/geometry/safe_integer_conversions.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() + gfx::ToCeiledInt(shadow.blur() / 2)); |
+ } |
+ 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 +118,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. |
+ shadows.emplace_back(gfx::Vector2d(), 2, SK_ColorBLACK); |
+ |
+ auto source = new ShadowImageSource(shadows, false); |
+ g_top_shadow.Get() = gfx::ImageSkia(source, source->size()); |
+ } |
+ 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(), 2 * kSmallShadowBlur, |
+ 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 +184,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 +259,11 @@ 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. |
+ 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); |