omnibox_result_view.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For WinDDK ATL compatibility, these ATL headers must come first.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <atlbase.h>  // NOLINT
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <atlwin.h>  // NOLINT
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/omnibox/omnibox_result_view.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>  // NOLINT
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/bidi_line_iterator.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_vector.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/omnibox/omnibox_result_view_model.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/text/text_elider.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/color_utils.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/render_text.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme_win.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme_aura.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char16 kEllipsis[] = { 0x2026, 0x0 };
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The minimum distance between the top and bottom of the {icon|text} and the
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// top or bottom of the row.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMinimumIconVerticalPadding = 2;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMinimumTextVerticalPadding = 3;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OmniboxResultView, public:
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Precalculated data used to draw a complete visual run within the match.
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// This will include all or part of at least one, and possibly several,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// classifications.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct OmniboxResultView::RunData {
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RunData() : run_start(0), visual_order(0), is_rtl(false), pixel_width(0) {}
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t run_start;  // Offset within the match text where this run begins.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int visual_order;  // Where this run occurs in visual order.  The earliest
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // run drawn is run 0.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_rtl;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pixel_width;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Styled text classification pieces within this run, in logical order.
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Classifications classifications;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class is a utility class for calculations affected by whether the result
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// view is horizontally mirrored.  The drawing functions can be written as if
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// all drawing occurs left-to-right, and then use this class to get the actual
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// coordinates to begin drawing onscreen.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OmniboxResultView::MirroringContext {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MirroringContext() : center_(0), right_(0) {}
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tells the mirroring context to use the provided range as the physical
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // bounds of the drawing region.  When coordinate mirroring is needed, the
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // mirror point will be the center of this range.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Initialize(int x, int width) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    center_ = x + width / 2;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    right_ = x + width;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Given a logical range within the drawing region, returns the coordinate of
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the possibly-mirrored "left" side.  (This functions exactly like
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // View::MirroredLeftPointForRect().)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int mirrored_left_coord(int left, int right) const {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return base::i18n::IsRTL() ? (center_ + (center_ - right)) : left;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Given a logical coordinate within the drawing region, returns the remaining
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // width available.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int remaining_width(int x) const {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return right_ - x;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int center_;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int right_;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MirroringContext);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OmniboxResultView::OmniboxResultView(
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OmniboxResultViewModel* model,
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int model_index,
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gfx::Font& font)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : edge_item_padding_(LocationBarView::GetItemPadding()),
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      item_padding_(LocationBarView::GetItemPadding()),
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      minimum_text_vertical_padding_(kMinimumTextVerticalPadding),
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_(model),
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_index_(model_index),
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      font_(font),
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      font_height_(std::max(font.GetHeight(),
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            font.DeriveFont(0, gfx::BOLD).GetHeight())),
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ellipsis_width_(font.GetStringWidth(string16(kEllipsis))),
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mirroring_context_(new MirroringContext()),
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      keyword_icon_(new views::ImageView()),
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ALLOW_THIS_IN_INITIALIZER_LIST(
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          animation_(new ui::SlideAnimation(this))) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_GE(model_index, 0);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (default_icon_size_ == 0) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_icon_size_ =
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        AutocompleteMatch::TypeToIcon(AutocompleteMatch::URL_WHAT_YOU_TYPED))->
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        width();
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keyword_icon_->set_owned_by_client();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keyword_icon_->EnableCanvasFlippingForRTLUI(true);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keyword_icon_->SetImage(GetKeywordIcon());
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keyword_icon_->SizeToPreferredSize();
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OmniboxResultView::~OmniboxResultView() {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkColor OmniboxResultView::GetColor(
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResultViewState state,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ColorKind kind) const {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ui::NativeTheme* theme = GetNativeTheme();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (theme == ui::NativeThemeWin::instance()) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static bool win_initialized = false;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static SkColor win_colors[NUM_STATES][NUM_KINDS];
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!win_initialized) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      win_colors[NORMAL][BACKGROUND] = color_utils::GetSysSkColor(COLOR_WINDOW);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      win_colors[SELECTED][BACKGROUND] =
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          color_utils::GetSysSkColor(COLOR_HIGHLIGHT);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      win_colors[NORMAL][TEXT] = color_utils::GetSysSkColor(COLOR_WINDOWTEXT);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      win_colors[SELECTED][TEXT] =
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          color_utils::GetSysSkColor(COLOR_HIGHLIGHTTEXT);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CommonInitColors(theme, win_colors);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      win_initialized = true;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return win_colors[state][kind];
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool initialized = false;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static SkColor colors[NUM_STATES][NUM_KINDS];
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialized) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    colors[SELECTED][BACKGROUND] = theme->GetSystemColor(
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ui::NativeTheme::kColorId_TextfieldSelectionBackgroundFocused);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    colors[NORMAL][BACKGROUND] = theme->GetSystemColor(
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ui::NativeTheme::kColorId_TextfieldDefaultBackground);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    colors[NORMAL][URL] = SkColorSetARGB(0xff, 0x00, 0x99, 0x33);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    colors[SELECTED][URL] = SkColorSetARGB(0xff, 0x00, 0x66, 0x22);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    colors[HOVERED][URL] = SkColorSetARGB(0xff, 0x00, 0x66, 0x22);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CommonInitColors(theme, colors);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    initialized = true;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return colors[state][kind];
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxResultView::SetMatch(const AutocompleteMatch& match) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  match_ = match;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  animation_->Reset();
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (match.associated_keyword.get()) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keyword_icon_->SetImage(GetKeywordIcon());
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!keyword_icon_->parent())
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddChildView(keyword_icon_.get());
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (keyword_icon_->parent()) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RemoveChildView(keyword_icon_.get());
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Layout();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxResultView::ShowKeyword(bool show_keyword) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (show_keyword)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    animation_->Show();
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    animation_->Hide();
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxResultView::Invalidate() {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  keyword_icon_->SetImage(GetKeywordIcon());
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::Size OmniboxResultView::GetPreferredSize() {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::Size(0, std::max(
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default_icon_size_ + (kMinimumIconVerticalPadding * 2),
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetTextHeight() + (minimum_text_vertical_padding_ * 2)));
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OmniboxResultView, protected:
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OmniboxResultView::ResultViewState OmniboxResultView::GetState() const {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_->IsSelectedIndex(model_index_))
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SELECTED;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return model_->IsHoveredIndex(model_index_) ? HOVERED : NORMAL;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxResultView::PaintMatch(gfx::Canvas* canvas,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const AutocompleteMatch& match,
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   int x) {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  x = DrawString(canvas, match.contents, match.contents_class, false, x,
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 text_bounds_.y());
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Paint the description.
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(pkasting): Because we paint in multiple separate pieces, we can wind
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // up with no space even for an ellipsis for one or both of these pieces.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Instead, we should paint the entire match as a single long string.  This
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // would also let us use a more properly-localizable string than we get with
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just the IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR.
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!match.description.empty()) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string16 separator =
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ACMatchClassifications classifications;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    classifications.push_back(
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ACMatchClassification(0, ACMatchClassification::NONE));
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    x = DrawString(canvas, separator, classifications, true, x,
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   text_bounds_.y());
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DrawString(canvas, match.description, match.description_class, true, x,
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               text_bounds_.y());
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int OmniboxResultView::GetTextHeight() const {
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return font_height_;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxResultView::CommonInitColors(const ui::NativeTheme* theme,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         SkColor colors[][NUM_KINDS]) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  colors[HOVERED][BACKGROUND] =
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      color_utils::AlphaBlend(colors[SELECTED][BACKGROUND],
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              colors[NORMAL][BACKGROUND], 64);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  colors[HOVERED][TEXT] = colors[NORMAL][TEXT];
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_AURA)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool is_aura = theme == ui::NativeThemeAura::instance();
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool is_aura = false;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < NUM_STATES; ++i) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (is_aura) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      colors[i][TEXT] =
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          color_utils::AlphaBlend(SK_ColorBLACK, colors[i][BACKGROUND], 0xdd);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      colors[i][DIMMED_TEXT] =
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          color_utils::AlphaBlend(SK_ColorBLACK, colors[i][BACKGROUND], 0xbb);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      colors[i][DIMMED_TEXT] =
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          color_utils::AlphaBlend(colors[i][TEXT], colors[i][BACKGROUND], 128);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      colors[i][URL] = color_utils::GetReadableColor(SkColorSetRGB(0, 128, 0),
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     colors[i][BACKGROUND]);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(joi): Programmatically draw the dropdown border using
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // this color as well. (Right now it's drawn as black with 25%
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // alpha.)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    colors[i][DIVIDER] =
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        color_utils::AlphaBlend(colors[i][TEXT], colors[i][BACKGROUND], 0x34);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OmniboxResultView::SortRunsLogically(const RunData& lhs,
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          const RunData& rhs) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return lhs.run_start < rhs.run_start;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool OmniboxResultView::SortRunsVisually(const RunData& lhs,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const RunData& rhs) {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return lhs.visual_order < rhs.visual_order;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int OmniboxResultView::default_icon_size_ = 0;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::ImageSkia OmniboxResultView::GetIcon() const {
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::Image image = model_->GetIconIfExtensionMatch(model_index_);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!image.IsEmpty())
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return image.AsImageSkia();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int icon = match_.starred ?
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match_.type);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetState() == SELECTED) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (icon) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IDR_OMNIBOX_EXTENSION_APP:
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        icon = IDR_OMNIBOX_EXTENSION_APP_SELECTED;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IDR_OMNIBOX_HTTP:
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        icon = IDR_OMNIBOX_HTTP_SELECTED;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IDR_OMNIBOX_SEARCH:
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        icon = IDR_OMNIBOX_SEARCH_SELECTED;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IDR_OMNIBOX_STAR:
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        icon = IDR_OMNIBOX_STAR_SELECTED;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(icon);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const gfx::ImageSkia* OmniboxResultView::GetKeywordIcon() const {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: If we ever begin returning icons of varying size, then callers need
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to ensure that |keyword_icon_| is resized each time its image is reset.
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (GetState() == SELECTED) ? IDR_OMNIBOX_TTS_SELECTED : IDR_OMNIBOX_TTS);
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int OmniboxResultView::DrawString(
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Canvas* canvas,
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string16& text,
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ACMatchClassifications& classifications,
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool force_dim,
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int x,
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int y) {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (text.empty())
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return x;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check whether or not this text is a URL.  URLs are always displayed LTR
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // regardless of locale.
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_url = true;
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ACMatchClassifications::const_iterator i(classifications.begin());
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != classifications.end(); ++i) {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!(i->style & ACMatchClassification::URL)) {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_url = false;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Split the text into visual runs.  We do this first so that we don't need to
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // worry about whether our eliding might change the visual display in
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // unintended ways, e.g. by removing directional markings or by adding an
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ellipsis that's not enclosed in appropriate markings.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::i18n::BiDiLineIterator bidi_line;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!bidi_line.Open(text, base::i18n::IsRTL(), is_url))
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return x;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int num_runs = bidi_line.CountRuns();
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedVector<gfx::RenderText> render_texts;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Runs runs;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int run = 0; run < num_runs; ++run) {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int run_start_int = 0, run_length_int = 0;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The index we pass to GetVisualRun corresponds to the position of the run
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // in the displayed text. For example, the string "Google in HEBREW" (where
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // HEBREW is text in the Hebrew language) has two runs: "Google in " which
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is an LTR run, and "HEBREW" which is an RTL run. In an LTR context, the
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // run "Google in " has the index 0 (since it is the leftmost run
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // displayed). In an RTL context, the same run has the index 1 because it
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is the rightmost run. This is why the order in which we traverse the
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // runs is different depending on the locale direction.
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const UBiDiDirection run_direction = bidi_line.GetVisualRun(
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (base::i18n::IsRTL() && !is_url) ? (num_runs - run - 1) : run,
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &run_start_int, &run_length_int);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_GT(run_length_int, 0);
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    runs.push_back(RunData());
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RunData* current_run = &runs.back();
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    current_run->run_start = run_start_int;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const size_t run_end = current_run->run_start + run_length_int;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    current_run->visual_order = run;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    current_run->is_rtl = !is_url && (run_direction == UBIDI_RTL);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Compute classifications for this run.
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < classifications.size(); ++i) {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const size_t text_start =
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          std::max(classifications[i].offset, current_run->run_start);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (text_start >= run_end)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;  // We're past the last classification in the run.
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const size_t text_end = (i < (classifications.size() - 1)) ?
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          std::min(classifications[i + 1].offset, run_end) : run_end;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (text_end <= current_run->run_start)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;  // We haven't reached the first classification in the run.
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      render_texts.push_back(gfx::RenderText::CreateInstance());
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gfx::RenderText* render_text = render_texts.back();
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      current_run->classifications.push_back(render_text);
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      render_text->SetText(text.substr(text_start, text_end - text_start));
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      render_text->SetFont(font_);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Calculate style-related data.
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (classifications[i].style & ACMatchClassification::MATCH)
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        render_text->SetStyle(gfx::BOLD, true);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const ResultViewState state = GetState();
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (classifications[i].style & ACMatchClassification::URL)
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        render_text->SetColor(GetColor(state, URL));
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else if (classifications[i].style & ACMatchClassification::DIM)
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        render_text->SetColor(GetColor(state, DIMMED_TEXT));
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        render_text->SetColor(GetColor(state, force_dim ? DIMMED_TEXT : TEXT));
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      current_run->pixel_width += render_text->GetStringSize().width();
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!current_run->classifications.empty());
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!runs.empty());
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sort into logical order so we can elide logically.
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(runs.begin(), runs.end(), &SortRunsLogically);
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now determine what to elide, if anything.  Several subtle points:
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   * Because we have the run data, we can get edge cases correct, like
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     whether to place an ellipsis before or after the end of a run when the
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     text needs to be elided at the run boundary.
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   * The "or one before it" comments below refer to cases where an earlier
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     classification fits completely, but leaves too little space for an
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     ellipsis that turns out to be needed later.  These cases are commented
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     more completely in Elide().
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int remaining_width = mirroring_context_->remaining_width(x);
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (Runs::iterator i(runs.begin()); i != runs.end(); ++i) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i->pixel_width > remaining_width) {
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This run or one before it needs to be elided.
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for (Classifications::iterator j(i->classifications.begin());
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           j != i->classifications.end(); ++j) {
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        const int width = (*j)->GetStringSize().width();
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (width > remaining_width) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // This classification or one before it needs to be elided.  Erase all
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // further classifications and runs so Elide() can simply reverse-
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // iterate over everything to find the specific classification to
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // elide.
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          i->classifications.erase(++j, i->classifications.end());
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          runs.erase(++i, runs.end());
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          Elide(&runs, remaining_width);
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        remaining_width -= width;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    remaining_width -= i->pixel_width;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sort back into visual order so we can display the runs correctly.
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(runs.begin(), runs.end(), &SortRunsVisually);
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Draw the runs.
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (Runs::iterator i(runs.begin()); i != runs.end(); ++i) {
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const bool reverse_visible_order = (i->is_rtl != base::i18n::IsRTL());
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (reverse_visible_order)
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::reverse(i->classifications.begin(), i->classifications.end());
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (Classifications::const_iterator j(i->classifications.begin());
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         j != i->classifications.end(); ++j) {
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const gfx::Size size = (*j)->GetStringSize();
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Align the text runs to a common baseline.
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const gfx::Rect rect(
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          mirroring_context_->mirrored_left_coord(x, x + size.width()),
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          y + font_.GetBaseline() - (*j)->GetBaseline(),
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          size.width(), size.height());
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (*j)->SetDisplayRect(rect);
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (*j)->Draw(canvas);
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      x += size.width();
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return x;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxResultView::Elide(Runs* runs, int remaining_width) const {
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The complexity of this function is due to edge cases like the following:
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We have 100 px of available space, an initial classification that takes 86
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // px, and a font that has a 15 px wide ellipsis character.  Now if the first
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // classification is followed by several very narrow classifications (e.g. 3
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // px wide each), we don't know whether we need to elide or not at the time we
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // see the first classification -- it depends on how many subsequent
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // classifications follow, and some of those may be in the next run (or
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // several runs!).  This is why instead we let our caller move forward until
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we know we definitely need to elide, and then in this function we move
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // backward again until we find a string that we can successfully do the
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // eliding on.
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool first_classification = true;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (Runs::reverse_iterator i(runs->rbegin()); i != runs->rend(); ++i) {
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (Classifications::reverse_iterator j(i->classifications.rbegin());
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         j != i->classifications.rend(); ++j) {
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!first_classification) {
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We also add this classification's width (sans ellipsis) back to the
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // available width since we want to consider the available space we'll
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // have when we draw this classification.
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        remaining_width += (*j)->GetStringSize().width();
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // For all but the first classification we consider, we need to append
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // an ellipsis, since there isn't enough room to draw it after this
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // classification.
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (*j)->SetText((*j)->text() + kEllipsis);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      first_classification = false;
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Can we fit at least an ellipsis?
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      string16 elided_text = ui::ElideText((*j)->text(), (*j)->GetFont(),
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           remaining_width, ui::ELIDE_AT_END);
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Classifications::reverse_iterator prior(j + 1);
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const bool on_first_classification = (prior == i->classifications.rend());
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (elided_text.empty() && (remaining_width >= ellipsis_width_) &&
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          on_first_classification) {
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Edge case: This classification is bold, we can't fit a bold ellipsis
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // but we can fit a normal one, and this is the first classification in
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // the run.  We should display a lone normal ellipsis, because appending
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // one to the end of the previous run might put it in the wrong visual
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // location (if the previous run is reversed from the normal visual
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // order).
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // NOTE: If this isn't the first classification in the run, we don't
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // need to bother with this; see note below.
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        elided_text = kEllipsis;
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!elided_text.empty()) {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Success.  Elide this classification and stop.
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (*j)->SetText(elided_text);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If we could only fit an ellipsis, then only make it bold if there was
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // an immediate prior classification in this run that was also bold, or
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // it will look orphaned.
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if ((((*j)->GetFont().GetStyle() & gfx::BOLD) != 0) &&
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            (elided_text.length() == 1) &&
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            (on_first_classification ||
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             (((*prior)->GetFont().GetStyle() & gfx::BOLD) == 0))) {
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (*j)->SetStyle(gfx::BOLD, false);
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Erase any other classifications that come after the elided one.
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        i->classifications.erase(j.base(), i->classifications.end());
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        runs->erase(i.base(), runs->end());
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We couldn't fit an ellipsis.  Move back one classification,
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // append an ellipsis, and try again.
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // NOTE: In the edge case that a bold ellipsis doesn't fit but a
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // normal one would, and we reach here, then there is a previous
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // classification in this run, and so either:
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //   * It's normal, and will be able to draw successfully with the
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //     ellipsis we'll append to it, or
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //   * It is also bold, in which case we don't want to fall back
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //     to a normal ellipsis anyway (see comment above).
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We couldn't draw anything.
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  runs->clear();
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxResultView::Layout() {
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::ImageSkia icon = GetIcon();
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_bounds_.SetRect(edge_item_padding_ +
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ((icon.width() == default_icon_size_) ?
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          0 : LocationBarView::kIconInternalPadding),
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (height() - icon.height()) / 2, icon.width(), icon.height());
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int text_x = edge_item_padding_ + default_icon_size_ + item_padding_;
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int text_height = GetTextHeight();
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int text_width;
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (match_.associated_keyword.get()) {
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int kw_collapsed_size =
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        keyword_icon_->width() + edge_item_padding_;
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int max_kw_x = width() - kw_collapsed_size;
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int kw_x =
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        animation_->CurrentValueBetween(max_kw_x, edge_item_padding_);
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int kw_text_x = kw_x + keyword_icon_->width() + item_padding_;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_width = kw_x - text_x - item_padding_;
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keyword_text_bounds_.SetRect(kw_text_x, 0,
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::max(width() - kw_text_x - edge_item_padding_, 0), text_height);
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    keyword_icon_->SetPosition(gfx::Point(kw_x,
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (height() - keyword_icon_->height()) / 2));
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    text_width = width() - text_x - edge_item_padding_;
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  text_bounds_.SetRect(text_x, std::max(0, (height() - text_height) / 2),
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::max(text_width, 0), text_height);
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxResultView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  animation_->SetSlideDuration(width() / 4);
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxResultView::OnPaint(gfx::Canvas* canvas) {
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ResultViewState state = GetState();
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state != NORMAL)
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    canvas->DrawColor(GetColor(state, BACKGROUND));
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!match_.associated_keyword.get() ||
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      keyword_icon_->x() > icon_bounds_.right()) {
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Paint the icon.
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    canvas->DrawImageInt(GetIcon(), GetMirroredXForRect(icon_bounds_),
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         icon_bounds_.y());
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Paint the text.
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int x = GetMirroredXForRect(text_bounds_);
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mirroring_context_->Initialize(x, text_bounds_.width());
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PaintMatch(canvas, match_, x);
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (match_.associated_keyword.get()) {
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Paint the keyword text.
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int x = GetMirroredXForRect(keyword_text_bounds_);
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mirroring_context_->Initialize(x, keyword_text_bounds_.width());
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PaintMatch(canvas, *match_.associated_keyword.get(), x);
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OmniboxResultView::AnimationProgressed(const ui::Animation* animation) {
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Layout();
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SchedulePaint();
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
627