OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/renderer/searchbox/searchbox.h" | 5 #include "chrome/renderer/searchbox/searchbox.h" |
6 | 6 |
7 #include "base/utf_string_conversions.h" | 7 #include "chrome/common/instant_messages.h" |
8 #include "chrome/common/render_messages.h" | |
9 #include "chrome/common/url_constants.h" | |
10 #include "chrome/renderer/searchbox/searchbox_extension.h" | 8 #include "chrome/renderer/searchbox/searchbox_extension.h" |
11 #include "content/public/renderer/render_view.h" | 9 #include "content/public/renderer/render_view.h" |
12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityPolicy.h" | |
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | 10 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
14 | 11 |
15 namespace { | |
16 | |
17 // Prefix for a thumbnail URL. | |
18 const char kThumbnailUrlPrefix[] = "chrome-search://thumb/"; | |
19 | |
20 // Prefix for a thumbnail URL. | |
21 const char kFaviconUrlPrefix[] = "chrome-search://favicon/"; | |
22 | |
23 } | |
24 | |
25 SearchBox::SearchBox(content::RenderView* render_view) | 12 SearchBox::SearchBox(content::RenderView* render_view) |
26 : content::RenderViewObserver(render_view), | 13 : content::RenderViewObserver(render_view), |
27 content::RenderViewObserverTracker<SearchBox>(render_view), | 14 content::RenderViewObserverTracker<SearchBox>(render_view), |
28 verbatim_(false), | 15 verbatim_(false), |
29 selection_start_(0), | 16 selection_start_(0), |
30 selection_end_(0), | 17 selection_end_(0) { |
31 results_base_(0), | |
32 start_margin_(0), | |
33 last_results_base_(0), | |
34 is_key_capture_enabled_(false), | |
35 display_instant_results_(false), | |
36 omnibox_font_size_(0), | |
37 last_restricted_id_(0) { | |
38 } | 18 } |
39 | 19 |
40 SearchBox::~SearchBox() { | 20 SearchBox::~SearchBox() { |
41 } | 21 } |
42 | 22 |
43 void SearchBox::SetSuggestions( | |
44 const std::vector<InstantSuggestion>& suggestions) { | |
45 if (!suggestions.empty() && | |
46 suggestions[0].behavior == INSTANT_COMPLETE_REPLACE) { | |
47 query_ = suggestions[0].text; | |
48 verbatim_ = true; | |
49 selection_start_ = selection_end_ = query_.size(); | |
50 } | |
51 // Explicitly allow empty vector to be sent to the browser. | |
52 render_view()->Send(new ChromeViewHostMsg_SetSuggestions( | |
53 render_view()->GetRoutingID(), render_view()->GetPageId(), suggestions)); | |
54 } | |
55 | |
56 void SearchBox::ShowInstantOverlay(InstantShownReason reason, | |
57 int height, | |
58 InstantSizeUnits units) { | |
59 render_view()->Send(new ChromeViewHostMsg_ShowInstantOverlay( | |
60 render_view()->GetRoutingID(), render_view()->GetPageId(), reason, | |
61 height, units)); | |
62 } | |
63 | |
64 void SearchBox::FocusOmnibox() { | |
65 render_view()->Send(new ChromeViewHostMsg_FocusOmnibox( | |
66 render_view()->GetRoutingID(), render_view()->GetPageId())); | |
67 } | |
68 | |
69 void SearchBox::StartCapturingKeyStrokes() { | |
70 render_view()->Send(new ChromeViewHostMsg_StartCapturingKeyStrokes( | |
71 render_view()->GetRoutingID(), render_view()->GetPageId())); | |
72 } | |
73 | |
74 void SearchBox::StopCapturingKeyStrokes() { | |
75 render_view()->Send(new ChromeViewHostMsg_StopCapturingKeyStrokes( | |
76 render_view()->GetRoutingID(), render_view()->GetPageId())); | |
77 } | |
78 | |
79 void SearchBox::NavigateToURL(const GURL& url, | |
80 content::PageTransition transition, | |
81 WindowOpenDisposition disposition) { | |
82 render_view()->Send(new ChromeViewHostMsg_SearchBoxNavigate( | |
83 render_view()->GetRoutingID(), render_view()->GetPageId(), | |
84 url, transition, disposition)); | |
85 } | |
86 | |
87 void SearchBox::DeleteMostVisitedItem(int restrict_id) { | |
88 string16 url = RestrictedIdToURL(restrict_id); | |
89 render_view()->Send(new ChromeViewHostMsg_InstantDeleteMostVisitedItem( | |
90 render_view()->GetRoutingID(), GURL(url))); | |
91 } | |
92 | |
93 void SearchBox::UndoMostVisitedDeletion(int restrict_id) { | |
94 string16 url = RestrictedIdToURL(restrict_id); | |
95 render_view()->Send(new ChromeViewHostMsg_InstantUndoMostVisitedDeletion( | |
96 render_view()->GetRoutingID(), GURL(url))); | |
97 } | |
98 | |
99 void SearchBox::UndoAllMostVisitedDeletions() { | |
100 render_view()->Send(new ChromeViewHostMsg_InstantUndoAllMostVisitedDeletions( | |
101 render_view()->GetRoutingID())); | |
102 } | |
103 | |
104 int SearchBox::GetStartMargin() const { | |
105 return static_cast<int>(start_margin_ / GetZoom()); | |
106 } | |
107 | |
108 gfx::Rect SearchBox::GetPopupBounds() const { | 23 gfx::Rect SearchBox::GetPopupBounds() const { |
109 double zoom = GetZoom(); | 24 double zoom = GetZoom(); |
110 return gfx::Rect(static_cast<int>(popup_bounds_.x() / zoom), | 25 return gfx::Rect(static_cast<int>(popup_bounds_.x() / zoom), |
111 static_cast<int>(popup_bounds_.y() / zoom), | 26 static_cast<int>(popup_bounds_.y() / zoom), |
112 static_cast<int>(popup_bounds_.width() / zoom), | 27 static_cast<int>(popup_bounds_.width() / zoom), |
113 static_cast<int>(popup_bounds_.height() / zoom)); | 28 static_cast<int>(popup_bounds_.height() / zoom)); |
114 } | 29 } |
115 | 30 |
116 const std::vector<InstantAutocompleteResult>& | 31 void SearchBox::SetSuggestion(const InstantSuggestion& suggestion) { |
117 SearchBox::GetAutocompleteResults() { | 32 Send(new ChromeViewHostMsg_SearchBoxSetSuggestion( |
118 // Remember the last requested autocomplete_results to account for race | 33 routing_id(), render_view()->GetPageId(), suggestion)); |
119 // conditions between autocomplete providers returning new data and the user | |
120 // clicking on a suggestion. | |
121 last_autocomplete_results_ = autocomplete_results_; | |
122 last_results_base_ = results_base_; | |
123 return autocomplete_results_; | |
124 } | |
125 | |
126 const InstantAutocompleteResult* SearchBox::GetAutocompleteResultWithId( | |
127 size_t restricted_id) const { | |
128 if (restricted_id < last_results_base_ || | |
129 restricted_id >= last_results_base_ + last_autocomplete_results_.size()) | |
130 return NULL; | |
131 return &last_autocomplete_results_[restricted_id - last_results_base_]; | |
132 } | |
133 | |
134 const ThemeBackgroundInfo& SearchBox::GetThemeBackgroundInfo() { | |
135 return theme_info_; | |
136 } | 34 } |
137 | 35 |
138 bool SearchBox::OnMessageReceived(const IPC::Message& message) { | 36 bool SearchBox::OnMessageReceived(const IPC::Message& message) { |
139 bool handled = true; | 37 bool handled = true; |
140 IPC_BEGIN_MESSAGE_MAP(SearchBox, message) | 38 IPC_BEGIN_MESSAGE_MAP(SearchBox, message) |
| 39 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxDetermineInstantSupport, |
| 40 OnDetermineInstantSupport) |
141 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxChange, OnChange) | 41 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxChange, OnChange) |
142 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxSubmit, OnSubmit) | 42 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxSubmit, OnSubmit) |
143 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxCancel, OnCancel) | 43 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxBlur, OnBlur) |
144 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxPopupResize, OnPopupResize) | 44 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxPopupBounds, OnPopupBounds) |
145 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxMarginChange, OnMarginChange) | |
146 IPC_MESSAGE_HANDLER(ChromeViewMsg_DetermineIfPageSupportsInstant, | |
147 OnDetermineIfPageSupportsInstant) | |
148 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxAutocompleteResults, | |
149 OnAutocompleteResults) | |
150 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxUpOrDownKeyPressed, | |
151 OnUpOrDownKeyPressed) | |
152 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxCancelSelection, | |
153 OnCancelSelection) | |
154 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxSetDisplayInstantResults, | |
155 OnSetDisplayInstantResults) | |
156 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxKeyCaptureChanged, | |
157 OnKeyCaptureChange) | |
158 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxThemeChanged, | |
159 OnThemeChanged) | |
160 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxFontInformation, | |
161 OnFontInformationReceived) | |
162 IPC_MESSAGE_HANDLER( | |
163 ChromeViewMsg_SearchBoxGrantChromeSearchAccessFromOrigin, | |
164 OnGrantChromeSearchAccessFromOrigin) | |
165 IPC_MESSAGE_HANDLER(ChromeViewMsg_InstantMostVisitedItemsChanged, | |
166 OnMostVisitedChanged) | |
167 IPC_MESSAGE_UNHANDLED(handled = false) | 45 IPC_MESSAGE_UNHANDLED(handled = false) |
168 IPC_END_MESSAGE_MAP() | 46 IPC_END_MESSAGE_MAP() |
169 return handled; | 47 return handled; |
170 } | 48 } |
171 | 49 |
172 void SearchBox::DidClearWindowObject(WebKit::WebFrame* frame) { | 50 void SearchBox::OnDetermineInstantSupport() { |
173 extensions_v8::SearchBoxExtension::DispatchOnWindowReady(frame); | 51 bool supports_instant = |
| 52 extensions_v8::SearchBoxExtension::DetermineInstantSupport(render_view()); |
| 53 Send(new ChromeViewHostMsg_SearchBoxInstantSupportDetermined( |
| 54 routing_id(), render_view()->GetPageId(), supports_instant)); |
174 } | 55 } |
175 | 56 |
176 void SearchBox::OnChange(const string16& query, | 57 void SearchBox::OnChange(const string16& query, |
177 bool verbatim, | 58 bool verbatim, |
178 size_t selection_start, | 59 size_t selection_start, |
179 size_t selection_end) { | 60 size_t selection_end) { |
| 61 if (query_ == query && verbatim_ == verbatim && |
| 62 selection_start_ == selection_start && selection_end_ == selection_end) |
| 63 return; |
| 64 |
180 query_ = query; | 65 query_ = query; |
181 verbatim_ = verbatim; | 66 verbatim_ = verbatim; |
182 selection_start_ = selection_start; | 67 selection_start_ = selection_start; |
183 selection_end_ = selection_end; | 68 selection_end_ = selection_end; |
184 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { | 69 extensions_v8::SearchBoxExtension::Change(render_view()); |
185 DVLOG(1) << render_view() << " OnChange"; | |
186 extensions_v8::SearchBoxExtension::DispatchChange( | |
187 render_view()->GetWebView()->mainFrame()); | |
188 } | |
189 } | 70 } |
190 | 71 |
191 void SearchBox::OnSubmit(const string16& query) { | 72 void SearchBox::OnSubmit(const string16& query) { |
192 query_ = query; | 73 query_ = query; |
193 verbatim_ = true; | 74 verbatim_ = true; |
194 selection_start_ = selection_end_ = query_.size(); | 75 selection_start_ = query_.size(); |
195 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { | 76 selection_end_ = query_.size(); |
196 DVLOG(1) << render_view() << " OnSubmit"; | 77 extensions_v8::SearchBoxExtension::Submit(render_view()); |
197 extensions_v8::SearchBoxExtension::DispatchSubmit( | |
198 render_view()->GetWebView()->mainFrame()); | |
199 } | |
200 Reset(); | 78 Reset(); |
201 } | 79 } |
202 | 80 |
203 void SearchBox::OnCancel(const string16& query) { | 81 void SearchBox::OnBlur(const string16& query) { |
204 query_ = query; | 82 query_ = query; |
205 verbatim_ = true; | 83 verbatim_ = true; |
206 selection_start_ = selection_end_ = query_.size(); | 84 selection_start_ = query_.size(); |
207 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { | 85 selection_end_ = query_.size(); |
208 DVLOG(1) << render_view() << " OnCancel"; | 86 extensions_v8::SearchBoxExtension::Blur(render_view()); |
209 extensions_v8::SearchBoxExtension::DispatchCancel( | |
210 render_view()->GetWebView()->mainFrame()); | |
211 } | |
212 Reset(); | 87 Reset(); |
213 } | 88 } |
214 | 89 |
215 void SearchBox::OnPopupResize(const gfx::Rect& bounds) { | 90 void SearchBox::OnPopupBounds(const gfx::Rect& bounds) { |
| 91 if (popup_bounds_ == bounds) |
| 92 return; |
| 93 |
216 popup_bounds_ = bounds; | 94 popup_bounds_ = bounds; |
217 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { | 95 extensions_v8::SearchBoxExtension::PopupBounds(render_view()); |
218 DVLOG(1) << render_view() << " OnPopupResize"; | |
219 extensions_v8::SearchBoxExtension::DispatchResize( | |
220 render_view()->GetWebView()->mainFrame()); | |
221 } | |
222 } | |
223 | |
224 void SearchBox::OnMarginChange(int margin, int width) { | |
225 start_margin_ = margin; | |
226 | |
227 // Override only the width parameter of the popup bounds. | |
228 popup_bounds_.set_width(width); | |
229 | |
230 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { | |
231 extensions_v8::SearchBoxExtension::DispatchMarginChange( | |
232 render_view()->GetWebView()->mainFrame()); | |
233 } | |
234 } | |
235 | |
236 void SearchBox::OnDetermineIfPageSupportsInstant() { | |
237 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { | |
238 bool result = extensions_v8::SearchBoxExtension::PageSupportsInstant( | |
239 render_view()->GetWebView()->mainFrame()); | |
240 DVLOG(1) << render_view() << " PageSupportsInstant: " << result; | |
241 render_view()->Send(new ChromeViewHostMsg_InstantSupportDetermined( | |
242 render_view()->GetRoutingID(), render_view()->GetPageId(), result)); | |
243 } | |
244 } | |
245 | |
246 void SearchBox::OnAutocompleteResults( | |
247 const std::vector<InstantAutocompleteResult>& results) { | |
248 results_base_ += autocomplete_results_.size(); | |
249 autocomplete_results_ = results; | |
250 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { | |
251 DVLOG(1) << render_view() << " OnAutocompleteResults"; | |
252 extensions_v8::SearchBoxExtension::DispatchAutocompleteResults( | |
253 render_view()->GetWebView()->mainFrame()); | |
254 } | |
255 } | |
256 | |
257 void SearchBox::OnUpOrDownKeyPressed(int count) { | |
258 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { | |
259 DVLOG(1) << render_view() << " OnKeyPress: " << count; | |
260 extensions_v8::SearchBoxExtension::DispatchUpOrDownKeyPress( | |
261 render_view()->GetWebView()->mainFrame(), count); | |
262 } | |
263 } | |
264 | |
265 void SearchBox::OnCancelSelection(const string16& query) { | |
266 // TODO(sreeram): crbug.com/176101 The state reset below are somewhat wrong. | |
267 query_ = query; | |
268 verbatim_ = true; | |
269 selection_start_ = selection_end_ = query_.size(); | |
270 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { | |
271 DVLOG(1) << render_view() << " OnKeyPress ESC"; | |
272 extensions_v8::SearchBoxExtension::DispatchEscKeyPress( | |
273 render_view()->GetWebView()->mainFrame()); | |
274 } | |
275 } | |
276 | |
277 void SearchBox::OnKeyCaptureChange(bool is_key_capture_enabled) { | |
278 if (is_key_capture_enabled != is_key_capture_enabled_ && | |
279 render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { | |
280 is_key_capture_enabled_ = is_key_capture_enabled; | |
281 DVLOG(1) << render_view() << " OnKeyCaptureChange"; | |
282 extensions_v8::SearchBoxExtension::DispatchKeyCaptureChange( | |
283 render_view()->GetWebView()->mainFrame()); | |
284 } | |
285 } | |
286 | |
287 void SearchBox::OnSetDisplayInstantResults(bool display_instant_results) { | |
288 display_instant_results_ = display_instant_results; | |
289 } | |
290 | |
291 void SearchBox::OnThemeChanged(const ThemeBackgroundInfo& theme_info) { | |
292 theme_info_ = theme_info; | |
293 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { | |
294 extensions_v8::SearchBoxExtension::DispatchThemeChange( | |
295 render_view()->GetWebView()->mainFrame()); | |
296 } | |
297 } | |
298 | |
299 void SearchBox::OnFontInformationReceived(const string16& omnibox_font, | |
300 size_t omnibox_font_size) { | |
301 omnibox_font_ = omnibox_font; | |
302 omnibox_font_size_ = omnibox_font_size; | |
303 } | |
304 | |
305 void SearchBox::OnGrantChromeSearchAccessFromOrigin(const GURL& origin_url) { | |
306 string16 chrome_search_scheme(ASCIIToUTF16(chrome::kChromeSearchScheme)); | |
307 WebKit::WebSecurityPolicy::addOriginAccessWhitelistEntry( | |
308 origin_url, | |
309 chrome_search_scheme, | |
310 ASCIIToUTF16(chrome::kChromeUIFaviconHost), | |
311 false); | |
312 WebKit::WebSecurityPolicy::addOriginAccessWhitelistEntry( | |
313 origin_url, | |
314 chrome_search_scheme, | |
315 ASCIIToUTF16(chrome::kChromeUIThemeHost), | |
316 false); | |
317 WebKit::WebSecurityPolicy::addOriginAccessWhitelistEntry( | |
318 origin_url, | |
319 chrome_search_scheme, | |
320 ASCIIToUTF16(chrome::kChromeUIThumbnailHost), | |
321 false); | |
322 } | 96 } |
323 | 97 |
324 double SearchBox::GetZoom() const { | 98 double SearchBox::GetZoom() const { |
325 WebKit::WebView* web_view = render_view()->GetWebView(); | 99 WebKit::WebView* web_view = render_view()->GetWebView(); |
326 if (web_view) { | 100 if (web_view) { |
327 double zoom = WebKit::WebView::zoomLevelToZoomFactor(web_view->zoomLevel()); | 101 double zoom = WebKit::WebView::zoomLevelToZoomFactor(web_view->zoomLevel()); |
328 if (zoom != 0) | 102 if (zoom != 0) |
329 return zoom; | 103 return zoom; |
330 } | 104 } |
331 return 1.0; | 105 return 1.0; |
332 } | 106 } |
333 | 107 |
334 void SearchBox::Reset() { | 108 void SearchBox::Reset() { |
335 query_.clear(); | 109 query_.clear(); |
336 verbatim_ = false; | 110 verbatim_ = false; |
337 selection_start_ = 0; | 111 selection_start_ = 0; |
338 selection_end_ = 0; | 112 selection_end_ = 0; |
339 results_base_ = 0; | |
340 popup_bounds_ = gfx::Rect(); | 113 popup_bounds_ = gfx::Rect(); |
341 start_margin_ = 0; | |
342 autocomplete_results_.clear(); | |
343 is_key_capture_enabled_ = false; | |
344 theme_info_ = ThemeBackgroundInfo(); | |
345 // Don't reset display_instant_results_ to prevent clearing it on committed | |
346 // results pages in extended mode. Otherwise resetting it is a no-op because | |
347 // a new loader is created when it changes; see crbug.com/164662. | |
348 // Also don't reset omnibox_font_ or omnibox_font_size_ since it never | |
349 // changes. | |
350 } | 114 } |
351 | |
352 void SearchBox::OnMostVisitedChanged( | |
353 const std::vector<MostVisitedItem>& items) { | |
354 most_visited_items_ = items; | |
355 | |
356 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) { | |
357 extensions_v8::SearchBoxExtension::DispatchMostVisitedChanged( | |
358 render_view()->GetWebView()->mainFrame()); | |
359 } | |
360 } | |
361 | |
362 const std::vector<MostVisitedItem>& SearchBox::GetMostVisitedItems() { | |
363 return most_visited_items_; | |
364 } | |
365 | |
366 int SearchBox::UrlToRestrictedId(string16 url) { | |
367 if (url_to_restricted_id_map_[url]) | |
368 return url_to_restricted_id_map_[url]; | |
369 | |
370 last_restricted_id_++; | |
371 url_to_restricted_id_map_[url] = last_restricted_id_; | |
372 restricted_id_to_url_map_[last_restricted_id_] = url; | |
373 | |
374 return last_restricted_id_; | |
375 } | |
376 | |
377 string16 SearchBox::RestrictedIdToURL(int id) { | |
378 return restricted_id_to_url_map_[id]; | |
379 } | |
380 | |
381 string16 SearchBox::GenerateThumbnailUrl(int id) { | |
382 std::ostringstream ostr; | |
383 ostr << kThumbnailUrlPrefix << id; | |
384 GURL url = GURL(ostr.str()); | |
385 return UTF8ToUTF16(url.spec()); | |
386 } | |
387 | |
388 string16 SearchBox::GenerateFaviconUrl(int id) { | |
389 std::ostringstream ostr; | |
390 ostr << kFaviconUrlPrefix << id; | |
391 GURL url = GURL(ostr.str()); | |
392 return UTF8ToUTF16(url.spec()); | |
393 } | |
OLD | NEW |