| Index: chrome/browser/autocomplete/autocomplete_popup_view_win.cc | 
| =================================================================== | 
| --- chrome/browser/autocomplete/autocomplete_popup_view_win.cc	(revision 21913) | 
| +++ chrome/browser/autocomplete/autocomplete_popup_view_win.cc	(working copy) | 
| @@ -1,692 +0,0 @@ | 
| -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 
| -// Use of this source code is governed by a BSD-style license that can be | 
| -// found in the LICENSE file. | 
| - | 
| -#include "chrome/browser/autocomplete/autocomplete_popup_view_win.h" | 
| - | 
| -// TODO(deanm): Clean up these includes, not going to fight it now. | 
| -#include <atlbase.h> | 
| -#include <atlapp.h> | 
| -#include <atlcrack.h> | 
| -#include <atlmisc.h> | 
| -#include <cmath> | 
| - | 
| -#include "app/gfx/canvas.h" | 
| -#include "app/gfx/font.h" | 
| -#include "app/l10n_util.h" | 
| -#include "app/resource_bundle.h" | 
| -#include "base/command_line.h" | 
| -#include "base/string_util.h" | 
| -#include "base/win_util.h" | 
| -#include "chrome/browser/autocomplete/autocomplete.h" | 
| -#include "chrome/browser/autocomplete/autocomplete_edit.h" | 
| -#include "chrome/browser/autocomplete/autocomplete_popup_model.h" | 
| -#include "chrome/browser/browser_process.h" | 
| -#include "chrome/browser/net/dns_global.h" | 
| -#include "chrome/browser/profile.h" | 
| -#include "chrome/browser/search_engines/template_url.h" | 
| -#include "chrome/browser/search_engines/template_url_model.h" | 
| -#include "chrome/browser/views/autocomplete/autocomplete_popup_contents_view.h" | 
| -#include "chrome/browser/views/location_bar_view.h" | 
| -#include "chrome/common/chrome_switches.h" | 
| -#include "chrome/common/notification_service.h" | 
| -#include "grit/theme_resources.h" | 
| -#include "third_party/icu38/public/common/unicode/ubidi.h" | 
| -#include "views/view.h" | 
| - | 
| -// Padding between text and the star indicator, in pixels. | 
| -static const int kStarPadding = 4; | 
| - | 
| -// This class implements a utility used for mirroring x-coordinates when the | 
| -// application language is a right-to-left one. | 
| -class AutocompletePopupViewWin::MirroringContext { | 
| - public: | 
| -  MirroringContext() : min_x_(0), center_x_(0), max_x_(0), enabled_(false) { } | 
| - | 
| -  // Initializes the bounding region used for mirroring coordinates. | 
| -  // This class uses the center of this region as an axis for calculating | 
| -  // mirrored coordinates. | 
| -  void Initialize(int x1, int x2, bool enabled); | 
| - | 
| -  // Return the "left" side of the specified region. | 
| -  // When the application language is a right-to-left one, this function | 
| -  // calculates the mirrored coordinates of the input region and returns the | 
| -  // left side of the mirrored region. | 
| -  // The input region must be in the bounding region specified in the | 
| -  // Initialize() function. | 
| -  int GetLeft(int x1, int x2) const; | 
| - | 
| -  // Returns whether or not we are mirroring the x coordinate. | 
| -  bool enabled() const { | 
| -    return enabled_; | 
| -  } | 
| - | 
| - private: | 
| -  int min_x_; | 
| -  int center_x_; | 
| -  int max_x_; | 
| -  bool enabled_; | 
| - | 
| -  DISALLOW_EVIL_CONSTRUCTORS(MirroringContext); | 
| -}; | 
| - | 
| -void AutocompletePopupViewWin::MirroringContext::Initialize(int x1, | 
| -                                                            int x2, | 
| -                                                            bool enabled) { | 
| -  min_x_ = std::min(x1, x2); | 
| -  max_x_ = std::max(x1, x2); | 
| -  center_x_ = min_x_ + (max_x_ - min_x_) / 2; | 
| -  enabled_ = enabled; | 
| -} | 
| - | 
| -int AutocompletePopupViewWin::MirroringContext::GetLeft(int x1, int x2) const { | 
| -  return enabled_ ? | 
| -      (center_x_ + (center_x_ - std::max(x1, x2))) : std::min(x1, x2); | 
| -} | 
| - | 
| -const wchar_t AutocompletePopupViewWin::DrawLineInfo::ellipsis_str[] = | 
| -    L"\x2026"; | 
| - | 
| -AutocompletePopupViewWin::DrawLineInfo::DrawLineInfo(const gfx::Font& font) { | 
| -  // Create regular and bold fonts. | 
| -  regular_font = font.DeriveFont(-1); | 
| -  bold_font = regular_font.DeriveFont(0, gfx::Font::BOLD); | 
| - | 
| -  // The total padding added to each line (bottom padding is what is | 
| -  // left over after DrawEntry() specifies its top offset). | 
| -  static const int kTotalLinePadding = 5; | 
| -  font_height = std::max(regular_font.height(), bold_font.height()); | 
| -  line_height = font_height + kTotalLinePadding; | 
| -  ave_char_width = regular_font.GetExpectedTextWidth(1); | 
| -  ellipsis_width = std::max(regular_font.GetStringWidth(ellipsis_str), | 
| -                            bold_font.GetStringWidth(ellipsis_str)); | 
| - | 
| -  // Create background colors. | 
| -  background_colors[NORMAL] = GetSysColor(COLOR_WINDOW); | 
| -  background_colors[SELECTED] = GetSysColor(COLOR_HIGHLIGHT); | 
| -  background_colors[HOVERED] = | 
| -      AlphaBlend(background_colors[SELECTED], background_colors[NORMAL], 0x40); | 
| - | 
| -  // Create text colors. | 
| -  text_colors[NORMAL] = GetSysColor(COLOR_WINDOWTEXT); | 
| -  text_colors[HOVERED] = text_colors[NORMAL]; | 
| -  text_colors[SELECTED] = GetSysColor(COLOR_HIGHLIGHTTEXT); | 
| - | 
| -  // Create brushes and url colors. | 
| -  const COLORREF dark_url(0x008000); | 
| -  const COLORREF light_url(0xd0ffd0); | 
| -  for (int i = 0; i < MAX_STATUS_ENTRIES; ++i) { | 
| -    // Pick whichever URL color contrasts better. | 
| -    const double dark_contrast = | 
| -        LuminosityContrast(dark_url, background_colors[i]); | 
| -    const double light_contrast = | 
| -        LuminosityContrast(light_url, background_colors[i]); | 
| -    url_colors[i] = (dark_contrast > light_contrast) ? dark_url : light_url; | 
| - | 
| -    brushes[i] = CreateSolidBrush(background_colors[i]); | 
| -  } | 
| -} | 
| - | 
| -AutocompletePopupViewWin::DrawLineInfo::~DrawLineInfo() { | 
| -  for (int i = 0; i < MAX_STATUS_ENTRIES; ++i) | 
| -    DeleteObject(brushes[i]); | 
| -} | 
| - | 
| -// static | 
| -double AutocompletePopupViewWin::DrawLineInfo::LuminosityContrast( | 
| -    COLORREF color1, | 
| -    COLORREF color2) { | 
| -  // This algorithm was adapted from the following text at | 
| -  // http://juicystudio.com/article/luminositycontrastratioalgorithm.php : | 
| -  // | 
| -  // "[Luminosity contrast can be calculated as] (L1+.05) / (L2+.05) where L is | 
| -  // luminosity and is defined as .2126*R + .7152*G + .0722B using linearised | 
| -  // R, G, and B values. Linearised R (for example) = (R/FS)^2.2 where FS is | 
| -  // full scale value (255 for 8 bit color channels). L1 is the higher value | 
| -  // (of text or background) and L2 is the lower value. | 
| -  // | 
| -  // The Gamma correction and RGB constants are derived from the Standard | 
| -  // Default Color Space for the Internet (sRGB), and the 0.05 offset is | 
| -  // included to compensate for contrast ratios that occur when a value is at | 
| -  // or near zero, and for ambient light effects. | 
| -  const double l1 = Luminosity(color1); | 
| -  const double l2 = Luminosity(color2); | 
| -  return (l1 > l2) ? ((l1 + 0.05) / (l2 + 0.05)) : ((l2 + 0.05) / (l1 + 0.05)); | 
| -} | 
| - | 
| -// static | 
| -double AutocompletePopupViewWin::DrawLineInfo::Luminosity(COLORREF color) { | 
| -  // See comments in LuminosityContrast(). | 
| -  const double linearised_r = | 
| -      pow(static_cast<double>(GetRValue(color)) / 255.0, 2.2); | 
| -  const double linearised_g = | 
| -      pow(static_cast<double>(GetGValue(color)) / 255.0, 2.2); | 
| -  const double linearised_b = | 
| -      pow(static_cast<double>(GetBValue(color)) / 255.0, 2.2); | 
| -  return (0.2126 * linearised_r) + (0.7152 * linearised_g) + | 
| -      (0.0722 * linearised_b); | 
| -} | 
| - | 
| -COLORREF AutocompletePopupViewWin::DrawLineInfo::AlphaBlend( | 
| -    COLORREF foreground, | 
| -    COLORREF background, | 
| -    BYTE alpha) { | 
| -  if (alpha == 0) | 
| -    return background; | 
| -  else if (alpha == 0xff) | 
| -    return foreground; | 
| - | 
| -  return RGB( | 
| -    ((GetRValue(foreground) * alpha) + | 
| -     (GetRValue(background) * (0xff - alpha))) / 0xff, | 
| -    ((GetGValue(foreground) * alpha) + | 
| -     (GetGValue(background) * (0xff - alpha))) / 0xff, | 
| -    ((GetBValue(foreground) * alpha) + | 
| -     (GetBValue(background) * (0xff - alpha))) / 0xff); | 
| -} | 
| - | 
| -AutocompletePopupViewWin::AutocompletePopupViewWin( | 
| -    const gfx::Font& font, | 
| -    AutocompleteEditViewWin* edit_view, | 
| -    AutocompleteEditModel* edit_model, | 
| -    Profile* profile) | 
| -    : model_(new AutocompletePopupModel(this, edit_model, profile)), | 
| -      edit_view_(edit_view), | 
| -      line_info_(font), | 
| -      mirroring_context_(new MirroringContext()), | 
| -      star_(ResourceBundle::GetSharedInstance().GetBitmapNamed( | 
| -          IDR_CONTENT_STAR_ON)) { | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::InvalidateLine(size_t line) { | 
| -  RECT rc; | 
| -  GetClientRect(&rc); | 
| -  rc.top = LineTopPixel(line); | 
| -  rc.bottom = rc.top + line_info_.line_height; | 
| -  InvalidateRect(&rc, false); | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::UpdatePopupAppearance() { | 
| -  const AutocompleteResult& result = model_->result(); | 
| -  if (result.empty()) { | 
| -    // No matches, close any existing popup. | 
| -    if (m_hWnd) { | 
| -      DestroyWindow(); | 
| -      m_hWnd = NULL; | 
| -    } | 
| -    return; | 
| -  } | 
| - | 
| -  // Figure the coordinates of the popup: | 
| -  // Get the coordinates of the location bar view; these are returned relative | 
| -  // to its parent. | 
| -  // TODO(pkasting): http://b/1345937  All this use of editor accessors should | 
| -  // die once this class is a true ChromeView. | 
| -  CRect rc = edit_view_->parent_view()->bounds().ToRECT(); | 
| -  // Subtract the top left corner to make the coordinates relative to the | 
| -  // location bar view itself, and convert to screen coordinates. | 
| -  gfx::Point top_left(-rc.TopLeft()); | 
| -  views::View::ConvertPointToScreen(edit_view_->parent_view(), &top_left); | 
| -  rc.OffsetRect(top_left.ToPOINT()); | 
| -  // Expand by one pixel on each side since that's the amount the location bar | 
| -  // view is inset from the divider line that edges the adjacent buttons. | 
| -  // Deflate the top and bottom by the height of the extra graphics around the | 
| -  // edit. | 
| -  // TODO(pkasting): http://b/972786 This shouldn't be hardcoded to rely on | 
| -  // LocationBarView constants.  Instead we should just make the edit be "at the | 
| -  // right coordinates", or something else generic. | 
| -  rc.InflateRect(1, -LocationBarView::kVertMargin); | 
| -  // Now rc is the exact width we want and is positioned like the edit would | 
| -  // be, so shift the top and bottom downwards so the new top is where the old | 
| -  // bottom is and the rect has the height we need for all our entries, plus a | 
| -  // one-pixel border on top and bottom. | 
| -  rc.top = rc.bottom; | 
| -  rc.bottom += static_cast<int>(result.size()) * line_info_.line_height + 2; | 
| - | 
| -  if (!m_hWnd) { | 
| -    // To prevent this window from being activated, we create an invisible | 
| -    // window and manually show it without activating it. | 
| -    Create(edit_view_->m_hWnd, rc, AUTOCOMPLETEPOPUPVIEW_CLASSNAME, WS_POPUP, | 
| -           WS_EX_TOOLWINDOW); | 
| -    // When an IME is attached to the rich-edit control, retrieve its window | 
| -    // handle and show this popup window under the IME windows. | 
| -    // Otherwise, show this popup window under top-most windows. | 
| -    // TODO(hbono): http://b/1111369 if we exclude this popup window from the | 
| -    // display area of IME windows, this workaround becomes unnecessary. | 
| -    HWND ime_window = ImmGetDefaultIMEWnd(edit_view_->m_hWnd); | 
| -    SetWindowPos(ime_window ? ime_window : HWND_NOTOPMOST, 0, 0, 0, 0, | 
| -                 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW); | 
| -  } else { | 
| -    // Already open, just resize the window.  This is a bit tricky; we want to | 
| -    // repaint the whole window, since the contents may have changed, but | 
| -    // MoveWindow() won't repaint portions that haven't moved or been | 
| -    // added/removed.  So we first call InvalidateRect(), so the next repaint | 
| -    // paints the whole window, then tell MoveWindow() to do the actual | 
| -    // repaint, which will also properly repaint Windows formerly under the | 
| -    // popup. | 
| -    InvalidateRect(NULL, false); | 
| -    MoveWindow(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, true); | 
| -  } | 
| - | 
| -  // TODO(pkasting): http://b/1111369 We should call ImmSetCandidateWindow() on | 
| -  // the edit_view_'s IME context here, and exclude ourselves from its display | 
| -  // area.  Not clear what to pass for the lpCandidate->ptCurrentPos member, | 
| -  // though... | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::OnHoverEnabledOrDisabled(bool disabled) { | 
| -  TRACKMOUSEEVENT tme; | 
| -  tme.cbSize = sizeof(TRACKMOUSEEVENT); | 
| -  if (disabled) { | 
| -    // Save the current mouse position to check against for re-enabling. | 
| -    GetCursorPos(&last_hover_coordinates_);  // Returns screen coordinates | 
| - | 
| -    // Cancel existing registration for WM_MOUSELEAVE notifications. | 
| -    tme.dwFlags = TME_CANCEL | TME_LEAVE; | 
| -  } else { | 
| -    // Register for WM_MOUSELEAVE notifications. | 
| -    tme.dwFlags = TME_LEAVE; | 
| -  } | 
| -  tme.hwndTrack = m_hWnd; | 
| -  tme.dwHoverTime = HOVER_DEFAULT;  // Not actually used | 
| -  TrackMouseEvent(&tme); | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::OnLButtonDown(UINT keys, const CPoint& point) { | 
| -  const size_t new_hovered_line = PixelToLine(point.y); | 
| -  model_->SetHoveredLine(new_hovered_line); | 
| -  model_->SetSelectedLine(new_hovered_line, false); | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::OnMButtonDown(UINT keys, const CPoint& point) { | 
| -  model_->SetHoveredLine(PixelToLine(point.y)); | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::OnLButtonUp(UINT keys, const CPoint& point) { | 
| -  OnButtonUp(point, CURRENT_TAB); | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::OnMButtonUp(UINT keys, const CPoint& point) { | 
| -  OnButtonUp(point, NEW_BACKGROUND_TAB); | 
| -} | 
| - | 
| -LRESULT AutocompletePopupViewWin::OnMouseActivate(HWND window, | 
| -                                               UINT hit_test, | 
| -                                               UINT mouse_message) { | 
| -  return MA_NOACTIVATE; | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::OnMouseLeave() { | 
| -  // The mouse has left the window, so no line is hovered. | 
| -  model_->SetHoveredLine(AutocompletePopupModel::kNoMatch); | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::OnMouseMove(UINT keys, const CPoint& point) { | 
| -  // Track hover when | 
| -  // (a) The left or middle button is down (the user is interacting via the | 
| -  //     mouse) | 
| -  // (b) The user moves the mouse from where we last stopped tracking hover | 
| -  // (c) We started tracking previously due to (a) or (b) and haven't stopped | 
| -  //     yet (user hasn't used the keyboard to interact again) | 
| -  const bool action_button_pressed = !!(keys & (MK_MBUTTON | MK_LBUTTON)); | 
| -  CPoint screen_point(point); | 
| -  ClientToScreen(&screen_point); | 
| -  if (action_button_pressed || (last_hover_coordinates_ != screen_point) || | 
| -      (model_->hovered_line() != AutocompletePopupModel::kNoMatch)) { | 
| -    // Determine the hovered line from the y coordinate of the event.  We don't | 
| -    // need to check whether the x coordinates are within the window since if | 
| -    // they weren't someone else would have received the WM_MOUSEMOVE. | 
| -    const size_t new_hovered_line = PixelToLine(point.y); | 
| -    model_->SetHoveredLine(new_hovered_line); | 
| - | 
| -    // When the user has the left button down, update their selection | 
| -    // immediately (don't wait for mouseup). | 
| -    if (keys & MK_LBUTTON) | 
| -      model_->SetSelectedLine(new_hovered_line, false); | 
| -  } | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::OnPaint(HDC other_dc) { | 
| -  const AutocompleteResult& result = model_->result(); | 
| -  CHECK(!result.empty());  // Shouldn't be drawing an empty popup; any empty | 
| -                           // result set should have synchronously closed us. | 
| - | 
| -  CPaintDC dc(m_hWnd); | 
| - | 
| -  RECT rc; | 
| -  GetClientRect(&rc); | 
| -  mirroring_context_->Initialize(rc.left, rc.right, | 
| -      l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT); | 
| -  DrawBorder(rc, dc); | 
| - | 
| -  bool all_descriptions_empty = true; | 
| -  for (AutocompleteResult::const_iterator i(result.begin()); i != result.end(); | 
| -       ++i) { | 
| -    if (!i->description.empty()) { | 
| -      all_descriptions_empty = false; | 
| -      break; | 
| -    } | 
| -  } | 
| - | 
| -  // Only repaint the invalid lines. | 
| -  // In rare cases, it seems possible to get line offsets off the end of the | 
| -  // popup.  I suspect this can happen when the user invalidates a new line | 
| -  // (e.g. by moving the mouse) and, before the paint request is serviced, hits | 
| -  // a key that causes autocomplete to run, causing the results list to become | 
| -  // shorter (at least initially).  So sanitize the line numbers here. | 
| -  const size_t last_valid_line = result.size() - 1; | 
| -  const size_t first_line = PixelToLine(dc.m_ps.rcPaint.top); | 
| -  if (first_line > last_valid_line) | 
| -    return; | 
| -  const size_t last_line = | 
| -      std::min(PixelToLine(dc.m_ps.rcPaint.bottom), last_valid_line); | 
| - | 
| -  for (size_t i = first_line; i <= last_line; ++i) { | 
| -    DrawLineInfo::LineStatus status; | 
| -    // Selection should take precedence over hover. | 
| -    if (i == model_->selected_line()) | 
| -      status = DrawLineInfo::SELECTED; | 
| -    else if (i == model_->hovered_line()) | 
| -      status = DrawLineInfo::HOVERED; | 
| -    else | 
| -      status = DrawLineInfo::NORMAL; | 
| -    DrawEntry(dc, rc, i, status, all_descriptions_empty, | 
| -              result.match_at(i).starred); | 
| -  } | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::OnButtonUp(const CPoint& point, | 
| -                                          WindowOpenDisposition disposition) { | 
| -  const size_t line = PixelToLine(point.y); | 
| -  const AutocompleteMatch& match = model_->result().match_at(line); | 
| -  // OpenURL() may close the popup, which will clear the result set and, by | 
| -  // extension, |match| and its contents.  So copy the relevant strings out to | 
| -  // make sure they stay alive until the call completes. | 
| -  const GURL url(match.destination_url); | 
| -  std::wstring keyword; | 
| -  const bool is_keyword_hint = model_->GetKeywordForMatch(match, &keyword); | 
| -  edit_view_->OpenURL(url, disposition, match.transition, GURL(), line, | 
| -                      is_keyword_hint ? std::wstring() : keyword); | 
| -} | 
| - | 
| -int AutocompletePopupViewWin::LineTopPixel(size_t line) const { | 
| -  // The popup has a 1 px top border. | 
| -  return line_info_.line_height * static_cast<int>(line) + 1; | 
| -} | 
| - | 
| -size_t AutocompletePopupViewWin::PixelToLine(int y) const { | 
| -  const size_t line = std::max(y - 1, 0) / line_info_.line_height; | 
| -  return std::min(line, model_->result().size() - 1); | 
| -} | 
| - | 
| -// Draws a light border around the inside of the window with the given client | 
| -// rectangle and DC. | 
| -void AutocompletePopupViewWin::DrawBorder(const RECT& rc, HDC dc) { | 
| -  HPEN hpen = CreatePen(PS_SOLID, 1, RGB(199, 202, 206)); | 
| -  HGDIOBJ old_pen = SelectObject(dc, hpen); | 
| - | 
| -  int width = rc.right - rc.left - 1; | 
| -  int height = rc.bottom - rc.top - 1; | 
| - | 
| -  MoveToEx(dc, 0, 0, NULL); | 
| -  LineTo(dc, 0, height); | 
| -  LineTo(dc, width, height); | 
| -  LineTo(dc, width, 0); | 
| -  LineTo(dc, 0, 0); | 
| - | 
| -  SelectObject(dc, old_pen); | 
| -  DeleteObject(hpen); | 
| -} | 
| - | 
| -int AutocompletePopupViewWin::DrawString(HDC dc, | 
| -                                         int x, | 
| -                                         int y, | 
| -                                         int max_x, | 
| -                                         const wchar_t* text, | 
| -                                         int length, | 
| -                                         int style, | 
| -                                         const DrawLineInfo::LineStatus status, | 
| -                                         const MirroringContext* context, | 
| -                                         bool text_direction_is_rtl) const { | 
| -  if (length <= 0) | 
| -    return 0; | 
| - | 
| -  // Set up the text decorations. | 
| -  SelectObject(dc, (style & ACMatchClassification::MATCH) ? | 
| -      line_info_.bold_font.hfont() : line_info_.regular_font.hfont()); | 
| -  const COLORREF foreground = (style & ACMatchClassification::URL) ? | 
| -      line_info_.url_colors[status] : line_info_.text_colors[status]; | 
| -  const COLORREF background = line_info_.background_colors[status]; | 
| -  SetTextColor(dc, (style & ACMatchClassification::DIM) ? | 
| -      DrawLineInfo::AlphaBlend(foreground, background, 0xAA) : foreground); | 
| - | 
| -  // Retrieve the width of the decorated text and display it. When we cannot | 
| -  // display this fragment in the given width, we trim the fragment and add an | 
| -  // ellipsis. | 
| -  // | 
| -  // TODO(hbono): http:///b/1222425 We should change the following eliding code | 
| -  // with more aggressive one. | 
| -  int text_x = x; | 
| -  int max_length = 0; | 
| -  SIZE text_size = {0}; | 
| -  GetTextExtentExPoint(dc, text, length, | 
| -                       max_x - line_info_.ellipsis_width - text_x, &max_length, | 
| -                       NULL, &text_size); | 
| - | 
| -  if (max_length < length) | 
| -    GetTextExtentPoint32(dc, text, max_length, &text_size); | 
| - | 
| -  const int mirrored_x = context->GetLeft(text_x, text_x + text_size.cx); | 
| -  RECT text_bounds = {mirrored_x, | 
| -                      0, | 
| -                      mirrored_x + text_size.cx, | 
| -                      line_info_.line_height}; | 
| - | 
| -  int flags = DT_SINGLELINE | DT_NOPREFIX; | 
| -  if (text_direction_is_rtl) | 
| -    // In order to make sure RTL text is displayed correctly (for example, a | 
| -    // trailing space should be displayed on the left and not on the right), we | 
| -    // pass the flag DT_RTLREADING. | 
| -    flags |= DT_RTLREADING; | 
| - | 
| -  DrawText(dc, text, length, &text_bounds, flags); | 
| -  text_x += text_size.cx; | 
| - | 
| -  // Draw the ellipsis. Note that since we use the mirroring context, the | 
| -  // ellipsis are drawn either to the right or to the left of the text. | 
| -  if (max_length < length) { | 
| -    TextOut(dc, context->GetLeft(text_x, text_x + line_info_.ellipsis_width), | 
| -            0, line_info_.ellipsis_str, arraysize(line_info_.ellipsis_str) - 1); | 
| -    text_x += line_info_.ellipsis_width; | 
| -  } | 
| - | 
| -  return text_x - x; | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::DrawMatchFragments( | 
| -    HDC dc, | 
| -    const std::wstring& text, | 
| -    const ACMatchClassifications& classifications, | 
| -    int x, | 
| -    int y, | 
| -    int max_x, | 
| -    DrawLineInfo::LineStatus status) const { | 
| -  if (!text.length()) | 
| -    return; | 
| - | 
| -  // Check whether or not this text is a URL string. | 
| -  // A URL string is basically in English with possible included words in | 
| -  // Arabic or Hebrew. For such case, ICU provides a special algorithm and we | 
| -  // should use it. | 
| -  bool url = false; | 
| -  for (ACMatchClassifications::const_iterator i = classifications.begin(); | 
| -       i != classifications.end(); ++i) { | 
| -    if (i->style & ACMatchClassification::URL) | 
| -      url = true; | 
| -  } | 
| - | 
| -  // Initialize a bidirectional line iterator of ICU and split the text into | 
| -  // visual runs. (A visual run is consecutive characters which have the same | 
| -  // display direction and should be displayed at once.) | 
| -  l10n_util::BiDiLineIterator bidi_line; | 
| -  if (!bidi_line.Open(text, mirroring_context_->enabled(), url)) | 
| -    return; | 
| -  const int runs = bidi_line.CountRuns(); | 
| - | 
| -  // Draw the visual runs. | 
| -  // This loop splits each run into text fragments with the given | 
| -  // classifications and draws the text fragments. | 
| -  // When the direction of a run is right-to-left, we have to mirror the | 
| -  // x-coordinate of this run and render the fragments in the right-to-left | 
| -  // reading order. To handle this display order independently from the one of | 
| -  // this popup window, this loop renders a run with the steps below: | 
| -  // 1. Create a local display context for each run; | 
| -  // 2. Render the run into the local display context, and; | 
| -  // 3. Copy the local display context to the one of the popup window. | 
| -  int run_x = x; | 
| -  for (int run = 0; run < runs; ++run) { | 
| -    int run_start = 0; | 
| -    int run_length = 0; | 
| - | 
| -    // The index we pass to GetVisualRun corresponds to the position of the run | 
| -    // in the displayed text. For example, the string "Google in HEBREW" (where | 
| -    // HEBREW is text in the Hebrew language) has two runs: "Google in " which | 
| -    // is an LTR run, and "HEBREW" which is an RTL run. In an LTR context, the | 
| -    // run "Google in " has the index 0 (since it is the leftmost run | 
| -    // displayed). In an RTL context, the same run has the index 1 because it | 
| -    // is the rightmost run. This is why the order in which we traverse the | 
| -    // runs is different depending on the locale direction. | 
| -    // | 
| -    // Note that for URLs we always traverse the runs from lower to higher | 
| -    // indexes because the return order of runs for a URL always matches the | 
| -    // physical order of the context. | 
| -    int current_run = | 
| -        (mirroring_context_->enabled() && !url) ? (runs - run - 1) : run; | 
| -    const UBiDiDirection run_direction = bidi_line.GetVisualRun(current_run, | 
| -                                                                &run_start, | 
| -                                                                &run_length); | 
| -    const int run_end = run_start + run_length; | 
| - | 
| -    // Set up a local display context for rendering this run. | 
| -    int text_x = 0; | 
| -    const int text_max_x = max_x - run_x; | 
| -    MirroringContext run_context; | 
| -    run_context.Initialize(0, text_max_x, run_direction == UBIDI_RTL); | 
| - | 
| -    // In addition to creating a mirroring context for the run, we indicate | 
| -    // whether the run needs to be rendered as RTL text. The mirroring context | 
| -    // alone in not sufficient because there are cases where a mirrored RTL run | 
| -    // needs to be rendered in an LTR context (for example, an RTL run within | 
| -    // an URL). | 
| -    bool run_direction_is_rtl = (run_direction == UBIDI_RTL) && !url; | 
| -    CDC text_dc(CreateCompatibleDC(dc)); | 
| -    CBitmap text_bitmap(CreateCompatibleBitmap(dc, text_max_x, | 
| -                                               line_info_.font_height)); | 
| -    SelectObject(text_dc, text_bitmap); | 
| -    const RECT text_rect = {0, 0, text_max_x, line_info_.line_height}; | 
| -    FillRect(text_dc, &text_rect, line_info_.brushes[status]); | 
| -    SetBkMode(text_dc, TRANSPARENT); | 
| - | 
| -    // Split this run with the given classifications and draw the fragments | 
| -    // into the local display context. | 
| -    for (ACMatchClassifications::const_iterator i = classifications.begin(); | 
| -         i != classifications.end(); ++i) { | 
| -      const int text_start = std::max(run_start, static_cast<int>(i->offset)); | 
| -      const int text_end = std::min(run_end, (i != classifications.end() - 1) ? | 
| -          static_cast<int>((i + 1)->offset) : run_end); | 
| -      text_x += DrawString(text_dc, text_x, 0, text_max_x, &text[text_start], | 
| -                           text_end - text_start, i->style, status, | 
| -                           &run_context, run_direction_is_rtl); | 
| -    } | 
| - | 
| -    // Copy the local display context to the one of the popup window and | 
| -    // delete the local display context. | 
| -    BitBlt(dc, mirroring_context_->GetLeft(run_x, run_x + text_x), y, text_x, | 
| -           line_info_.line_height, text_dc, run_context.GetLeft(0, text_x), 0, | 
| -           SRCCOPY); | 
| -    run_x += text_x; | 
| -  } | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::DrawEntry(HDC dc, | 
| -                                         const RECT& client_rect, | 
| -                                         size_t line, | 
| -                                         DrawLineInfo::LineStatus status, | 
| -                                         bool all_descriptions_empty, | 
| -                                         bool starred) const { | 
| -  // Calculate outer bounds of entry, and fill background. | 
| -  const int top_pixel = LineTopPixel(line); | 
| -  const RECT rc = {1, top_pixel, client_rect.right - client_rect.left - 1, | 
| -                   top_pixel + line_info_.line_height}; | 
| -  FillRect(dc, &rc, line_info_.brushes[status]); | 
| - | 
| -  // Calculate and display contents/description sections as follows: | 
| -  // * 2 px top margin, bottom margin is handled by line_height. | 
| -  const int y = rc.top + 2; | 
| - | 
| -  // * 1 char left/right margin. | 
| -  const int side_margin = line_info_.ave_char_width; | 
| - | 
| -  // * 50% of the remaining width is initially allocated to each section, with | 
| -  //   a 2 char margin followed by the star column and kStarPadding padding. | 
| -  const int content_min_x = rc.left + side_margin; | 
| -  const int description_max_x = rc.right - side_margin; | 
| -  const int mid_line = (description_max_x - content_min_x) / 2 + content_min_x; | 
| -  const int star_col_width = kStarPadding + star_->width(); | 
| -  const int content_right_margin = line_info_.ave_char_width * 2; | 
| - | 
| -  // * If this would make the content section display fewer than 40 characters, | 
| -  //   the content section is increased to that minimum at the expense of the | 
| -  //   description section. | 
| -  const int content_width = | 
| -      std::max(mid_line - content_min_x - content_right_margin, | 
| -               line_info_.ave_char_width * 40); | 
| -  const int description_width = description_max_x - content_min_x - | 
| -      content_width - star_col_width; | 
| - | 
| -  // * If this would make the description section display fewer than 20 | 
| -  //   characters, or if there are no descriptions to display or the result is | 
| -  //   the HISTORY_SEARCH shortcut, the description section is eliminated, and | 
| -  //   all the available width is used for the content section. | 
| -  int star_x; | 
| -  const AutocompleteMatch& match = model_->result().match_at(line); | 
| -  if ((description_width < (line_info_.ave_char_width * 20)) || | 
| -      all_descriptions_empty || | 
| -      (match.type == AutocompleteMatch::OPEN_HISTORY_PAGE)) { | 
| -    star_x = description_max_x - star_col_width + kStarPadding; | 
| -    DrawMatchFragments(dc, match.contents, match.contents_class, content_min_x, | 
| -                       y, star_x - kStarPadding, status); | 
| -  } else { | 
| -    star_x = description_max_x - description_width - star_col_width; | 
| -    DrawMatchFragments(dc, match.contents, match.contents_class, content_min_x, | 
| -                       y, content_min_x + content_width, status); | 
| -    DrawMatchFragments(dc, match.description, match.description_class, | 
| -                       description_max_x - description_width, y, | 
| -                       description_max_x, status); | 
| -  } | 
| -  if (starred) | 
| -    DrawStar(dc, star_x, | 
| -             (line_info_.line_height - star_->height()) / 2 + top_pixel); | 
| -} | 
| - | 
| -void AutocompletePopupViewWin::DrawStar(HDC dc, int x, int y) const { | 
| -  gfx::Canvas canvas(star_->width(), star_->height(), false); | 
| -  // Make the background completely transparent. | 
| -  canvas.drawColor(SK_ColorBLACK, SkXfermode::kClear_Mode); | 
| -  canvas.DrawBitmapInt(*star_, 0, 0); | 
| -  canvas.getTopPlatformDevice().drawToHDC( | 
| -      dc, mirroring_context_->GetLeft(x, x + star_->width()), y, NULL); | 
| -} | 
| - | 
| -// static | 
| -AutocompletePopupView* AutocompletePopupView::CreatePopupView( | 
| -    const gfx::Font& font, | 
| -    AutocompleteEditViewWin* edit_view, | 
| -    AutocompleteEditModel* edit_model, | 
| -    Profile* profile, | 
| -    AutocompletePopupPositioner* popup_positioner) { | 
| -  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableOmnibox2)) | 
| -    return new AutocompletePopupViewWin(font, edit_view, edit_model, profile); | 
| -  return new AutocompletePopupContentsView(font, edit_view, edit_model, | 
| -                                           profile, popup_positioner); | 
| -} | 
|  |