summaryrefslogtreecommitdiffstats
path: root/chrome/browser/views/autocomplete/autocomplete_popup_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/views/autocomplete/autocomplete_popup_win.cc')
-rw-r--r--chrome/browser/views/autocomplete/autocomplete_popup_win.cc229
1 files changed, 207 insertions, 22 deletions
diff --git a/chrome/browser/views/autocomplete/autocomplete_popup_win.cc b/chrome/browser/views/autocomplete/autocomplete_popup_win.cc
index 96290e9..6b01ba7 100644
--- a/chrome/browser/views/autocomplete/autocomplete_popup_win.cc
+++ b/chrome/browser/views/autocomplete/autocomplete_popup_win.cc
@@ -4,22 +4,201 @@
#include "chrome/browser/views/autocomplete/autocomplete_popup_win.h"
+#include <dwmapi.h>
+
#include "chrome/browser/autocomplete/autocomplete_edit_view_win.h"
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
+#include "chrome/common/gfx/chrome_canvas.h"
+#include "chrome/common/gfx/insets.h"
+#include "chrome/common/gfx/path.h"
+#include "chrome/common/resource_bundle.h"
#include "chrome/common/win_util.h"
+#include "grit/theme_resources.h"
+
+// The stroke color around the popup border.
+static const SkColor kEdgeColor = SkColorSetRGB(183, 195, 219);
+static const int kPopupTransparency = 235;
+
+class PopupBorder : public views::Border {
+ public:
+ PopupBorder() {
+ InitClass();
+ }
+ virtual ~PopupBorder() {}
+
+ // Returns the border radius of the edge of the popup.
+ static int GetBorderRadius() {
+ InitClass();
+ return dropshadow_topleft_->width() - dropshadow_left_->width();
+ }
+
+ // Overridden from views::Border:
+ virtual void Paint(const views::View& view, ChromeCanvas* canvas) const;
+ virtual void GetInsets(gfx::Insets* insets) const;
+
+ private:
+ // Border graphics.
+ static SkBitmap* dropshadow_left_;
+ static SkBitmap* dropshadow_topleft_;
+ static SkBitmap* dropshadow_top_;
+ static SkBitmap* dropshadow_topright_;
+ static SkBitmap* dropshadow_right_;
+ static SkBitmap* dropshadow_bottomright_;
+ static SkBitmap* dropshadow_bottom_;
+ static SkBitmap* dropshadow_bottomleft_;
+
+ static void InitClass();
+
+ DISALLOW_COPY_AND_ASSIGN(PopupBorder);
+};
+
+// static
+SkBitmap* PopupBorder::dropshadow_left_ = NULL;
+SkBitmap* PopupBorder::dropshadow_topleft_ = NULL;
+SkBitmap* PopupBorder::dropshadow_top_ = NULL;
+SkBitmap* PopupBorder::dropshadow_topright_ = NULL;
+SkBitmap* PopupBorder::dropshadow_right_ = NULL;
+SkBitmap* PopupBorder::dropshadow_bottomright_ = NULL;
+SkBitmap* PopupBorder::dropshadow_bottom_ = NULL;
+SkBitmap* PopupBorder::dropshadow_bottomleft_ = NULL;
+
+void PopupBorder::Paint(const views::View& view, ChromeCanvas* canvas) const {
+ int ds_tl_width = dropshadow_topleft_->width();
+ int ds_tl_height = dropshadow_topleft_->height();
+ int ds_tr_width = dropshadow_topright_->width();
+ int ds_tr_height = dropshadow_topright_->height();
+ int ds_br_width = dropshadow_bottomright_->width();
+ int ds_br_height = dropshadow_bottomright_->height();
+ int ds_bl_width = dropshadow_bottomleft_->width();
+ int ds_bl_height = dropshadow_bottomleft_->height();
+
+ canvas->DrawBitmapInt(*dropshadow_topleft_, 0, 0);
+ canvas->TileImageInt(*dropshadow_top_, ds_tl_width, 0,
+ view.width() - ds_tr_width - ds_tl_width,
+ dropshadow_top_->height());
+ canvas->DrawBitmapInt(*dropshadow_topright_, view.width() - ds_tr_width, 0);
+ canvas->TileImageInt(*dropshadow_right_,
+ view.width() - dropshadow_right_->width(),
+ ds_tr_height, dropshadow_right_->width(),
+ view.height() - ds_tr_height - ds_br_height);
+ canvas->DrawBitmapInt(*dropshadow_bottomright_, view.width() - ds_br_width,
+ view.height() - ds_br_height);
+ canvas->TileImageInt(*dropshadow_bottom_, ds_bl_width,
+ view.height() - dropshadow_bottom_->height(),
+ view.width() - ds_bl_width - ds_br_width,
+ dropshadow_bottom_->height());
+ canvas->DrawBitmapInt(*dropshadow_bottomleft_, 0,
+ view.height() - dropshadow_bottomleft_->height());
+ canvas->TileImageInt(*dropshadow_left_, 0, ds_tl_height,
+ dropshadow_left_->width(),
+ view.height() - ds_tl_height - ds_bl_height);
+}
+
+void PopupBorder::GetInsets(gfx::Insets* insets) const {
+ // The left, right and bottom edge image sizes define our insets. The corner
+ // images don't determine this because they can extend in both directions.
+ insets->Set(dropshadow_top_->height(), dropshadow_left_->width(),
+ dropshadow_bottom_->height(), dropshadow_right_->width());
+}
+
+void PopupBorder::InitClass() {
+ static bool initialized = false;
+ if (!initialized) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ dropshadow_left_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_L);
+ dropshadow_topleft_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_TL);
+ dropshadow_top_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_T);
+ dropshadow_topright_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_TR);
+ dropshadow_right_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_R);
+ dropshadow_bottomright_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_BR);
+ dropshadow_bottom_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_B);
+ dropshadow_bottomleft_ = rb.GetBitmapNamed(IDR_OMNIBOX_POPUP_DS_BL);
+ initialized = true;
+ }
+}
+
+class AutocompletePopupViewContents : public views::View {
+ public:
+ AutocompletePopupViewContents() {
+ set_border(new PopupBorder);
+ }
+ virtual ~AutocompletePopupViewContents() {}
+
+ // Overridden from views::View:
+ virtual void Paint(ChromeCanvas* canvas);
+ virtual void Layout();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AutocompletePopupViewContents);
+};
+
+void AutocompletePopupViewContents::Paint(ChromeCanvas* canvas) {
+ gfx::Rect contents_rect = GetLocalBounds(false);
+
+ {
+ SkPaint paint;
+ SkRect rect;
+ rect.set(SkIntToScalar(contents_rect.x()),
+ SkIntToScalar(contents_rect.y()),
+ SkIntToScalar(contents_rect.right()),
+ SkIntToScalar(contents_rect.bottom()));
+
+ SkScalar radius = SkIntToScalar(PopupBorder::GetBorderRadius());
+ paint.setColor(SK_ColorWHITE);
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawRoundRect(rect, radius, radius, paint);
+ }
+
+ // Allow the window blur effect to show through the popup background.
+ SkPaint paint;
+ paint.setColor(SkColorSetARGB(kPopupTransparency, 255, 255, 255));
+ paint.setPorterDuffXfermode(SkPorterDuff::kDstIn_Mode);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->FillRectInt(contents_rect.x(), contents_rect.y(),
+ contents_rect.width(), contents_rect.height(), paint);
+
+ // Paint the dropshadow.
+ PaintBorder(canvas);
+}
+
+void AutocompletePopupViewContents::Layout() {
+ // Provide a blurred background effect within the contents region of the
+ // popup.
+ DWM_BLURBEHIND bb = {0};
+ bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+ bb.fEnable = true;
+
+ gfx::Rect contents_rect = GetLocalBounds(false);
+ gfx::Point origin(contents_rect.origin());
+ views::View::ConvertPointToWidget(this, &origin);
+ contents_rect.set_origin(origin);
+
+ ScopedGDIObject<HRGN> popup_region;
+ popup_region.Set(CreateRectRgn(contents_rect.x(), contents_rect.y(),
+ contents_rect.right(),
+ contents_rect.bottom()));
+ bb.hRgnBlur = popup_region.Get();
+ DwmEnableBlurBehindWindow(GetWidget()->GetNativeView(), &bb);
+}
////////////////////////////////////////////////////////////////////////////////
// AutocompletePopupWin, public:
-AutocompletePopupWin::AutocompletePopupWin(const ChromeFont& font,
- AutocompleteEditViewWin* edit_view,
- AutocompleteEditModel* edit_model,
- Profile* profile)
+AutocompletePopupWin::AutocompletePopupWin(
+ const ChromeFont& font,
+ AutocompleteEditViewWin* edit_view,
+ AutocompleteEditModel* edit_model,
+ Profile* profile,
+ AutocompletePopupPositioner* popup_positioner)
: model_(new AutocompletePopupModel(this, edit_model, profile)),
- edit_view_(edit_view) {
+ edit_view_(edit_view),
+ popup_positioner_(popup_positioner),
+ contents_(new AutocompletePopupViewContents) {
set_delete_on_destroy(false);
set_window_style(WS_POPUP | WS_CLIPCHILDREN);
- set_window_ex_style(WS_EX_TOOLWINDOW);
+ set_window_ex_style(WS_EX_TOOLWINDOW | WS_EX_LAYERED);
+ contents_ = new AutocompletePopupViewContents;
}
AutocompletePopupWin::~AutocompletePopupWin() {
@@ -29,7 +208,7 @@ AutocompletePopupWin::~AutocompletePopupWin() {
// AutocompletePopupWin, AutocompletePopupView overrides:
bool AutocompletePopupWin::IsOpen() const {
- return false;
+ return IsWindow() && IsVisible();
}
void AutocompletePopupWin::InvalidateLine(size_t line) {
@@ -44,15 +223,24 @@ void AutocompletePopupWin::UpdatePopupAppearance() {
return;
}
- gfx::Rect popup_bounds = GetPopupScreenBounds();
+ gfx::Rect popup_bounds = GetPopupBounds();
if (!::IsWindow(GetNativeView())) {
// Create the popup
HWND parent_hwnd = edit_view_->parent_view()->GetWidget()->GetNativeView();
Init(parent_hwnd, popup_bounds, false);
- Show();
+ SetContentsView(contents_);
+
+ // When an IME is attached to the rich-edit control, retrieve its window
+ // handle and show this popup window under the IME windows.
+ // Otherwise, show this popup window under top-most windows.
+ // TODO(hbono): http://b/1111369 if we exclude this popup window from the
+ // display area of IME windows, this workaround becomes unnecessary.
+ HWND ime_window = ImmGetDefaultIMEWnd(edit_view_->m_hWnd);
+ SetWindowPos(ime_window ? ime_window : HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
} else {
// Move the popup
- int flags = 0;
+ int flags = SWP_NOACTIVATE;
if (!IsVisible())
flags |= SWP_SHOWWINDOW;
win_util::SetChildBounds(GetNativeView(), NULL, NULL, popup_bounds, 0,
@@ -73,16 +261,13 @@ AutocompletePopupModel* AutocompletePopupWin::GetModel() {
////////////////////////////////////////////////////////////////////////////////
// AutocompletePopupWin, private:
-gfx::Rect AutocompletePopupWin::GetPopupScreenBounds() const {
- gfx::Point popup_origin;
- views::View::ConvertPointToScreen(edit_view_->parent_view(), &popup_origin);
-
- gfx::Rect popup_bounds(popup_origin,
- edit_view_->parent_view()->bounds().size());
-
- // The popup starts at the bottom of the edit.
- popup_bounds.set_y(popup_bounds.bottom());
- popup_bounds.set_height(100);
- return popup_bounds;
+gfx::Rect AutocompletePopupWin::GetPopupBounds() const {
+ gfx::Insets insets;
+ contents_->border()->GetInsets(&insets);
+ gfx::Rect contents_bounds = popup_positioner_->GetPopupBounds();
+ contents_bounds.set_height(100); // TODO(beng): size to contents (once we have
+ // contents!)
+ contents_bounds.Inset(-insets.left(), -insets.top(), -insets.right(),
+ -insets.bottom());
+ return contents_bounds;
}
-