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 04bb74bcb783ba4cd6281b2a1d5d38b63aed88aa..57e080010e84f0130efe12cfae389386eb034609 100644 |
| --- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc |
| +++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc |
| @@ -22,6 +22,7 @@ |
| #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/image/image_skia_operations.h" |
| #include "ui/gfx/path.h" |
| @@ -33,10 +34,38 @@ |
| namespace { |
| -// Cache the shadow images so that potentially expensive shadow drawing isn't |
| +// This source takes two images and draws one above the other. |
| +class StackedImagesImageSource : public gfx::CanvasImageSource { |
| + public: |
| + StackedImagesImageSource(const gfx::ImageSkia& top, |
| + const gfx::ImageSkia& bottom) |
| + : CanvasImageSource( |
| + gfx::Size(top.width(), top.height() + bottom.height()), |
| + false), |
| + top_(top), |
| + bottom_(bottom) { |
| + DCHECK_EQ(top.width(), bottom.width()); |
| + } |
| + ~StackedImagesImageSource() override {} |
| + |
| + // CanvasImageSource overrides: |
| + void Draw(gfx::Canvas* canvas) override { |
| + canvas->DrawImageInt(top_, 0, 0); |
| + canvas->DrawImageInt(bottom_, 0, top_.height()); |
| + } |
| + |
| + private: |
| + const gfx::ImageSkia top_; |
| + const gfx::ImageSkia bottom_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(StackedImagesImageSource); |
| +}; |
| + |
| +// Cache the shadow image 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; |
| +static int g_top_shadow_height = 0; |
| +static int g_bottom_shadow_height = 0; |
| +base::LazyInstance<gfx::ImageSkia> g_shadow_ninebox = LAZY_INSTANCE_INITIALIZER; |
| } // namespace |
| @@ -83,30 +112,42 @@ OmniboxPopupContentsView::OmniboxPopupContentsView( |
| // The contents is owned by the LocationBarView. |
| set_owned_by_client(); |
| - if (g_top_shadow.Get().isNull()) { |
| - std::vector<gfx::ShadowValue> shadows; |
| + if (g_shadow_ninebox.Get().isNull()) { |
| + std::vector<gfx::ShadowValue> top_shadows; |
| // Blur by 1dp. See comment below about blur accounting. |
| - shadows.emplace_back(gfx::Vector2d(), 2, SK_ColorBLACK); |
| - g_top_shadow.Get() = |
| - gfx::ImageSkiaOperations::CreateHorizontalShadow(shadows, false); |
| - } |
| - if (g_bottom_shadow.Get().isNull()) { |
| + top_shadows.emplace_back(gfx::Vector2d(), 2, SK_ColorBLACK); |
| + gfx::ImageSkia top_shadow_image = |
| + gfx::ImageSkiaOperations::CreateHorizontalShadow(top_shadows, false); |
| + g_top_shadow_height = top_shadow_image.height(); |
| + |
| + // Values for the bottom shadow. |
| const int kSmallShadowBlur = 3; |
| const int kLargeShadowBlur = 8; |
| const int kLargeShadowYOffset = 3; |
| - std::vector<gfx::ShadowValue> shadows; |
| + std::vector<gfx::ShadowValue> bottom_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); |
| - |
| - g_bottom_shadow.Get() = |
| - gfx::ImageSkiaOperations::CreateHorizontalShadow(shadows, true); |
| + bottom_shadows.emplace_back(gfx::Vector2d(), 2 * kSmallShadowBlur, |
| + SK_ColorBLACK); |
| + bottom_shadows.emplace_back(gfx::Vector2d(0, kLargeShadowYOffset), |
| + 2 * kLargeShadowBlur, SK_ColorBLACK); |
| + |
| + gfx::ImageSkia bottom_shadow_image = |
| + gfx::ImageSkiaOperations::CreateHorizontalShadow(bottom_shadows, true); |
| + g_bottom_shadow_height = bottom_shadow_image.height(); |
| + auto source = |
| + new StackedImagesImageSource(top_shadow_image, bottom_shadow_image); |
| + g_shadow_ninebox.Get() = gfx::ImageSkia(source, source->size()); |
| } |
| + shadow_layer_.reset(new ui::Layer(ui::LAYER_NINE_PATCH)); |
| + shadow_layer_->SetFillsBoundsOpaquely(false); |
| + shadow_layer_->UpdateNinePatchLayerImage(g_shadow_ninebox.Get()); |
| + shadow_layer_->UpdateNinePatchLayerAperture( |
| + gfx::Rect(0, g_top_shadow_height, 1, 0)); |
| + shadow_layer_->UpdateNinePatchLayerBorder(gfx::Rect( |
| + 0, g_top_shadow_height, 0, g_top_shadow_height + g_bottom_shadow_height)); |
| SetEventTargeter( |
| std::unique_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); |
| @@ -148,8 +189,7 @@ gfx::Rect OmniboxPopupContentsView::GetPopupBounds() const { |
| void OmniboxPopupContentsView::LayoutChildren() { |
| gfx::Rect contents_rect = GetContentsBounds(); |
| contents_rect.Inset(GetLayoutInsets(OMNIBOX_DROPDOWN)); |
| - contents_rect.Inset(start_margin_, g_top_shadow.Get().height(), end_margin_, |
| - 0); |
| + contents_rect.Inset(start_margin_, g_top_shadow_height, end_margin_, 0); |
| int top = contents_rect.y(); |
| for (size_t i = 0; i < AutocompleteResult::kMaxMatches; ++i) { |
| @@ -226,8 +266,8 @@ void OmniboxPopupContentsView::UpdatePopupAppearance() { |
| // 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(); |
| + int top_edge_overlap = |
| + views::NonClientFrameView::kClientEdgeThickness + g_top_shadow_height; |
| gfx::Point top_left_screen_coord; |
| int width; |
| @@ -246,6 +286,13 @@ void OmniboxPopupContentsView::UpdatePopupAppearance() { |
| target_bounds_ = new_target_bounds; |
| if (!popup_) { |
| + // Create a new layer even if one already exists to make sure it's correctly |
| + // parented. |
|
Evan Stade
2016/12/01 02:39:02
I'm not entirely sure why this is necessary --- it
sadrul
2016/12/06 20:05:22
Yeah ... this seems weird.
|
| + SetPaintToLayer(false); |
| + SetPaintToLayer(true); |
| + layer()->SetFillsBoundsOpaquely(false); |
| + layer()->Add(shadow_layer_.get()); |
| + |
| views::Widget* popup_parent = location_bar_view_->GetWidget(); |
| // If the popup is currently closed, we need to create it. |
| @@ -357,6 +404,15 @@ views::View* OmniboxPopupContentsView::GetTooltipHandlerForPoint( |
| return nullptr; |
| } |
| +void OmniboxPopupContentsView::OnBoundsChanged( |
| + const gfx::Rect& previous_bounds) { |
| + gfx::Rect shadow_bounds = GetLocalBounds(); |
| + shadow_layer_->SetBounds(shadow_bounds); |
| + shadow_bounds.Inset( |
| + gfx::Insets(g_top_shadow_height, 0, g_bottom_shadow_height, 0)); |
| + shadow_layer_->UpdateNinePatchOcclusion(shadow_bounds); |
|
sadrul
2016/12/06 20:05:22
ui::Shadow seems to update layer-border/aperture a
|
| +} |
| + |
| bool OmniboxPopupContentsView::OnMousePressed( |
| const ui::MouseEvent& event) { |
| ignore_mouse_drag_ = false; // See comment on |ignore_mouse_drag_| in header. |
| @@ -435,7 +491,7 @@ int OmniboxPopupContentsView::CalculatePopupHeight() { |
| // amount of space between the text and the popup border as there is in the |
| // interior between each row of text. |
| return popup_height + GetLayoutInsets(OMNIBOX_DROPDOWN).height() + |
| - g_top_shadow.Get().height() + g_bottom_shadow.Get().height(); |
| + g_top_shadow_height + g_bottom_shadow_height; |
| } |
| OmniboxResultView* OmniboxPopupContentsView::CreateResultView( |
| @@ -451,18 +507,10 @@ const char* OmniboxPopupContentsView::GetClassName() const { |
| return "OmniboxPopupContentsView"; |
| } |
| -void OmniboxPopupContentsView::OnPaint(gfx::Canvas* canvas) { |
| - 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(); |
| - contents_bounds.Inset(0, g_top_shadow.Get().height(), 0, |
| - g_bottom_shadow.Get().height()); |
| + contents_bounds.Inset( |
| + gfx::Insets(g_top_shadow_height, 0, g_bottom_shadow_height, 0)); |
| ui::ClipRecorder clip_recorder(context); |
| clip_recorder.ClipRect(contents_bounds); |