searchbox.cc revision 868fa2fe829687343ffae624259930155e16dbd8
11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// Copyright 2012 The Chromium Authors. All rights reserved.
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// Use of this source code is governed by a BSD-style license that can be
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// found in the LICENSE file.
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "chrome/renderer/searchbox/searchbox.h"
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include <string>
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "base/string_number_conversions.h"
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "base/string_util.h"
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "base/strings/utf_string_conversions.h"
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "chrome/common/chrome_switches.h"
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "chrome/common/omnibox_focus_state.h"
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "chrome/common/render_messages.h"
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "chrome/common/url_constants.h"
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "chrome/renderer/searchbox/searchbox_extension.h"
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "content/public/renderer/render_view.h"
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "googleurl/src/gurl.h"
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "grit/renderer_resources.h"
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "net/base/escape.h"
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "ui/base/resource/resource_bundle.h"
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertnamespace {
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// Size of the results cache.
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertconst size_t kMaxInstantAutocompleteResultItemCacheSize = 100;
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}  // namespace
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertnamespace internal {  // for testing
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// Parses |url| and fills in |id| with the InstantRestrictedID obtained from the
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// |url|. |render_view_id| is the ID of the associated RenderView.
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert//
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// Valid |url| forms:
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// chrome-search://favicon/<view_id>/<restricted_id>
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// chrome-search://thumb/<view_id>/<restricted_id>
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert//
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// If the |url| is valid, returns true and fills in |id| with restricted_id
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// value. If the |url| is invalid, returns false and |id| is not set.
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertbool GetInstantRestrictedIDFromURL(int render_view_id,
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                                   const GURL& url,
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                                   InstantRestrictedID* id) {
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // Strip leading path.
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  std::string path = url.path().substr(1);
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // Check that the path is of Most visited item ID form.
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  std::vector<std::string> tokens;
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  if (Tokenize(path, "/", &tokens) != 2)
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return false;
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  int view_id = 0;
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  if (!base::StringToInt(tokens[0], &view_id) || view_id != render_view_id)
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return false;
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  return base::StringToInt(tokens[1], id);
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}  // namespace internal
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn BringertSearchBox::SearchBox(content::RenderView* render_view)
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    : content::RenderViewObserver(render_view),
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      content::RenderViewObserverTracker<SearchBox>(render_view),
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      verbatim_(false),
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      query_is_restricted_(false),
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      selection_start_(0),
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      selection_end_(0),
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      start_margin_(0),
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      is_focused_(false),
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      is_key_capture_enabled_(false),
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      display_instant_results_(false),
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      omnibox_font_size_(0),
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      autocomplete_results_cache_(kMaxInstantAutocompleteResultItemCacheSize),
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      most_visited_items_cache_(kMaxInstantMostVisitedItemCacheSize) {
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn BringertSearchBox::~SearchBox() {
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertvoid SearchBox::SetSuggestions(
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    const std::vector<InstantSuggestion>& suggestions) {
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  if (!suggestions.empty() &&
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      suggestions[0].behavior == INSTANT_COMPLETE_REPLACE) {
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    SetQuery(suggestions[0].text, true);
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    selection_start_ = selection_end_ = query_.size();
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // Explicitly allow empty vector to be sent to the browser.
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  render_view()->Send(new ChromeViewHostMsg_SetSuggestions(
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      render_view()->GetRoutingID(), render_view()->GetPageId(), suggestions));
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertvoid SearchBox::MarkQueryAsRestricted() {
951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  query_is_restricted_ = true;
961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  query_.clear();
971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertvoid SearchBox::ShowInstantOverlay(int height, InstantSizeUnits units) {
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  render_view()->Send(new ChromeViewHostMsg_ShowInstantOverlay(
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      render_view()->GetRoutingID(), render_view()->GetPageId(), height,
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      units));
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertvoid SearchBox::FocusOmnibox() {
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  render_view()->Send(new ChromeViewHostMsg_FocusOmnibox(
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      render_view()->GetRoutingID(), render_view()->GetPageId(),
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      OMNIBOX_FOCUS_VISIBLE));
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertvoid SearchBox::StartCapturingKeyStrokes() {
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  render_view()->Send(new ChromeViewHostMsg_FocusOmnibox(
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      render_view()->GetRoutingID(), render_view()->GetPageId(),
1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      OMNIBOX_FOCUS_INVISIBLE));
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertvoid SearchBox::StopCapturingKeyStrokes() {
118  render_view()->Send(new ChromeViewHostMsg_FocusOmnibox(
119      render_view()->GetRoutingID(), render_view()->GetPageId(),
120      OMNIBOX_FOCUS_NONE));
121}
122
123void SearchBox::NavigateToURL(const GURL& url,
124                              content::PageTransition transition,
125                              WindowOpenDisposition disposition,
126                              bool is_search_type) {
127  render_view()->Send(new ChromeViewHostMsg_SearchBoxNavigate(
128      render_view()->GetRoutingID(), render_view()->GetPageId(),
129      url, transition, disposition, is_search_type));
130}
131
132void SearchBox::DeleteMostVisitedItem(
133    InstantRestrictedID most_visited_item_id) {
134  render_view()->Send(new ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem(
135      render_view()->GetRoutingID(), render_view()->GetPageId(),
136      GetURLForMostVisitedItem(most_visited_item_id)));
137}
138
139void SearchBox::UndoMostVisitedDeletion(
140    InstantRestrictedID most_visited_item_id) {
141  render_view()->Send(new ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion(
142      render_view()->GetRoutingID(), render_view()->GetPageId(),
143      GetURLForMostVisitedItem(most_visited_item_id)));
144}
145
146void SearchBox::UndoAllMostVisitedDeletions() {
147  render_view()->Send(
148      new ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions(
149      render_view()->GetRoutingID(), render_view()->GetPageId()));
150}
151
152void SearchBox::ShowBars() {
153  DVLOG(1) << render_view() << " ShowBars";
154  render_view()->Send(new ChromeViewHostMsg_SearchBoxShowBars(
155      render_view()->GetRoutingID(), render_view()->GetPageId()));
156}
157
158void SearchBox::HideBars() {
159  DVLOG(1) << render_view() << " HideBars";
160  render_view()->Send(new ChromeViewHostMsg_SearchBoxHideBars(
161      render_view()->GetRoutingID(), render_view()->GetPageId()));
162}
163
164int SearchBox::GetStartMargin() const {
165  return static_cast<int>(start_margin_ / GetZoom());
166}
167
168gfx::Rect SearchBox::GetPopupBounds() const {
169  double zoom = GetZoom();
170  return gfx::Rect(static_cast<int>(popup_bounds_.x() / zoom),
171                   static_cast<int>(popup_bounds_.y() / zoom),
172                   static_cast<int>(popup_bounds_.width() / zoom),
173                   static_cast<int>(popup_bounds_.height() / zoom));
174}
175
176void SearchBox::GetAutocompleteResults(
177    std::vector<InstantAutocompleteResultIDPair>* results) const {
178  autocomplete_results_cache_.GetCurrentItems(results);
179}
180
181bool SearchBox::GetAutocompleteResultWithID(
182    InstantRestrictedID autocomplete_result_id,
183    InstantAutocompleteResult* result) const {
184  return autocomplete_results_cache_.GetItemWithRestrictedID(
185      autocomplete_result_id, result);
186}
187
188const ThemeBackgroundInfo& SearchBox::GetThemeBackgroundInfo() {
189  return theme_info_;
190}
191
192bool SearchBox::GenerateThumbnailURLFromTransientURL(const GURL& transient_url,
193                                                     GURL* url) const {
194  InstantRestrictedID rid = 0;
195  if (!internal::GetInstantRestrictedIDFromURL(render_view()->GetRoutingID(),
196                                               transient_url, &rid)) {
197    return false;
198  }
199
200  GURL most_visited_item_url(GetURLForMostVisitedItem(rid));
201  if (most_visited_item_url.is_empty())
202    return false;
203  *url = GURL(base::StringPrintf("chrome-search://thumb/%s",
204                                 most_visited_item_url.spec().c_str()));
205  return true;
206}
207
208bool SearchBox::GenerateFaviconURLFromTransientURL(const GURL& transient_url,
209                                                   GURL* url) const {
210  InstantRestrictedID rid = 0;
211  if (!internal::GetInstantRestrictedIDFromURL(render_view()->GetRoutingID(),
212                                               transient_url, &rid)) {
213    return false;
214  }
215
216  GURL most_visited_item_url(GetURLForMostVisitedItem(rid));
217  if (most_visited_item_url.is_empty())
218    return false;
219  *url = GURL(base::StringPrintf("chrome-search://favicon/%s",
220                                 most_visited_item_url.spec().c_str()));
221  return true;
222}
223
224bool SearchBox::OnMessageReceived(const IPC::Message& message) {
225  bool handled = true;
226  IPC_BEGIN_MESSAGE_MAP(SearchBox, message)
227    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxChange, OnChange)
228    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxSubmit, OnSubmit)
229    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxCancel, OnCancel)
230    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxPopupResize, OnPopupResize)
231    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxMarginChange, OnMarginChange)
232    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxBarsHidden, OnBarsHidden)
233    IPC_MESSAGE_HANDLER(ChromeViewMsg_DetermineIfPageSupportsInstant,
234                        OnDetermineIfPageSupportsInstant)
235    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxAutocompleteResults,
236                        OnAutocompleteResults)
237    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxUpOrDownKeyPressed,
238                        OnUpOrDownKeyPressed)
239    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxEscKeyPressed, OnEscKeyPressed)
240    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxCancelSelection,
241                        OnCancelSelection)
242    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxSetDisplayInstantResults,
243                        OnSetDisplayInstantResults)
244    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxFocusChanged, OnFocusChanged)
245    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxThemeChanged,
246                        OnThemeChanged)
247    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxFontInformation,
248                        OnFontInformationReceived)
249    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxMostVisitedItemsChanged,
250                        OnMostVisitedChanged)
251    IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxToggleVoiceSearch,
252                        OnToggleVoiceSearch)
253    IPC_MESSAGE_UNHANDLED(handled = false)
254  IPC_END_MESSAGE_MAP()
255  return handled;
256}
257
258void SearchBox::OnChange(const string16& query,
259                         bool verbatim,
260                         size_t selection_start,
261                         size_t selection_end) {
262  SetQuery(query, verbatim);
263  selection_start_ = selection_start;
264  selection_end_ = selection_end;
265
266  // If |query| is empty, this is due to the user backspacing away all the text
267  // in the omnibox, or hitting Escape to restore the "permanent URL", or
268  // switching tabs, etc. In all these cases, there will be no corresponding
269  // OnAutocompleteResults(), so clear the autocomplete results ourselves, by
270  // adding an empty set. Don't notify the page using an "onnativesuggestions"
271  // event, though.
272  if (query.empty()) {
273    autocomplete_results_cache_.AddItems(
274        std::vector<InstantAutocompleteResult>());
275  }
276
277  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
278    DVLOG(1) << render_view() << " OnChange";
279    extensions_v8::SearchBoxExtension::DispatchChange(
280        render_view()->GetWebView()->mainFrame());
281  }
282}
283
284void SearchBox::OnSubmit(const string16& query) {
285  // Submit() is called when the user hits Enter to commit the omnibox text.
286  // If |query| is non-blank, the user committed a search. If it's blank, the
287  // omnibox text was a URL, and the user is navigating to it, in which case
288  // we shouldn't update the |query_| or associated state.
289  if (!query.empty()) {
290    SetQuery(query, true);
291    selection_start_ = selection_end_ = query_.size();
292  }
293
294  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
295    DVLOG(1) << render_view() << " OnSubmit";
296    extensions_v8::SearchBoxExtension::DispatchSubmit(
297        render_view()->GetWebView()->mainFrame());
298  }
299
300  if (!query.empty())
301    Reset();
302}
303
304void SearchBox::OnCancel(const string16& query) {
305  SetQuery(query, true);
306  selection_start_ = selection_end_ = query_.size();
307  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
308    DVLOG(1) << render_view() << " OnCancel";
309    extensions_v8::SearchBoxExtension::DispatchCancel(
310        render_view()->GetWebView()->mainFrame());
311  }
312  Reset();
313}
314
315void SearchBox::OnPopupResize(const gfx::Rect& bounds) {
316  popup_bounds_ = bounds;
317  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
318    DVLOG(1) << render_view() << " OnPopupResize";
319    extensions_v8::SearchBoxExtension::DispatchResize(
320        render_view()->GetWebView()->mainFrame());
321  }
322}
323
324void SearchBox::OnMarginChange(int margin, int width) {
325  start_margin_ = margin;
326
327  // Override only the width parameter of the popup bounds.
328  popup_bounds_.set_width(width);
329
330  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
331    extensions_v8::SearchBoxExtension::DispatchMarginChange(
332        render_view()->GetWebView()->mainFrame());
333  }
334}
335
336void SearchBox::OnBarsHidden() {
337  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
338    extensions_v8::SearchBoxExtension::DispatchBarsHidden(
339        render_view()->GetWebView()->mainFrame());
340  }
341}
342
343void SearchBox::OnDetermineIfPageSupportsInstant() {
344  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
345    bool result = extensions_v8::SearchBoxExtension::PageSupportsInstant(
346        render_view()->GetWebView()->mainFrame());
347    DVLOG(1) << render_view() << " PageSupportsInstant: " << result;
348    render_view()->Send(new ChromeViewHostMsg_InstantSupportDetermined(
349        render_view()->GetRoutingID(), render_view()->GetPageId(), result));
350  }
351}
352
353void SearchBox::OnAutocompleteResults(
354    const std::vector<InstantAutocompleteResult>& results) {
355  autocomplete_results_cache_.AddItems(results);
356  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
357    DVLOG(1) << render_view() << " OnAutocompleteResults";
358    extensions_v8::SearchBoxExtension::DispatchAutocompleteResults(
359        render_view()->GetWebView()->mainFrame());
360  }
361}
362
363void SearchBox::OnUpOrDownKeyPressed(int count) {
364  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
365    DVLOG(1) << render_view() << " OnKeyPress: " << count;
366    extensions_v8::SearchBoxExtension::DispatchUpOrDownKeyPress(
367        render_view()->GetWebView()->mainFrame(), count);
368  }
369}
370
371void SearchBox::OnEscKeyPressed() {
372  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
373    DVLOG(1) << render_view() << " OnEscKeyPressed ";
374    extensions_v8::SearchBoxExtension::DispatchEscKeyPress(
375        render_view()->GetWebView()->mainFrame());
376  }
377}
378
379void SearchBox::OnCancelSelection(const string16& query,
380                                  bool verbatim,
381                                  size_t selection_start,
382                                  size_t selection_end) {
383  SetQuery(query, verbatim);
384  selection_start_ = selection_start;
385  selection_end_ = selection_end;
386  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
387    DVLOG(1) << render_view() << " OnKeyPress ESC";
388    extensions_v8::SearchBoxExtension::DispatchEscKeyPress(
389        render_view()->GetWebView()->mainFrame());
390  }
391}
392
393void SearchBox::OnFocusChanged(OmniboxFocusState new_focus_state,
394                               OmniboxFocusChangeReason reason) {
395  bool key_capture_enabled = new_focus_state == OMNIBOX_FOCUS_INVISIBLE;
396  if (key_capture_enabled != is_key_capture_enabled_) {
397    // Tell the page if the key capture mode changed unless the focus state
398    // changed because of TYPING. This is because in that case, the browser
399    // hasn't really stopped capturing key strokes.
400    //
401    // (More practically, if we don't do this check, the page would receive
402    // onkeycapturechange before the corresponding onchange, and the page would
403    // have no way of telling whether the keycapturechange happened because of
404    // some actual user action or just because they started typing.)
405    if (reason != OMNIBOX_FOCUS_CHANGE_TYPING &&
406        render_view()->GetWebView() &&
407        render_view()->GetWebView()->mainFrame()) {
408      is_key_capture_enabled_ = key_capture_enabled;
409      DVLOG(1) << render_view() << " OnKeyCaptureChange";
410      extensions_v8::SearchBoxExtension::DispatchKeyCaptureChange(
411          render_view()->GetWebView()->mainFrame());
412    }
413  }
414  bool is_focused = new_focus_state == OMNIBOX_FOCUS_VISIBLE;
415  if (is_focused != is_focused_) {
416    is_focused_ = is_focused;
417    DVLOG(1) << render_view() << " OnFocusChange";
418    extensions_v8::SearchBoxExtension::DispatchFocusChange(
419        render_view()->GetWebView()->mainFrame());
420  }
421}
422
423void SearchBox::OnSetDisplayInstantResults(bool display_instant_results) {
424  display_instant_results_ = display_instant_results;
425}
426
427void SearchBox::OnThemeChanged(const ThemeBackgroundInfo& theme_info) {
428  theme_info_ = theme_info;
429  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
430    extensions_v8::SearchBoxExtension::DispatchThemeChange(
431        render_view()->GetWebView()->mainFrame());
432  }
433}
434
435void SearchBox::OnFontInformationReceived(const string16& omnibox_font,
436                                          size_t omnibox_font_size) {
437  omnibox_font_ = omnibox_font;
438  omnibox_font_size_ = omnibox_font_size;
439}
440
441double SearchBox::GetZoom() const {
442  WebKit::WebView* web_view = render_view()->GetWebView();
443  if (web_view) {
444    double zoom = WebKit::WebView::zoomLevelToZoomFactor(web_view->zoomLevel());
445    if (zoom != 0)
446      return zoom;
447  }
448  return 1.0;
449}
450
451void SearchBox::Reset() {
452  query_.clear();
453  verbatim_ = false;
454  query_is_restricted_ = false;
455  selection_start_ = 0;
456  selection_end_ = 0;
457  popup_bounds_ = gfx::Rect();
458  start_margin_ = 0;
459  is_focused_ = false;
460  is_key_capture_enabled_ = false;
461  theme_info_ = ThemeBackgroundInfo();
462  // Don't reset display_instant_results_ to prevent clearing it on committed
463  // results pages in extended mode. Otherwise resetting it is a no-op because
464  // a new loader is created when it changes; see crbug.com/164662.
465  // Also don't reset omnibox_font_ or omnibox_font_size_ since it never
466  // changes.
467}
468
469void SearchBox::SetQuery(const string16& query, bool verbatim) {
470  query_ = query;
471  verbatim_ = verbatim;
472  query_is_restricted_ = false;
473}
474
475void SearchBox::OnMostVisitedChanged(
476    const std::vector<InstantMostVisitedItem>& items) {
477  most_visited_items_cache_.AddItems(items);
478  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
479    extensions_v8::SearchBoxExtension::DispatchMostVisitedChanged(
480        render_view()->GetWebView()->mainFrame());
481  }
482}
483
484void SearchBox::GetMostVisitedItems(
485    std::vector<InstantMostVisitedItemIDPair>* items) const {
486  return most_visited_items_cache_.GetCurrentItems(items);
487}
488
489bool SearchBox::GetMostVisitedItemWithID(
490    InstantRestrictedID most_visited_item_id,
491    InstantMostVisitedItem* item) const {
492  return most_visited_items_cache_.GetItemWithRestrictedID(most_visited_item_id,
493                                                           item);
494}
495
496GURL SearchBox::GetURLForMostVisitedItem(InstantRestrictedID item_id) const {
497  InstantMostVisitedItem item;
498  return GetMostVisitedItemWithID(item_id, &item) ? item.url : GURL();
499}
500
501void SearchBox::OnToggleVoiceSearch() {
502  if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
503    extensions_v8::SearchBoxExtension::DispatchToggleVoiceSearch(
504        render_view()->GetWebView()->mainFrame());
505  }
506}
507