| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this |
| 2 // source code is governed by a BSD-style license that can be found in the | 2 // source code is governed by a BSD-style license that can be found in the |
| 3 // LICENSE file. | 3 // LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h" | 5 #include "chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h" |
| 6 | 6 |
| 7 #include <objidl.h> | 7 #include <objidl.h> |
| 8 #include <commctrl.h> | 8 #include <commctrl.h> |
| 9 #include <dwmapi.h> | 9 #include <dwmapi.h> |
| 10 | 10 |
| 11 #include "app/gfx/canvas.h" | 11 #include "app/gfx/canvas.h" |
| 12 #include "app/gfx/color_utils.h" | 12 #include "app/gfx/color_utils.h" |
| 13 #include "app/gfx/insets.h" | 13 #include "app/gfx/insets.h" |
| 14 #include "app/gfx/path.h" | 14 #include "app/gfx/path.h" |
| 15 #include "app/l10n_util.h" | 15 #include "app/l10n_util.h" |
| 16 #include "app/resource_bundle.h" | 16 #include "app/resource_bundle.h" |
| 17 #include "app/theme_provider.h" | 17 #include "app/theme_provider.h" |
| 18 #include "app/win_util.h" | 18 #include "app/win_util.h" |
| 19 #include "base/compiler_specific.h" | 19 #include "base/compiler_specific.h" |
| 20 #include "chrome/browser/autocomplete/autocomplete_edit_view_win.h" | 20 #include "chrome/browser/autocomplete/autocomplete_edit_view_win.h" |
| 21 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" | 21 #include "chrome/browser/autocomplete/autocomplete_popup_model.h" |
| 22 #include "chrome/browser/views/autocomplete/autocomplete_popup_win.h" | 22 #include "chrome/browser/views/autocomplete/autocomplete_popup_win.h" |
| 23 #include "grit/generated_resources.h" | 23 #include "grit/generated_resources.h" |
| 24 #include "grit/theme_resources.h" | 24 #include "grit/theme_resources.h" |
| 25 #include "third_party/skia/include/core/SkShader.h" | 25 #include "third_party/skia/include/core/SkShader.h" |
| 26 #include "third_party/icu38/public/common/unicode/ubidi.h" | 26 #include "third_party/icu38/public/common/unicode/ubidi.h" |
| 27 #include "views/widget/widget.h" | 27 #include "views/widget/widget.h" |
| 28 | 28 |
| 29 // Colors for various components of the view. | 29 namespace { |
| 30 static const SkColor kBackgroundColor = | 30 |
| 31 color_utils::GetSysSkColor(COLOR_WINDOW); | 31 enum ResultViewState { |
| 32 static const SkColor kSelectedBackgroundColor = | 32 NORMAL = 0, |
| 33 color_utils::GetSysSkColor(COLOR_HIGHLIGHT); | 33 SELECTED, |
| 34 static const SkColor kHoverBackgroundColor = | 34 HOVERED, |
| 35 SkColorSetA(kSelectedBackgroundColor, 127); | 35 NUM_STATES |
| 36 static const SkColor kTextColor = | 36 }; |
| 37 color_utils::GetSysSkColor(COLOR_WINDOWTEXT); | 37 |
| 38 static const SkColor kSelectedTextColor = | 38 enum ColorKind { |
| 39 color_utils::GetSysSkColor(COLOR_HIGHLIGHTTEXT); | 39 BACKGROUND = 0, |
| 40 static const SkColor kDimTextColor = | 40 TEXT, |
| 41 color_utils::GetSysSkColor(COLOR_GRAYTEXT); | 41 DIMMED_TEXT, |
| 42 static const SkColor kSelectedDimTextColor = | 42 URL, |
| 43 color_utils::GetSysSkColor(COLOR_HIGHLIGHTTEXT); | 43 NUM_KINDS |
| 44 static const SkColor kStandardURLColor = SkColorSetRGB(0, 0x80, 0); | 44 }; |
| 45 static const SkColor kHighlightURLColor = SkColorSetRGB(0xD0, 0xFF, 0xD0); | 45 |
| 46 static const int kGlassPopupTransparency = 240; | 46 SkColor GetColor(ResultViewState state, ColorKind kind) { |
| 47 static const int kOpaquePopupTransparency = 255; | 47 static bool initialized = false; |
| 48 static const int kHoverRowAlpha = 0x40; | 48 static SkColor colors[NUM_STATES][NUM_KINDS]; |
| 49 if (!initialized) { |
| 50 colors[NORMAL][BACKGROUND] = color_utils::GetSysSkColor(COLOR_WINDOW); |
| 51 colors[SELECTED][BACKGROUND] = color_utils::GetSysSkColor(COLOR_HIGHLIGHT); |
| 52 colors[NORMAL][TEXT] = color_utils::GetSysSkColor(COLOR_WINDOWTEXT); |
| 53 colors[SELECTED][TEXT] = color_utils::GetSysSkColor(COLOR_HIGHLIGHTTEXT); |
| 54 |
| 55 colors[HOVERED][BACKGROUND] = |
| 56 color_utils::AlphaBlend(colors[SELECTED][BACKGROUND], |
| 57 colors[NORMAL][BACKGROUND], 64); |
| 58 colors[HOVERED][TEXT] = colors[NORMAL][TEXT]; |
| 59 const SkColor kDarkURL = SkColorSetRGB(0, 128, 0); |
| 60 const SkColor kLightURL = SkColorSetRGB(128, 255, 128); |
| 61 for (int i = 0; i < NUM_STATES; ++i) { |
| 62 colors[i][DIMMED_TEXT] = |
| 63 color_utils::AlphaBlend(colors[i][TEXT], colors[i][BACKGROUND], 128); |
| 64 colors[i][URL] = color_utils::PickMoreReadableColor(kDarkURL, kLightURL, |
| 65 colors[i][BACKGROUND]); |
| 66 } |
| 67 initialized = true; |
| 68 } |
| 69 |
| 70 return colors[state][kind]; |
| 71 } |
| 72 |
| 73 const SkAlpha kGlassPopupAlpha = 240; |
| 74 const SkAlpha kOpaquePopupAlpha = 255; |
| 49 // The minimum distance between the top and bottom of the icon and the top or | 75 // The minimum distance between the top and bottom of the icon and the top or |
| 50 // bottom of the row. "Minimum" is used because the vertical padding may be | 76 // bottom of the row. "Minimum" is used because the vertical padding may be |
| 51 // larger, depending on the size of the text. | 77 // larger, depending on the size of the text. |
| 52 static const int kIconVerticalPadding = 2; | 78 const int kIconVerticalPadding = 2; |
| 53 // The minimum distance between the top and bottom of the text and the top or | 79 // The minimum distance between the top and bottom of the text and the top or |
| 54 // bottom of the row. See comment about the use of "minimum" for | 80 // bottom of the row. See comment about the use of "minimum" for |
| 55 // kIconVerticalPadding. | 81 // kIconVerticalPadding. |
| 56 static const int kTextVerticalPadding = 3; | 82 const int kTextVerticalPadding = 3; |
| 57 // The padding at the left edge of the row, left of the icon. | 83 // The padding at the left edge of the row, left of the icon. |
| 58 static const int kRowLeftPadding = 6; | 84 const int kRowLeftPadding = 6; |
| 59 // The padding on the right edge of the row, right of the text. | 85 // The padding on the right edge of the row, right of the text. |
| 60 static const int kRowRightPadding = 3; | 86 const int kRowRightPadding = 3; |
| 61 // The horizontal distance between the right edge of the icon and the left edge | 87 // The horizontal distance between the right edge of the icon and the left edge |
| 62 // of the text. | 88 // of the text. |
| 63 static const int kIconTextSpacing = 9; | 89 const int kIconTextSpacing = 9; |
| 64 // The size delta between the font used for the edit and the result rows. Passed | 90 // The size delta between the font used for the edit and the result rows. Passed |
| 65 // to gfx::Font::DeriveFont. | 91 // to gfx::Font::DeriveFont. |
| 66 static const int kEditFontAdjust = -1; | 92 const int kEditFontAdjust = -1; |
| 93 |
| 94 } |
| 67 | 95 |
| 68 class AutocompleteResultView : public views::View { | 96 class AutocompleteResultView : public views::View { |
| 69 public: | 97 public: |
| 70 AutocompleteResultView(AutocompleteResultViewModel* model, | 98 AutocompleteResultView(AutocompleteResultViewModel* model, |
| 71 int model_index, | 99 int model_index, |
| 72 const gfx::Font& font); | 100 const gfx::Font& font); |
| 73 virtual ~AutocompleteResultView(); | 101 virtual ~AutocompleteResultView(); |
| 74 | 102 |
| 75 // Updates the match used to paint the contents of this result view. We copy | 103 // Updates the match used to paint the contents of this result view. We copy |
| 76 // the match so that we can continue to paint the last result even after the | 104 // the match so that we can continue to paint the last result even after the |
| 77 // model has changed. | 105 // model has changed. |
| 78 void set_match(const AutocompleteMatch& match) { match_ = match; } | 106 void set_match(const AutocompleteMatch& match) { match_ = match; } |
| 79 | 107 |
| 80 // Overridden from views::View: | 108 // Overridden from views::View: |
| 81 virtual void Paint(gfx::Canvas* canvas); | 109 virtual void Paint(gfx::Canvas* canvas); |
| 82 virtual void Layout(); | 110 virtual void Layout(); |
| 83 virtual gfx::Size GetPreferredSize(); | 111 virtual gfx::Size GetPreferredSize(); |
| 84 virtual void OnMouseEntered(const views::MouseEvent& event); | 112 virtual void OnMouseEntered(const views::MouseEvent& event); |
| 85 virtual void OnMouseMoved(const views::MouseEvent& event); | 113 virtual void OnMouseMoved(const views::MouseEvent& event); |
| 86 virtual void OnMouseExited(const views::MouseEvent& event); | 114 virtual void OnMouseExited(const views::MouseEvent& event); |
| 87 virtual bool OnMousePressed(const views::MouseEvent& event); | 115 virtual bool OnMousePressed(const views::MouseEvent& event); |
| 88 virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled); | 116 virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled); |
| 89 virtual bool OnMouseDragged(const views::MouseEvent& event); | 117 virtual bool OnMouseDragged(const views::MouseEvent& event); |
| 90 | 118 |
| 91 private: | 119 private: |
| 92 // Get colors for row backgrounds and text for different row states. | 120 ResultViewState GetState() const; |
| 93 SkColor GetBackgroundColor() const; | |
| 94 SkColor GetTextColor() const; | |
| 95 | 121 |
| 96 SkBitmap* GetIcon() const; | 122 SkBitmap* GetIcon() const; |
| 97 | 123 |
| 98 // Draws the specified |text| into the canvas, using highlighting provided by | 124 // Draws the specified |text| into the canvas, using highlighting provided by |
| 99 // |classifications|. If |force_dim| is true, ACMatchClassification::DIM is | 125 // |classifications|. If |force_dim| is true, ACMatchClassification::DIM is |
| 100 // added to all of the classifications. Returns the x position to the right | 126 // added to all of the classifications. Returns the x position to the right |
| 101 // of the string. | 127 // of the string. |
| 102 int DrawString(gfx::Canvas* canvas, | 128 int DrawString(gfx::Canvas* canvas, |
| 103 const std::wstring& text, | 129 const std::wstring& text, |
| 104 const ACMatchClassifications& classifications, | 130 const ACMatchClassifications& classifications, |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 289 mirroring_context_(new MirroringContext()), | 315 mirroring_context_(new MirroringContext()), |
| 290 match_(NULL, 0, false, AutocompleteMatch::URL_WHAT_YOU_TYPED) { | 316 match_(NULL, 0, false, AutocompleteMatch::URL_WHAT_YOU_TYPED) { |
| 291 CHECK(model_index >= 0); | 317 CHECK(model_index >= 0); |
| 292 InitClass(); | 318 InitClass(); |
| 293 } | 319 } |
| 294 | 320 |
| 295 AutocompleteResultView::~AutocompleteResultView() { | 321 AutocompleteResultView::~AutocompleteResultView() { |
| 296 } | 322 } |
| 297 | 323 |
| 298 void AutocompleteResultView::Paint(gfx::Canvas* canvas) { | 324 void AutocompleteResultView::Paint(gfx::Canvas* canvas) { |
| 299 canvas->FillRectInt(GetBackgroundColor(), 0, 0, width(), height()); | 325 const ResultViewState state = GetState(); |
| 326 if (state != NORMAL) |
| 327 canvas->drawColor(GetColor(state, BACKGROUND)); |
| 300 | 328 |
| 301 int x = MirroredLeftPointForRect(icon_bounds_); | 329 int x = MirroredLeftPointForRect(icon_bounds_); |
| 302 | 330 |
| 303 // Paint the icon. | 331 // Paint the icon. |
| 304 canvas->DrawBitmapInt(*GetIcon(), x, icon_bounds_.y()); | 332 canvas->DrawBitmapInt(*GetIcon(), x, icon_bounds_.y()); |
| 305 | 333 |
| 306 // Paint the text. | 334 // Paint the text. |
| 307 // Initialize the |mirroring_context_| with the left and right positions. | 335 // Initialize the |mirroring_context_| with the left and right positions. |
| 308 // The DrawString() function uses this |mirroring_context_| to calculate the | 336 // The DrawString() function uses this |mirroring_context_| to calculate the |
| 309 // position of an input text. | 337 // position of an input text. |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 382 else if (event.IsOnlyLeftMouseButton()) | 410 else if (event.IsOnlyLeftMouseButton()) |
| 383 model_->OpenIndex(model_index_, CURRENT_TAB); | 411 model_->OpenIndex(model_index_, CURRENT_TAB); |
| 384 } | 412 } |
| 385 | 413 |
| 386 bool AutocompleteResultView::OnMouseDragged(const views::MouseEvent& event) { | 414 bool AutocompleteResultView::OnMouseDragged(const views::MouseEvent& event) { |
| 387 // TODO(beng): move all message handling into the contents view and override | 415 // TODO(beng): move all message handling into the contents view and override |
| 388 // GetViewForPoint. | 416 // GetViewForPoint. |
| 389 return false; | 417 return false; |
| 390 } | 418 } |
| 391 | 419 |
| 392 SkColor AutocompleteResultView::GetBackgroundColor() const { | 420 ResultViewState AutocompleteResultView::GetState() const { |
| 393 if (model_->IsSelectedIndex(model_index_)) | 421 if (model_->IsSelectedIndex(model_index_)) |
| 394 return kSelectedBackgroundColor; | 422 return SELECTED; |
| 395 return hot_ ? kHoverBackgroundColor : kBackgroundColor; | 423 return model_->IsHoveredIndex(model_index_) ? HOVERED : NORMAL; |
| 396 } | |
| 397 | |
| 398 SkColor AutocompleteResultView::GetTextColor() const { | |
| 399 return model_->IsSelectedIndex(model_index_) ? kSelectedTextColor | |
| 400 : kTextColor; | |
| 401 } | 424 } |
| 402 | 425 |
| 403 SkBitmap* AutocompleteResultView::GetIcon() const { | 426 SkBitmap* AutocompleteResultView::GetIcon() const { |
| 404 bool selected = model_->IsSelectedIndex(model_index_); | 427 bool selected = model_->IsSelectedIndex(model_index_); |
| 405 if (match_.starred) | 428 if (match_.starred) |
| 406 return selected ? icon_star_selected_ : icon_star_; | 429 return selected ? icon_star_selected_ : icon_star_; |
| 407 switch (match_.type) { | 430 switch (match_.type) { |
| 408 case AutocompleteMatch::URL_WHAT_YOU_TYPED: | 431 case AutocompleteMatch::URL_WHAT_YOU_TYPED: |
| 409 case AutocompleteMatch::HISTORY_URL: | 432 case AutocompleteMatch::HISTORY_URL: |
| 410 case AutocompleteMatch::NAVSUGGEST: | 433 case AutocompleteMatch::NAVSUGGEST: |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 string_width, display_font.height()); | 539 string_width, display_font.height()); |
| 517 return string_width; | 540 return string_width; |
| 518 } | 541 } |
| 519 | 542 |
| 520 gfx::Font AutocompleteResultView::GetFragmentFont(int style) const { | 543 gfx::Font AutocompleteResultView::GetFragmentFont(int style) const { |
| 521 return (style & ACMatchClassification::MATCH) ? | 544 return (style & ACMatchClassification::MATCH) ? |
| 522 font_.DeriveFont(0, gfx::Font::BOLD) : font_; | 545 font_.DeriveFont(0, gfx::Font::BOLD) : font_; |
| 523 } | 546 } |
| 524 | 547 |
| 525 SkColor AutocompleteResultView::GetFragmentTextColor(int style) const { | 548 SkColor AutocompleteResultView::GetFragmentTextColor(int style) const { |
| 526 bool selected = model_->IsSelectedIndex(model_index_); | 549 const ResultViewState state = GetState(); |
| 527 if (style & ACMatchClassification::URL) { | 550 if (style & ACMatchClassification::URL) |
| 528 // TODO(beng): bring over the contrast logic from the old popup and massage | 551 return GetColor(state, URL); |
| 529 // these values. See autocomplete_popup_view_win.cc and | 552 return GetColor(state, |
| 530 // LuminosityContrast etc. | 553 (style & ACMatchClassification::DIM) ? DIMMED_TEXT : TEXT); |
| 531 return selected ? kHighlightURLColor : kStandardURLColor; | |
| 532 } | |
| 533 if (style & ACMatchClassification::DIM) | |
| 534 return selected ? kSelectedDimTextColor : kDimTextColor; | |
| 535 return GetTextColor(); | |
| 536 } | 554 } |
| 537 | 555 |
| 538 void AutocompleteResultView::InitClass() { | 556 void AutocompleteResultView::InitClass() { |
| 539 if (!initialized_) { | 557 if (!initialized_) { |
| 540 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 558 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 541 icon_url_ = rb.GetBitmapNamed(IDR_O2_GLOBE); | 559 icon_url_ = rb.GetBitmapNamed(IDR_O2_GLOBE); |
| 542 icon_url_selected_ = rb.GetBitmapNamed(IDR_O2_GLOBE_SELECTED); | 560 icon_url_selected_ = rb.GetBitmapNamed(IDR_O2_GLOBE_SELECTED); |
| 543 icon_history_ = rb.GetBitmapNamed(IDR_O2_HISTORY); | 561 icon_history_ = rb.GetBitmapNamed(IDR_O2_HISTORY); |
| 544 icon_history_selected_ = rb.GetBitmapNamed(IDR_O2_HISTORY_SELECTED); | 562 icon_history_selected_ = rb.GetBitmapNamed(IDR_O2_HISTORY_SELECTED); |
| 545 icon_search_ = rb.GetBitmapNamed(IDR_O2_SEARCH); | 563 icon_search_ = rb.GetBitmapNamed(IDR_O2_SEARCH); |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 821 // | 839 // |
| 822 // Because the border of this view creates an anti-aliased round-rect region | 840 // Because the border of this view creates an anti-aliased round-rect region |
| 823 // for the contents, we need to render our rectangular result child views into | 841 // for the contents, we need to render our rectangular result child views into |
| 824 // this round rect region. We can't use a simple clip because clipping is | 842 // this round rect region. We can't use a simple clip because clipping is |
| 825 // 1-bit and we get nasty jagged edges. | 843 // 1-bit and we get nasty jagged edges. |
| 826 // | 844 // |
| 827 // Instead, we paint all our children into a second canvas and use that as a | 845 // Instead, we paint all our children into a second canvas and use that as a |
| 828 // shader to fill a path representing the round-rect clipping region. This | 846 // shader to fill a path representing the round-rect clipping region. This |
| 829 // yields a nice anti-aliased edge. | 847 // yields a nice anti-aliased edge. |
| 830 gfx::Canvas contents_canvas(width(), height(), true); | 848 gfx::Canvas contents_canvas(width(), height(), true); |
| 831 contents_canvas.FillRectInt(kBackgroundColor, 0, 0, width(), height()); | 849 contents_canvas.drawColor(GetColor(NORMAL, BACKGROUND)); |
| 832 View::PaintChildren(&contents_canvas); | 850 View::PaintChildren(&contents_canvas); |
| 833 // We want the contents background to be slightly transparent so we can see | 851 // We want the contents background to be slightly transparent so we can see |
| 834 // the blurry glass effect on DWM systems behind. We do this _after_ we paint | 852 // the blurry glass effect on DWM systems behind. We do this _after_ we paint |
| 835 // the children since they paint text, and GDI will reset this alpha data if | 853 // the children since they paint text, and GDI will reset this alpha data if |
| 836 // we paint text after this call. | 854 // we paint text after this call. |
| 837 MakeCanvasTransparent(&contents_canvas); | 855 MakeCanvasTransparent(&contents_canvas); |
| 838 | 856 |
| 839 // Now paint the contents of the contents canvas into the actual canvas. | 857 // Now paint the contents of the contents canvas into the actual canvas. |
| 840 SkPaint paint; | 858 SkPaint paint; |
| 841 paint.setAntiAlias(true); | 859 paint.setAntiAlias(true); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 918 MakeContentsPath(&contents_path, contents_rect); | 936 MakeContentsPath(&contents_path, contents_rect); |
| 919 ScopedGDIObject<HRGN> popup_region; | 937 ScopedGDIObject<HRGN> popup_region; |
| 920 popup_region.Set(contents_path.CreateHRGN()); | 938 popup_region.Set(contents_path.CreateHRGN()); |
| 921 bb.hRgnBlur = popup_region.Get(); | 939 bb.hRgnBlur = popup_region.Get(); |
| 922 DwmEnableBlurBehindWindow(GetWidget()->GetNativeView(), &bb); | 940 DwmEnableBlurBehindWindow(GetWidget()->GetNativeView(), &bb); |
| 923 } | 941 } |
| 924 | 942 |
| 925 void AutocompletePopupContentsView::MakeCanvasTransparent( | 943 void AutocompletePopupContentsView::MakeCanvasTransparent( |
| 926 gfx::Canvas* canvas) { | 944 gfx::Canvas* canvas) { |
| 927 // Allow the window blur effect to show through the popup background. | 945 // Allow the window blur effect to show through the popup background. |
| 928 SkPaint paint; | 946 SkAlpha alpha = GetThemeProvider()->ShouldUseNativeFrame() ? |
| 929 SkColor transparency = GetThemeProvider()->ShouldUseNativeFrame() ? | 947 kGlassPopupAlpha : kOpaquePopupAlpha; |
| 930 kGlassPopupTransparency : kOpaquePopupTransparency; | 948 canvas->drawColor(SkColorSetA(GetColor(NORMAL, BACKGROUND), alpha), |
| 931 paint.setColor(SkColorSetARGB(transparency, 255, 255, 255)); | 949 SkXfermode::kDstIn_Mode); |
| 932 paint.setXfermodeMode(SkXfermode::kDstIn_Mode); | |
| 933 paint.setStyle(SkPaint::kFill_Style); | |
| 934 canvas->FillRectInt(0, 0, canvas->getDevice()->width(), | |
| 935 canvas->getDevice()->height(), paint); | |
| 936 } | 950 } |
| OLD | NEW |