1dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Use of this source code is governed by a BSD-style license that can be 3dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// found in the LICENSE file. 4dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// For WinDDK ATL compatibility, these ATL headers must come first. 6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "build/build_config.h" 7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN) 8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <atlbase.h> // NOLINT 9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <atlwin.h> // NOLINT 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 12dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/views/autocomplete/autocomplete_result_view.h" 13dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <algorithm> // NOLINT 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/i18n/bidi_line_iterator.h" 17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/views/autocomplete/autocomplete_result_view_model.h" 18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/views/location_bar/location_bar_view.h" 19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "grit/generated_resources.h" 20dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "grit/theme_resources.h" 21dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "ui/base/l10n/l10n_util.h" 22dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "ui/base/resource/resource_bundle.h" 23dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "ui/base/text/text_elider.h" 24dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "ui/gfx/canvas_skia.h" 25dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "ui/gfx/color_utils.h" 26dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(OS_LINUX) 28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/gtk/gtk_util.h" 29dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "ui/gfx/skia_utils_gtk.h" 30dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif 31dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 32dc0f95d653279beabeb9817299e2902918ba123eKristian Monsennamespace { 33dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 34dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenconst char16 kEllipsis[] = { 0x2026 }; 35dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 36dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// The minimum distance between the top and bottom of the {icon|text} and the 37dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// top or bottom of the row. 38dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenconst int kMinimumIconVerticalPadding = 2; 39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(TOUCH_UI) 41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int kMinimumTextVerticalPadding = 15; 42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#else 43dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenconst int kMinimumTextVerticalPadding = 3; 44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif 45dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 46dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} // namespace 47dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 48dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen//////////////////////////////////////////////////////////////////////////////// 49dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// AutocompleteResultView, public: 50dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 51dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Precalculated data used to draw the portion of a match classification that 52dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// fits entirely within one run. 53dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenstruct AutocompleteResultView::ClassificationData { 54dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen string16 text; 55dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const gfx::Font* font; 56dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SkColor color; 57dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int pixel_width; 58dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}; 59dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 60dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Precalculated data used to draw a complete visual run within the match. 61dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// This will include all or part of at leasdt one, and possibly several, 62dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// classifications. 63dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenstruct AutocompleteResultView::RunData { 64dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen size_t run_start; // Offset within the match text where this run begins. 65dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int visual_order; // Where this run occurs in visual order. The earliest 66dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // run drawn is run 0. 67dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool is_rtl; 68dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int pixel_width; 69dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Classifications classifications; // Classification pieces within this run, 70dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // in logical order. 71dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}; 72dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 73dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// This class is a utility class for calculations affected by whether the result 74dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// view is horizontally mirrored. The drawing functions can be written as if 75dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// all drawing occurs left-to-right, and then use this class to get the actual 76dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// coordinates to begin drawing onscreen. 77dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenclass AutocompleteResultView::MirroringContext { 78dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen public: 79dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen MirroringContext() : center_(0), right_(0) {} 80dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 81dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Tells the mirroring context to use the provided range as the physical 82dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // bounds of the drawing region. When coordinate mirroring is needed, the 83dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // mirror point will be the center of this range. 84dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen void Initialize(int x, int width) { 85dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen center_ = x + width / 2; 86dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen right_ = x + width; 87dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 88dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 89dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Given a logical range within the drawing region, returns the coordinate of 90dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // the possibly-mirrored "left" side. (This functions exactly like 91dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // View::MirroredLeftPointForRect().) 92dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int mirrored_left_coord(int left, int right) const { 93dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return base::i18n::IsRTL() ? (center_ + (center_ - right)) : left; 94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 95dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 96dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Given a logical coordinate within the drawing region, returns the remaining 97dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // width available. 98dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int remaining_width(int x) const { 99dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return right_ - x; 100dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 101dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 102dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen private: 103dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int center_; 104dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int right_; 105dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 106dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DISALLOW_COPY_AND_ASSIGN(MirroringContext); 107dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}; 108dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 109dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenAutocompleteResultView::AutocompleteResultView( 110dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen AutocompleteResultViewModel* model, 111dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int model_index, 112dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const gfx::Font& font, 113dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const gfx::Font& bold_font) 114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen : model_(model), 115dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen model_index_(model_index), 116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen normal_font_(font), 117dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bold_font_(bold_font), 118dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ellipsis_width_(font.GetStringWidth(string16(kEllipsis))), 119dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen mirroring_context_(new MirroringContext()), 120dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen match_(NULL, 0, false, AutocompleteMatch::URL_WHAT_YOU_TYPED) { 121dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen CHECK_GE(model_index, 0); 122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (default_icon_size_ == 0) { 123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen default_icon_size_ = ResourceBundle::GetSharedInstance().GetBitmapNamed( 124dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen AutocompleteMatch::TypeToIcon(AutocompleteMatch::URL_WHAT_YOU_TYPED))-> 125dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen width(); 126dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 128dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 129dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenAutocompleteResultView::~AutocompleteResultView() { 130dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 131dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 132dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static 133dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenSkColor AutocompleteResultView::GetColor(ResultViewState state, 134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ColorKind kind) { 135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen static bool initialized = false; 136dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen static SkColor colors[NUM_STATES][NUM_KINDS]; 137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!initialized) { 138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#if defined(OS_WIN) 139dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[NORMAL][BACKGROUND] = color_utils::GetSysSkColor(COLOR_WINDOW); 140dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[SELECTED][BACKGROUND] = color_utils::GetSysSkColor(COLOR_HIGHLIGHT); 141dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[NORMAL][TEXT] = color_utils::GetSysSkColor(COLOR_WINDOWTEXT); 142dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[SELECTED][TEXT] = color_utils::GetSysSkColor(COLOR_HIGHLIGHTTEXT); 143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#elif defined(OS_LINUX) 144dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen GdkColor bg_color, selected_bg_color, text_color, selected_text_color; 145dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen gtk_util::GetTextColors( 146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen &bg_color, &selected_bg_color, &text_color, &selected_text_color); 147dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[NORMAL][BACKGROUND] = gfx::GdkColorToSkColor(bg_color); 148dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[SELECTED][BACKGROUND] = gfx::GdkColorToSkColor(selected_bg_color); 149dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[NORMAL][TEXT] = gfx::GdkColorToSkColor(text_color); 150dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[SELECTED][TEXT] = gfx::GdkColorToSkColor(selected_text_color); 151dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#else 152dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // TODO(beng): source from theme provider. 153dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[NORMAL][BACKGROUND] = SK_ColorWHITE; 154dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[SELECTED][BACKGROUND] = SK_ColorBLUE; 155dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[NORMAL][TEXT] = SK_ColorBLACK; 156dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[SELECTED][TEXT] = SK_ColorWHITE; 157dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#endif 158dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[HOVERED][BACKGROUND] = 159dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen color_utils::AlphaBlend(colors[SELECTED][BACKGROUND], 160dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[NORMAL][BACKGROUND], 64); 161dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[HOVERED][TEXT] = colors[NORMAL][TEXT]; 162dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (int i = 0; i < NUM_STATES; ++i) { 163dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[i][DIMMED_TEXT] = 164dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen color_utils::AlphaBlend(colors[i][TEXT], colors[i][BACKGROUND], 128); 165dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[i][URL] = color_utils::GetReadableColor(SkColorSetRGB(0, 128, 0), 166dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen colors[i][BACKGROUND]); 167dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 168dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen initialized = true; 169dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 170dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 171dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return colors[state][kind]; 172dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 173dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid AutocompleteResultView::SetMatch(const AutocompleteMatch& match) { 175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen match_ = match; 176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Layout(); 177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 179dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen//////////////////////////////////////////////////////////////////////////////// 180dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// AutocompleteResultView, protected: 181dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 182dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid AutocompleteResultView::PaintMatch(gfx::Canvas* canvas, 183dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const AutocompleteMatch& match, 184dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int x) { 185dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen x = DrawString(canvas, match.contents, match.contents_class, false, x, 186dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen text_bounds_.y()); 187dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 188dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Paint the description. 189dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // TODO(pkasting): Because we paint in multiple separate pieces, we can wind 190dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // up with no space even for an ellipsis for one or both of these pieces. 191dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Instead, we should paint the entire match as a single long string. This 192dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // would also let us use a more properly-localizable string than we get with 193dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // just the IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR. 194dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!match.description.empty()) { 195dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen string16 separator = 196dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR); 197dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ACMatchClassifications classifications; 198dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen classifications.push_back( 199dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ACMatchClassification(0, ACMatchClassification::NONE)); 200dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen x = DrawString(canvas, separator, classifications, true, x, 201dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen text_bounds_.y()); 202dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 203dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DrawString(canvas, match.description, match.description_class, true, x, 204dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen text_bounds_.y()); 205dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 206dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 207dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint AutocompleteResultView::GetFontHeight() const { 209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return std::max(normal_font_.GetHeight(), bold_font_.GetHeight()); 210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 212dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static 213dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool AutocompleteResultView::SortRunsLogically(const RunData& lhs, 214dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const RunData& rhs) { 215dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return lhs.run_start < rhs.run_start; 216dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 217dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 218dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static 219dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool AutocompleteResultView::SortRunsVisually(const RunData& lhs, 220dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const RunData& rhs) { 221dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return lhs.visual_order < rhs.visual_order; 222dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 223dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 224dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static 225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint AutocompleteResultView::default_icon_size_ = 0; 226dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 227dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenAutocompleteResultView::ResultViewState 228dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen AutocompleteResultView::GetState() const { 229dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (model_->IsSelectedIndex(model_index_)) 230dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return SELECTED; 231dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return model_->IsHoveredIndex(model_index_) ? HOVERED : NORMAL; 232dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 233dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 234dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenconst SkBitmap* AutocompleteResultView::GetIcon() const { 235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const SkBitmap* bitmap = model_->GetIconIfExtensionMatch(model_index_); 236dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (bitmap) 237dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return bitmap; 238dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 239dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int icon = match_.starred ? 240dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match_.type); 241dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (model_->IsSelectedIndex(model_index_)) { 242dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen switch (icon) { 243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case IDR_OMNIBOX_EXTENSION_APP: 244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen icon = IDR_OMNIBOX_EXTENSION_APP_SELECTED; 245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen break; 246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case IDR_OMNIBOX_HTTP: 247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen icon = IDR_OMNIBOX_HTTP_SELECTED; 248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen break; 249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case IDR_OMNIBOX_HISTORY: 250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen icon = IDR_OMNIBOX_HISTORY_SELECTED; 251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen break; 252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case IDR_OMNIBOX_SEARCH: 253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen icon = IDR_OMNIBOX_SEARCH_SELECTED; 254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen break; 255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case IDR_OMNIBOX_STAR: 256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen icon = IDR_OMNIBOX_STAR_SELECTED; 257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen break; 258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen default: 259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen NOTREACHED(); 260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen break; 261dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 262dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 263dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return ResourceBundle::GetSharedInstance().GetBitmapNamed(icon); 264dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 265dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 266dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenint AutocompleteResultView::DrawString( 267dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen gfx::Canvas* canvas, 268dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const string16& text, 269dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const ACMatchClassifications& classifications, 270dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool force_dim, 271dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int x, 272dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int y) { 273dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (text.empty()) 274dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return x; 275dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 276dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Check whether or not this text is a URL. URLs are always displayed LTR 277dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // regardless of locale. 278dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool is_url = true; 279dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (ACMatchClassifications::const_iterator i(classifications.begin()); 280dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen i != classifications.end(); ++i) { 281dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!(i->style & ACMatchClassification::URL)) { 282dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen is_url = false; 283dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen break; 284dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 285dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 286dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 287dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Split the text into visual runs. We do this first so that we don't need to 288dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // worry about whether our eliding might change the visual display in 289dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // unintended ways, e.g. by removing directional markings or by adding an 290dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // ellipsis that's not enclosed in appropriate markings. 291dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen base::i18n::BiDiLineIterator bidi_line; 292dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!bidi_line.Open(text, base::i18n::IsRTL(), is_url)) 293dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return x; 294dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const int num_runs = bidi_line.CountRuns(); 295dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Runs runs; 296dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (int run = 0; run < num_runs; ++run) { 297dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int run_start_int = 0, run_length_int = 0; 298dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // The index we pass to GetVisualRun corresponds to the position of the run 299dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // in the displayed text. For example, the string "Google in HEBREW" (where 300dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // HEBREW is text in the Hebrew language) has two runs: "Google in " which 301dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // is an LTR run, and "HEBREW" which is an RTL run. In an LTR context, the 302dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // run "Google in " has the index 0 (since it is the leftmost run 303dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // displayed). In an RTL context, the same run has the index 1 because it 304dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // is the rightmost run. This is why the order in which we traverse the 305dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // runs is different depending on the locale direction. 306dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const UBiDiDirection run_direction = bidi_line.GetVisualRun( 307dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen (base::i18n::IsRTL() && !is_url) ? (num_runs - run - 1) : run, 308dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen &run_start_int, &run_length_int); 309dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DCHECK_GT(run_length_int, 0); 310dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen runs.push_back(RunData()); 311dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen RunData* current_run = &runs.back(); 312dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen current_run->run_start = run_start_int; 313dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const size_t run_end = current_run->run_start + run_length_int; 314dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen current_run->visual_order = run; 315dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen current_run->is_rtl = !is_url && (run_direction == UBIDI_RTL); 316dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen current_run->pixel_width = 0; 317dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 318dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Compute classifications for this run. 319dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (size_t i = 0; i < classifications.size(); ++i) { 320dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const size_t text_start = 321dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::max(classifications[i].offset, current_run->run_start); 322dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (text_start >= run_end) 323dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen break; // We're past the last classification in the run. 324dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 325dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const size_t text_end = (i < (classifications.size() - 1)) ? 326dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::min(classifications[i + 1].offset, run_end) : run_end; 327dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (text_end <= current_run->run_start) 328dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen continue; // We haven't reached the first classification in the run. 329dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 330dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen current_run->classifications.push_back(ClassificationData()); 331dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ClassificationData* current_data = 332dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ¤t_run->classifications.back(); 333dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen current_data->text = text.substr(text_start, text_end - text_start); 334dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 335dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Calculate style-related data. 336dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const int style = classifications[i].style; 337dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const bool use_bold_font = !!(style & ACMatchClassification::MATCH); 338dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen current_data->font = &(use_bold_font ? bold_font_ : normal_font_); 339dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const ResultViewState state = GetState(); 340dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (style & ACMatchClassification::URL) 341dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen current_data->color = GetColor(state, URL); 342dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen else if (style & ACMatchClassification::DIM) 343dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen current_data->color = GetColor(state, DIMMED_TEXT); 344dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen else 345dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen current_data->color = GetColor(state, force_dim ? DIMMED_TEXT : TEXT); 346dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen current_data->pixel_width = 347dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen current_data->font->GetStringWidth(current_data->text); 348dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen current_run->pixel_width += current_data->pixel_width; 349dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 350dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DCHECK(!current_run->classifications.empty()); 351dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 352dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen DCHECK(!runs.empty()); 353dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 354dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Sort into logical order so we can elide logically. 355dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::sort(runs.begin(), runs.end(), &SortRunsLogically); 356dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 357dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Now determine what to elide, if anything. Several subtle points: 358dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // * Because we have the run data, we can get edge cases correct, like 359dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // whether to place an ellipsis before or after the end of a run when the 360dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // text needs to be elided at the run boundary. 361dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // * The "or one before it" comments below refer to cases where an earlier 362dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // classification fits completely, but leaves too little space for an 363dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // ellipsis that turns out to be needed later. These cases are commented 364dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // more completely in Elide(). 365dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int remaining_width = mirroring_context_->remaining_width(x); 366dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (Runs::iterator i(runs.begin()); i != runs.end(); ++i) { 367dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (i->pixel_width > remaining_width) { 368dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // This run or one before it needs to be elided. 369dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (Classifications::iterator j(i->classifications.begin()); 370dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen j != i->classifications.end(); ++j) { 371dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (j->pixel_width > remaining_width) { 372dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // This classification or one before it needs to be elided. Erase all 373dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // further classifications and runs so Elide() can simply reverse- 374dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // iterate over everything to find the specific classification to 375dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // elide. 376dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen i->classifications.erase(++j, i->classifications.end()); 377dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen runs.erase(++i, runs.end()); 378dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Elide(&runs, remaining_width); 379dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen break; 380dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 381dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen remaining_width -= j->pixel_width; 382dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 383dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen break; 384dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 385dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen remaining_width -= i->pixel_width; 386dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 387dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 388dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Sort back into visual order so we can display the runs correctly. 389dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::sort(runs.begin(), runs.end(), &SortRunsVisually); 390dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 391dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Draw the runs. 392dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (Runs::iterator i(runs.begin()); i != runs.end(); ++i) { 393dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const bool reverse_visible_order = (i->is_rtl != base::i18n::IsRTL()); 394dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int flags = gfx::Canvas::NO_ELLIPSIS; // We've already elided. 395dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (reverse_visible_order) { 396dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen std::reverse(i->classifications.begin(), i->classifications.end()); 397dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (i->is_rtl) 398dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen flags |= gfx::Canvas::FORCE_RTL_DIRECTIONALITY; 399dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 400dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (Classifications::const_iterator j(i->classifications.begin()); 401dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen j != i->classifications.end(); ++j) { 402dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen int left = mirroring_context_->mirrored_left_coord(x, x + j->pixel_width); 403dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen canvas->DrawStringInt(j->text, *j->font, j->color, left, 404dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen y, j->pixel_width, j->font->GetHeight(), flags); 405dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen x += j->pixel_width; 406dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 407dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 408dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 409dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return x; 410dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 411dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 412dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid AutocompleteResultView::Elide(Runs* runs, int remaining_width) const { 413dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // The complexity of this function is due to edge cases like the following: 414dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // We have 100 px of available space, an initial classification that takes 86 415dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // px, and a font that has a 15 px wide ellipsis character. Now if the first 416dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // classification is followed by several very narrow classifications (e.g. 3 417dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // px wide each), we don't know whether we need to elide or not at the time we 418dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // see the first classification -- it depends on how many subsequent 419dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // classifications follow, and some of those may be in the next run (or 420dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // several runs!). This is why instead we let our caller move forward until 421dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // we know we definitely need to elide, and then in this function we move 422dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // backward again until we find a string that we can successfully do the 423dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // eliding on. 424dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen bool first_classification = true; 425dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (Runs::reverse_iterator i(runs->rbegin()); i != runs->rend(); ++i) { 426dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen for (Classifications::reverse_iterator j(i->classifications.rbegin()); 427dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen j != i->classifications.rend(); ++j) { 428dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!first_classification) { 429dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // For all but the first classification we consider, we need to append 430dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // an ellipsis, since there isn't enough room to draw it after this 431dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // classification. 432dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen j->text += kEllipsis; 433dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 434dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // We also add this classification's width (sans ellipsis) back to the 435dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // available width since we want to consider the available space we'll 436dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // have when we draw this classification. 437dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen remaining_width += j->pixel_width; 438dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 439dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen first_classification = false; 440dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 441dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Can we fit at least an ellipsis? 442dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen string16 elided_text = 443dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ui::ElideText(j->text, *j->font, remaining_width, false); 444dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen Classifications::reverse_iterator prior_classification(j); 445dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen ++prior_classification; 446dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen const bool on_first_classification = 447dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen (prior_classification == i->classifications.rend()); 448dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (elided_text.empty() && (remaining_width >= ellipsis_width_) && 449dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen on_first_classification) { 450dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Edge case: This classification is bold, we can't fit a bold ellipsis 451dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // but we can fit a normal one, and this is the first classification in 452dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // the run. We should display a lone normal ellipsis, because appending 453dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // one to the end of the previous run might put it in the wrong visual 454dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // location (if the previous run is reversed from the normal visual 455dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // order). 456dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // NOTE: If this isn't the first classification in the run, we don't 457dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // need to bother with this; see note below. 458dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen elided_text = kEllipsis; 459dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 460dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if (!elided_text.empty()) { 461dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Success. Elide this classification and stop. 462dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen j->text = elided_text; 463dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 464dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // If we could only fit an ellipsis, then only make it bold if there was 465dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // an immediate prior classification in this run that was also bold, or 466dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // it will look orphaned. 467dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen if ((elided_text.length() == 1) && 468dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen (on_first_classification || 469dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen (prior_classification->font == &normal_font_))) 470dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen j->font = &normal_font_; 471dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 472dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen j->pixel_width = j->font->GetStringWidth(elided_text); 473dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 474dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // Erase any other classifications that come after the elided one. 475dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen i->classifications.erase(j.base(), i->classifications.end()); 476dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen runs->erase(i.base(), runs->end()); 477dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen return; 478dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 479dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 480dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // We couldn't fit an ellipsis. Move back one classification, 481dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // append an ellipsis, and try again. 482dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // NOTE: In the edge case that a bold ellipsis doesn't fit but a 483dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // normal one would, and we reach here, then there is a previous 484dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // classification in this run, and so either: 485dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // * It's normal, and will be able to draw successfully with the 486dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // ellipsis we'll append to it, or 487dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // * It is also bold, in which case we don't want to fall back 488dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // to a normal ellipsis anyway (see comment above). 489dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 490dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen } 491dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 492dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // We couldn't draw anything. 493dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen runs->clear(); 494dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen} 495ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 496ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsengfx::Size AutocompleteResultView::GetPreferredSize() { 497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return gfx::Size(0, std::max( 498ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen default_icon_size_ + (kMinimumIconVerticalPadding * 2), 499ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GetFontHeight() + (kMinimumTextVerticalPadding * 2))); 500ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 501ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 502ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid AutocompleteResultView::Layout() { 503ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const SkBitmap* icon = GetIcon(); 504ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen icon_bounds_.SetRect(LocationBarView::kEdgeItemPadding + 505ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ((icon->width() == default_icon_size_) ? 506ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 0 : LocationBarView::kIconInternalPadding), 507ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (height() - icon->height()) / 2, icon->width(), icon->height()); 508ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 509ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int text_x = LocationBarView::kEdgeItemPadding + default_icon_size_ + 510ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen LocationBarView::kItemPadding; 511ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int font_height = GetFontHeight(); 512ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen text_bounds_.SetRect(text_x, std::max(0, (height() - font_height) / 2), 513ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::max(bounds().width() - text_x - LocationBarView::kEdgeItemPadding, 514ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 0), font_height); 515ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 516ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 517ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid AutocompleteResultView::OnPaint(gfx::Canvas* canvas) { 518ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const ResultViewState state = GetState(); 519ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (state != NORMAL) 520ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen canvas->AsCanvasSkia()->drawColor(GetColor(state, BACKGROUND)); 521ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 522ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Paint the icon. 523ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen canvas->DrawBitmapInt(*GetIcon(), GetMirroredXForRect(icon_bounds_), 524ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen icon_bounds_.y()); 525ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 526ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Paint the text. 527ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int x = GetMirroredXForRect(text_bounds_); 528ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen mirroring_context_->Initialize(x, text_bounds_.width()); 529ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen PaintMatch(canvas, match_, x); 530ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 531