Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // For WinDDK ATL compatibility, these ATL headers must come first. | 5 // For WinDDK ATL compatibility, these ATL headers must come first. |
| 6 #include "build/build_config.h" | 6 #include "build/build_config.h" |
| 7 | 7 |
| 8 #if defined(OS_WIN) | 8 #if defined(OS_WIN) |
| 9 #include <atlbase.h> // NOLINT | 9 #include <atlbase.h> // NOLINT |
| 10 #include <atlwin.h> // NOLINT | 10 #include <atlwin.h> // NOLINT |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 43 #include "ui/gfx/paint_vector_icon.h" | 43 #include "ui/gfx/paint_vector_icon.h" |
| 44 #include "ui/gfx/range/range.h" | 44 #include "ui/gfx/range/range.h" |
| 45 #include "ui/gfx/render_text.h" | 45 #include "ui/gfx/render_text.h" |
| 46 #include "ui/gfx/text_utils.h" | 46 #include "ui/gfx/text_utils.h" |
| 47 #include "ui/native_theme/native_theme.h" | 47 #include "ui/native_theme/native_theme.h" |
| 48 | 48 |
| 49 using ui::NativeTheme; | 49 using ui::NativeTheme; |
| 50 | 50 |
| 51 namespace { | 51 namespace { |
| 52 | 52 |
| 53 // The padding that should be placed between content and description in a | 53 // The vertical margin that should be used above and below each suggestion. |
| 54 // vertical layout. | 54 static const int kVerticalMargin = 1; |
|
Peter Kasting
2017/06/13 23:42:50
So why a margin of 1 and padding of 4 instead of a
Justin Donnelly
2017/06/15 18:56:53
Because that won't work in the multi-part case (an
Peter Kasting
2017/06/15 22:43:34
OK, but using 1 and 4 is sufficient for your needs
Justin Donnelly
2017/06/16 14:14:30
Yes. I've tested this extensively on Linux and Win
| |
| 55 static const int kVerticalPadding = 3; | 55 |
| 56 // The vertical padding to provide each RenderText in addition to the height of | |
| 57 // the font. Where possible, RenderText uses this additional space to vertically | |
| 58 // center the cap height of the font instead of centering the entire font. | |
| 59 static const int kVerticalPadding = 4; | |
|
Peter Kasting
2017/06/13 23:42:50
Nit: kAdditionalTextLineHeight?
Should this just
Justin Donnelly
2017/06/15 18:56:53
That would add additional, undesired space between
| |
| 56 | 60 |
| 57 // A mapping from OmniboxResultView's ResultViewState/ColorKind types to | 61 // A mapping from OmniboxResultView's ResultViewState/ColorKind types to |
| 58 // NativeTheme colors. | 62 // NativeTheme colors. |
| 59 struct TranslationTable { | 63 struct TranslationTable { |
| 60 ui::NativeTheme::ColorId id; | 64 ui::NativeTheme::ColorId id; |
| 61 OmniboxResultView::ResultViewState state; | 65 OmniboxResultView::ResultViewState state; |
| 62 OmniboxResultView::ColorKind kind; | 66 OmniboxResultView::ColorKind kind; |
| 63 } static const kTranslationTable[] = { | 67 } static const kTranslationTable[] = { |
| 64 { NativeTheme::kColorId_ResultsTableNormalBackground, | 68 { NativeTheme::kColorId_ResultsTableNormalBackground, |
| 65 OmniboxResultView::NORMAL, OmniboxResultView::BACKGROUND }, | 69 OmniboxResultView::NORMAL, OmniboxResultView::BACKGROUND }, |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 296 // selected. The non-answer text is already accessible as a consequence of | 300 // selected. The non-answer text is already accessible as a consequence of |
| 297 // updating the text in the omnibox but this alert and GetAccessibleNodeData | 301 // updating the text in the omnibox but this alert and GetAccessibleNodeData |
| 298 // below make the answer contents accessible. | 302 // below make the answer contents accessible. |
| 299 if (match_.answer) | 303 if (match_.answer) |
| 300 NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); | 304 NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); |
| 301 } | 305 } |
| 302 | 306 |
| 303 gfx::Size OmniboxResultView::CalculatePreferredSize() const { | 307 gfx::Size OmniboxResultView::CalculatePreferredSize() const { |
| 304 int height = GetTextHeight() + (2 * GetVerticalMargin()); | 308 int height = GetTextHeight() + (2 * GetVerticalMargin()); |
| 305 if (match_.answer) | 309 if (match_.answer) |
| 306 height += GetAnswerHeight() + kVerticalPadding; | 310 height += GetAnswerHeight(); |
| 307 else if (base::FeatureList::IsEnabled(omnibox::kUIExperimentVerticalLayout)) | 311 else if (base::FeatureList::IsEnabled(omnibox::kUIExperimentVerticalLayout)) |
| 308 height += GetTextHeight() + kVerticalPadding; | 312 height += GetTextHeight(); |
| 309 return gfx::Size(0, height); | 313 return gfx::Size(0, height); |
| 310 } | 314 } |
| 311 | 315 |
| 312 void OmniboxResultView::GetAccessibleNodeData(ui::AXNodeData* node_data) { | 316 void OmniboxResultView::GetAccessibleNodeData(ui::AXNodeData* node_data) { |
| 313 node_data->SetName(match_.answer | 317 node_data->SetName(match_.answer |
| 314 ? l10n_util::GetStringFUTF16( | 318 ? l10n_util::GetStringFUTF16( |
| 315 IDS_OMNIBOX_ACCESSIBLE_ANSWER, match_.contents, | 319 IDS_OMNIBOX_ACCESSIBLE_ANSWER, match_.contents, |
| 316 match_.answer->second_line().AccessibleText()) | 320 match_.answer->second_line().AccessibleText()) |
| 317 : match_.contents); | 321 : match_.contents); |
| 318 } | 322 } |
| 319 | 323 |
| 320 void OmniboxResultView::OnNativeThemeChanged(const ui::NativeTheme* theme) { | 324 void OmniboxResultView::OnNativeThemeChanged(const ui::NativeTheme* theme) { |
| 321 Invalidate(); | 325 Invalidate(); |
| 322 SchedulePaint(); | 326 SchedulePaint(); |
| 323 } | 327 } |
| 324 | 328 |
| 325 //////////////////////////////////////////////////////////////////////////////// | 329 //////////////////////////////////////////////////////////////////////////////// |
| 326 // OmniboxResultView, protected: | 330 // OmniboxResultView, protected: |
| 327 | 331 |
| 328 OmniboxResultView::ResultViewState OmniboxResultView::GetState() const { | 332 OmniboxResultView::ResultViewState OmniboxResultView::GetState() const { |
| 329 if (model_->IsSelectedIndex(model_index_)) | 333 if (model_->IsSelectedIndex(model_index_)) |
| 330 return SELECTED; | 334 return SELECTED; |
| 331 return model_->IsHoveredIndex(model_index_) ? HOVERED : NORMAL; | 335 return model_->IsHoveredIndex(model_index_) ? HOVERED : NORMAL; |
| 332 } | 336 } |
| 333 | 337 |
| 334 int OmniboxResultView::GetTextHeight() const { | 338 int OmniboxResultView::GetTextHeight() const { |
| 335 return font_height_; | 339 return font_height_ + kVerticalPadding; |
| 336 } | 340 } |
| 337 | 341 |
| 338 void OmniboxResultView::PaintMatch(const AutocompleteMatch& match, | 342 void OmniboxResultView::PaintMatch(const AutocompleteMatch& match, |
| 339 gfx::RenderText* contents, | 343 gfx::RenderText* contents, |
| 340 gfx::RenderText* description, | 344 gfx::RenderText* description, |
| 341 gfx::Canvas* canvas, | 345 gfx::Canvas* canvas, |
| 342 int x) const { | 346 int x) const { |
| 343 int y = text_bounds_.y() + GetVerticalMargin(); | 347 int y = text_bounds_.y() + GetVerticalMargin(); |
| 344 | 348 |
| 345 if (!separator_rendertext_) { | 349 if (!separator_rendertext_) { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 360 OmniboxPopupModel::ComputeMatchMaxWidths( | 364 OmniboxPopupModel::ComputeMatchMaxWidths( |
| 361 contents->GetContentWidth(), separator_width_, | 365 contents->GetContentWidth(), separator_width_, |
| 362 description ? description->GetContentWidth() : 0, | 366 description ? description->GetContentWidth() : 0, |
| 363 mirroring_context_->remaining_width(x), description_on_separate_line, | 367 mirroring_context_->remaining_width(x), description_on_separate_line, |
| 364 !AutocompleteMatch::IsSearchType(match.type), &contents_max_width, | 368 !AutocompleteMatch::IsSearchType(match.type), &contents_max_width, |
| 365 &description_max_width); | 369 &description_max_width); |
| 366 | 370 |
| 367 // Answers in Suggest results. | 371 // Answers in Suggest results. |
| 368 if (match.answer && description_max_width != 0) { | 372 if (match.answer && description_max_width != 0) { |
| 369 DrawRenderText(match, contents, CONTENTS, canvas, x, y, contents_max_width); | 373 DrawRenderText(match, contents, CONTENTS, canvas, x, y, contents_max_width); |
| 370 y += GetTextHeight() + kVerticalPadding; | 374 y += GetTextHeight(); |
| 371 if (!answer_image_.isNull()) { | 375 if (!answer_image_.isNull()) { |
| 372 int answer_icon_size = GetAnswerHeight(); | 376 int answer_icon_size = GetAnswerHeight(); |
| 373 canvas->DrawImageInt(answer_image_, 0, 0, answer_image_.width(), | 377 canvas->DrawImageInt(answer_image_, 0, 0, answer_image_.width(), |
| 374 answer_image_.height(), GetMirroredXInView(x), y, | 378 answer_image_.height(), GetMirroredXInView(x), y, |
| 375 answer_icon_size, answer_icon_size, true); | 379 answer_icon_size, answer_icon_size, true); |
| 376 // TODO(dschuyler): Perhaps this should be based on the font size | 380 // TODO(dschuyler): Perhaps this should be based on the font size |
| 377 // instead of hardcoded to 2 dp (e.g. by adding a space in an | 381 // instead of hardcoded to 2 dp (e.g. by adding a space in an |
| 378 // appropriate font to the beginning of the description, then reducing | 382 // appropriate font to the beginning of the description, then reducing |
| 379 // the additional padding here to zero). | 383 // the additional padding here to zero). |
| 380 const int kAnswerIconToTextPadding = 2; | 384 const int kAnswerIconToTextPadding = 2; |
| 381 x += answer_icon_size + kAnswerIconToTextPadding; | 385 x += answer_icon_size + kAnswerIconToTextPadding; |
| 382 } | 386 } |
| 383 DrawRenderText(match, description, DESCRIPTION, canvas, x, y, | 387 DrawRenderText(match, description, DESCRIPTION, canvas, x, y, |
| 384 description_max_width); | 388 description_max_width); |
| 385 return; | 389 return; |
| 386 } | 390 } |
| 387 | 391 |
| 388 // Regular results. | 392 // Regular results. |
| 389 if (base::FeatureList::IsEnabled(omnibox::kUIExperimentVerticalLayout)) { | 393 if (base::FeatureList::IsEnabled(omnibox::kUIExperimentVerticalLayout)) { |
| 390 // For no description, shift down halfways to draw contents in middle. | 394 // For no description, shift down halfways to draw contents in middle. |
| 391 if (description_max_width == 0) | 395 if (description_max_width == 0) |
| 392 y += (GetTextHeight() + kVerticalPadding) / 2; | 396 y += GetTextHeight() / 2; |
| 393 | 397 |
| 394 DrawRenderText(match, contents, CONTENTS, canvas, x, y, contents_max_width); | 398 DrawRenderText(match, contents, CONTENTS, canvas, x, y, contents_max_width); |
| 395 | 399 |
| 396 if (description_max_width != 0) { | 400 if (description_max_width != 0) { |
| 397 y += GetTextHeight() + kVerticalPadding; | 401 y += GetTextHeight(); |
| 398 DrawRenderText(match, description, DESCRIPTION, canvas, x, y, | 402 DrawRenderText(match, description, DESCRIPTION, canvas, x, y, |
| 399 description_max_width); | 403 description_max_width); |
| 400 } | 404 } |
| 401 } else { | 405 } else { |
| 402 x = DrawRenderText(match, contents, CONTENTS, canvas, x, y, | 406 x = DrawRenderText(match, contents, CONTENTS, canvas, x, y, |
| 403 contents_max_width); | 407 contents_max_width); |
| 404 if (description_max_width != 0) { | 408 if (description_max_width != 0) { |
| 405 x = DrawRenderText(match, separator_rendertext_.get(), SEPARATOR, canvas, | 409 x = DrawRenderText(match, separator_rendertext_.get(), SEPARATOR, canvas, |
| 406 x, y, separator_width_); | 410 x, y, separator_width_); |
| 407 DrawRenderText(match, description, DESCRIPTION, canvas, x, y, | 411 DrawRenderText(match, description, DESCRIPTION, canvas, x, y, |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 640 // the omnibox border outline shape exactly in OnPaint(). We have to inset | 644 // the omnibox border outline shape exactly in OnPaint(). We have to inset |
| 641 // here to keep the icons lined up. | 645 // here to keep the icons lined up. |
| 642 const int start_x = BackgroundWith1PxBorder::kLocationBarBorderThicknessDip + | 646 const int start_x = BackgroundWith1PxBorder::kLocationBarBorderThicknessDip + |
| 643 horizontal_padding; | 647 horizontal_padding; |
| 644 const int end_x = width() - start_x; | 648 const int end_x = width() - start_x; |
| 645 | 649 |
| 646 const gfx::ImageSkia icon = GetIcon(); | 650 const gfx::ImageSkia icon = GetIcon(); |
| 647 | 651 |
| 648 int row_height = GetTextHeight(); | 652 int row_height = GetTextHeight(); |
| 649 if (base::FeatureList::IsEnabled(omnibox::kUIExperimentVerticalLayout)) | 653 if (base::FeatureList::IsEnabled(omnibox::kUIExperimentVerticalLayout)) |
| 650 row_height += kVerticalPadding + GetTextHeight(); | 654 row_height += match_.answer ? GetTextHeight() : GetAnswerHeight(); |
| 651 | 655 |
| 652 const int icon_y = GetVerticalMargin() + (row_height - icon.height()) / 2; | 656 const int icon_y = GetVerticalMargin() + (row_height - icon.height()) / 2; |
| 653 icon_bounds_.SetRect(start_x, icon_y, icon.width(), icon.height()); | 657 icon_bounds_.SetRect(start_x, icon_y, icon.width(), icon.height()); |
| 654 | 658 |
| 655 const int text_x = start_x + LocationBarView::kIconWidth + horizontal_padding; | 659 const int text_x = start_x + LocationBarView::kIconWidth + horizontal_padding; |
| 656 int text_width = end_x - text_x; | 660 int text_width = end_x - text_x; |
| 657 | 661 |
| 658 if (match_.associated_keyword.get()) { | 662 if (match_.associated_keyword.get()) { |
| 659 const int max_kw_x = end_x - keyword_icon_->width(); | 663 const int max_kw_x = end_x - keyword_icon_->width(); |
| 660 const int kw_x = animation_->CurrentValueBetween(max_kw_x, start_x); | 664 const int kw_x = animation_->CurrentValueBetween(max_kw_x, start_x); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 740 ? match_.answer->second_line().text_fields()[0].type() | 744 ? match_.answer->second_line().text_fields()[0].type() |
| 741 : SuggestionAnswer::SUGGESTION; | 745 : SuggestionAnswer::SUGGESTION; |
| 742 return ui::ResourceBundle::GetSharedInstance().GetFontList( | 746 return ui::ResourceBundle::GetSharedInstance().GetFontList( |
| 743 GetTextStyle(text_type).font); | 747 GetTextStyle(text_type).font); |
| 744 } | 748 } |
| 745 | 749 |
| 746 int OmniboxResultView::GetAnswerHeight() const { | 750 int OmniboxResultView::GetAnswerHeight() const { |
| 747 // If the answer specifies a maximum of 1 line we can simply return the answer | 751 // If the answer specifies a maximum of 1 line we can simply return the answer |
| 748 // font height. | 752 // font height. |
| 749 if (match_.answer->second_line().num_text_lines() == 1) | 753 if (match_.answer->second_line().num_text_lines() == 1) |
| 750 return GetAnswerFont().GetHeight(); | 754 return GetAnswerFont().GetHeight() + kVerticalPadding; |
| 751 | 755 |
| 752 // Multi-line answers require layout in order to determine the number of lines | 756 // Multi-line answers require layout in order to determine the number of lines |
| 753 // the RenderText will use. | 757 // the RenderText will use. |
| 754 if (!description_rendertext_) { | 758 if (!description_rendertext_) { |
| 755 description_rendertext_ = | 759 description_rendertext_ = |
| 756 CreateAnswerText(match_.answer->second_line(), GetAnswerFont()); | 760 CreateAnswerText(match_.answer->second_line(), GetAnswerFont()); |
| 757 } | 761 } |
| 758 description_rendertext_->SetDisplayRect(gfx::Rect(text_bounds_.width(), 0)); | 762 description_rendertext_->SetDisplayRect(gfx::Rect(text_bounds_.width(), 0)); |
| 759 description_rendertext_->GetStringSize(); | 763 description_rendertext_->GetStringSize(); |
| 760 return GetAnswerFont().GetHeight() * description_rendertext_->GetNumLines(); | 764 return (GetAnswerFont().GetHeight() * |
| 765 description_rendertext_->GetNumLines()) + | |
| 766 kVerticalPadding; | |
| 761 } | 767 } |
| 762 | 768 |
| 763 int OmniboxResultView::GetVerticalMargin() const { | 769 int OmniboxResultView::GetVerticalMargin() const { |
| 764 // Regardless of the text size, we ensure a minimum size for the content line | 770 // Regardless of the text size, we ensure a minimum size for the content line |
| 765 // here. This minimum is larger for hybrid mouse/touch devices to ensure an | 771 // here. This minimum is larger for hybrid mouse/touch devices to ensure an |
| 766 // adequately sized touch target. | 772 // adequately sized touch target. |
| 767 using Md = ui::MaterialDesignController; | 773 using Md = ui::MaterialDesignController; |
| 768 const int kIconVerticalPad = base::GetFieldTrialParamByFeatureAsInt( | 774 const int kIconVerticalPad = base::GetFieldTrialParamByFeatureAsInt( |
| 769 omnibox::kUIExperimentVerticalMargin, | 775 omnibox::kUIExperimentVerticalMargin, |
| 770 OmniboxFieldTrial::kUIVerticalMarginParam, | 776 OmniboxFieldTrial::kUIVerticalMarginParam, |
| 771 Md::GetMode() == Md::MATERIAL_HYBRID ? 8 : 4); | 777 Md::GetMode() == Md::MATERIAL_HYBRID ? 8 : 4); |
| 772 const int min_height = LocationBarView::kIconWidth + 2 * kIconVerticalPad; | 778 const int min_height = LocationBarView::kIconWidth + 2 * kIconVerticalPad; |
| 773 | 779 |
| 774 return std::max(kVerticalPadding, (min_height - GetTextHeight()) / 2); | 780 return std::max(kVerticalMargin, (min_height - GetTextHeight()) / 2); |
| 775 } | 781 } |
| 776 | 782 |
| 777 std::unique_ptr<gfx::RenderText> OmniboxResultView::CreateAnswerText( | 783 std::unique_ptr<gfx::RenderText> OmniboxResultView::CreateAnswerText( |
| 778 const SuggestionAnswer::ImageLine& line, | 784 const SuggestionAnswer::ImageLine& line, |
| 779 const gfx::FontList& font_list) const { | 785 const gfx::FontList& font_list) const { |
| 780 std::unique_ptr<gfx::RenderText> destination = | 786 std::unique_ptr<gfx::RenderText> destination = |
| 781 CreateRenderText(base::string16()); | 787 CreateRenderText(base::string16()); |
| 782 destination->SetFontList(font_list); | 788 destination->SetFontList(font_list); |
| 783 | 789 |
| 784 for (const SuggestionAnswer::TextField& text_field : line.text_fields()) | 790 for (const SuggestionAnswer::TextField& text_field : line.text_fields()) |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 846 destination->AppendText(text); | 852 destination->AppendText(text); |
| 847 const TextStyle& text_style = GetTextStyle(text_type); | 853 const TextStyle& text_style = GetTextStyle(text_type); |
| 848 // TODO(dschuyler): follow up on the problem of different font sizes within | 854 // TODO(dschuyler): follow up on the problem of different font sizes within |
| 849 // one RenderText. Maybe with destination->SetFontList(...). | 855 // one RenderText. Maybe with destination->SetFontList(...). |
| 850 destination->ApplyWeight( | 856 destination->ApplyWeight( |
| 851 is_bold ? gfx::Font::Weight::BOLD : gfx::Font::Weight::NORMAL, range); | 857 is_bold ? gfx::Font::Weight::BOLD : gfx::Font::Weight::NORMAL, range); |
| 852 destination->ApplyColor( | 858 destination->ApplyColor( |
| 853 GetNativeTheme()->GetSystemColor(text_style.colors[GetState()]), range); | 859 GetNativeTheme()->GetSystemColor(text_style.colors[GetState()]), range); |
| 854 destination->ApplyBaselineStyle(text_style.baseline, range); | 860 destination->ApplyBaselineStyle(text_style.baseline, range); |
| 855 } | 861 } |
| OLD | NEW |