Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(341)

Side by Side Diff: chrome/browser/instant/instant_controller_impl.cc

Issue 12386019: Instant: Use only one hidden WebContents per profile. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/instant/instant_controller_impl.h"
6
7 #include "base/string_util.h"
8 #include "base/stringprintf.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/autocomplete/autocomplete_match.h"
11 #include "chrome/browser/history/history_service.h"
12 #include "chrome/browser/history/history_service_factory.h"
13 #include "chrome/browser/instant/instant_controller_utils.h"
14 #include "chrome/browser/instant/instant_overlay.h"
15 #include "chrome/browser/instant/instant_overlay_model.h"
16 #include "chrome/browser/instant/instant_preloader.h"
17 #include "chrome/browser/instant/instant_service.h"
18 #include "chrome/browser/instant/instant_service_factory.h"
19 #include "chrome/browser/ui/browser_instant_controller.h"
20 #include "chrome/common/chrome_notification_types.h"
21 #include "content/public/browser/navigation_entry.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/web_contents.h"
24
25 namespace {
26
27 // An artificial delay (in milliseconds) we introduce before telling the Instant
28 // page about the new omnibox bounds, in cases where the bounds shrink. This is
29 // to avoid the page jumping up/down very fast in response to bounds changes.
30 const int kUpdateBoundsDelayMS = 1000;
31
32 } // namespace
33
34 InstantControllerImpl::InstantControllerImpl(
35 chrome::BrowserInstantController* browser,
36 Profile* profile)
37 : browser_(browser),
38 service_(InstantServiceFactory::GetForProfile(profile)),
39 last_verbatim_(false),
40 last_transition_type_(content::PAGE_TRANSITION_LINK) {
41 service_->AddObserver(this);
42 model_.reset(new InstantOverlayModel(service_));
43 }
44
45 InstantControllerImpl::~InstantControllerImpl() {
46 service_->RemoveObserver(this);
47 }
48
49 bool InstantControllerImpl::Update(const AutocompleteMatch& match,
50 const string16& user_text,
51 const string16& full_text,
52 size_t selection_start,
53 size_t selection_end,
54 bool verbatim,
55 bool /* user_input_in_progress */,
56 bool omnibox_popup_is_open,
57 bool /* escape_pressed */,
58 bool is_keyword_search) {
59 // The overlay is being clicked and will commit soon. Don't change anything.
60 // TODO(sreeram): Add a browser test for this.
61 if (overlay_ && overlay_->is_pointer_down_from_activate())
62 return false;
63
64 // No overlay for URLs and keyword searches or if the user isn't typing.
65 if (!AutocompleteMatch::IsSearchType(match.type) || is_keyword_search ||
66 !omnibox_popup_is_open || user_text.empty() || full_text.empty()) {
67 HideOverlay();
68 return false;
69 }
70
71 if (!overlay_) {
72 // If we don't have a valid (Instant-supporting) web contents ready, bail.
73 if (!service_->preloader()->supports_instant())
74 return false;
75
76 overlay_.reset(new InstantOverlay(
77 this, service_, service_->preloader()->ReleaseContents()));
78 }
79
80 // Query is verbatim not only when |verbatim| is true (which indicates that
81 // the user pressed Delete/Backspace), but also when there's any selection
82 // (including inline autocompletion) or if the cursor is not at the end.
83 verbatim = verbatim || selection_start != selection_end ||
84 selection_start != full_text.size();
85
86 last_omnibox_text_ = full_text;
87 last_verbatim_ = verbatim;
88 last_transition_type_ = match.transition;
89 url_for_history_ = match.destination_url;
90
91 service_->LogDebugEvent(base::StringPrintf("%p Update '%s' %s [%d,%d]",
92 this,
93 UTF16ToUTF8(last_omnibox_text_).c_str(),
94 verbatim ? "verbatim" : "psychic",
95 static_cast<int>(selection_start),
96 static_cast<int>(selection_end)));
97
98 overlay_->page()->Change(full_text, verbatim, selection_start, selection_end);
99
100 content::NotificationService::current()->Notify(
101 chrome::NOTIFICATION_INSTANT_UPDATED,
102 content::NotificationService::AllSources(),
103 content::NotificationService::NoDetails());
104
105 return true;
106 }
107
108 void InstantControllerImpl::HandleAutocompleteResults(
109 const std::vector<AutocompleteProvider*>& /* providers */) {
110 }
111
112 bool InstantControllerImpl::OnUpOrDownKeyPressed(int /* count */) {
113 return false;
114 }
115
116 void InstantControllerImpl::OnCancel(const AutocompleteMatch& /* match */,
117 const string16& /* full_text */) {
118 }
119
120 bool InstantControllerImpl::IsOverlayingSearchResults() const {
121 return model_->contents() != NULL;
122 }
123
124 content::WebContents* InstantControllerImpl::GetOverlayContents() const {
125 return overlay_ ? overlay_->contents() : NULL;
126 }
127
128 const InstantOverlayModel* InstantControllerImpl::model() const {
129 return model_.get();
130 }
131
132 void InstantControllerImpl::AddOverlayModelObserver(
133 InstantOverlayModelObserver* observer) {
134 model_->AddObserver(observer);
135 }
136
137 void InstantControllerImpl::RemoveOverlayModelObserver(
138 InstantOverlayModelObserver* observer) {
139 model_->RemoveObserver(observer);
140 }
141
142 bool InstantControllerImpl::CommitIfPossible(InstantCommitType type) {
143 if (!IsOverlayingSearchResults())
144 return false;
145
146 service_->LogDebugEvent(base::StringPrintf("%p CommitIfPossible '%s' %s",
147 this,
148 UTF16ToUTF8(last_omnibox_text_).c_str(),
149 InstantControllerUtils::CommitTypeToString(type).c_str()));
150
151 if (type == INSTANT_COMMIT_FOCUS_LOST)
152 overlay_->page()->Blur(last_omnibox_text_);
153 else if (type != INSTANT_COMMIT_NAVIGATED)
154 overlay_->page()->Submit(last_omnibox_text_);
155
156 HistoryService* history = HistoryServiceFactory::GetForProfile(
157 service_->profile(), Profile::EXPLICIT_ACCESS);
158 if (history) {
159 history->AddPage(url_for_history_, base::Time::Now(), NULL, 0, GURL(),
160 history::RedirectList(), last_transition_type_,
161 history::SOURCE_BROWSED, false);
162
163 if (overlay_->page()->navigated_after_change() ||
164 type == INSTANT_COMMIT_NAVIGATED) {
165 content::NavigationEntry* entry =
166 overlay_->contents()->GetController().GetLastCommittedEntry();
167 history->AddPage(entry->GetVirtualURL(), base::Time::Now(),
168 history::SOURCE_BROWSED);
169 history->SetPageTitle(entry->GetVirtualURL(),
170 entry->GetTitleForDisplay(""));
171 }
172 }
173
174 scoped_ptr<content::WebContents> contents = overlay_->ReleaseContents();
175
176 if (type == INSTANT_COMMIT_PRESSED_ALT_ENTER) {
177 contents->GetController().PruneAllButActive();
178 } else {
179 content::WebContents* active_tab = browser_->GetActiveWebContents();
180 contents->GetController().CopyStateFromAndPrune(
181 &active_tab->GetController());
182 }
183
184 browser_->CommitInstant(contents.Pass(), last_transition_type_,
185 type == INSTANT_COMMIT_PRESSED_ALT_ENTER);
186
187 HideOverlay();
188
189 service_->LogDebugEvent(base::StringPrintf("%p Committed", this));
190
191 return true;
192 }
193
194 scoped_ptr<content::WebContents> InstantControllerImpl::ReleaseNTPContents() {
195 return scoped_ptr<content::WebContents>();
196 }
197
198 // TODO(tonyg): This method only fires when the popup bounds change. It also
199 // needs to fire when the overlay bounds change (e.g.: open/close info bar).
200 void InstantControllerImpl::SetPopupBounds(const gfx::Rect& bounds) {
201 if (popup_bounds_ == bounds)
202 return;
203
204 popup_bounds_ = bounds;
205
206 if (bounds.height() > last_popup_bounds_.height()) {
207 update_bounds_timer_.Stop();
208 SendPopupBoundsToPage();
209 } else if (!update_bounds_timer_.IsRunning()) {
210 update_bounds_timer_.Start(FROM_HERE,
211 base::TimeDelta::FromMilliseconds(kUpdateBoundsDelayMS),
212 this, &InstantControllerImpl::SendPopupBoundsToPage);
213 }
214 }
215
216 void InstantControllerImpl::SetOmniboxBounds(const gfx::Rect& /* bounds */) {
217 }
218
219 void InstantControllerImpl::OmniboxFocusChanged(
220 OmniboxFocusState state,
221 OmniboxFocusChangeReason reason,
222 gfx::NativeView view_gaining_focus) {
223
224 service_->LogDebugEvent(base::StringPrintf("%p OmniboxFocus %s due to %s",
225 this,
226 InstantControllerUtils::FocusStateToString(state).c_str(),
227 InstantControllerUtils::FocusChangeReasonToString(reason).c_str()));
228
229 if (state == OMNIBOX_FOCUS_NONE) {
230 // Don't do anything if we don't have an overlay or if the overlay isn't
231 // showing or if we are in the midst of committing the overlay.
232 if (!overlay_ || !IsOverlayingSearchResults() || !overlay_->contents())
233 return;
234
235 view_gaining_focus =
236 InstantControllerUtils::GetViewGainingFocus(view_gaining_focus);
237 if (InstantControllerUtils::IsViewInContents(view_gaining_focus,
238 overlay_->contents()))
239 CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST);
240 else
241 HideOverlay();
242 } else {
243 service_->preloader()->InitContents();
244 }
245 }
246
247 void InstantControllerImpl::TabDeactivated(
248 content::WebContents* /* contents */) {
249 if (overlay_ && overlay_->contents())
250 HideOverlay();
251 }
252
253 void InstantControllerImpl::SearchModeChanged(
254 const chrome::search::Mode& /* old_mode */,
255 const chrome::search::Mode& /* new_mode */) {
256 }
257
258 void InstantControllerImpl::ActiveTabChanged() {
259 }
260
261 void InstantControllerImpl::SwappedOverlayContents() {
262 if (IsOverlayingSearchResults()) {
263 model_->SetOverlayState(overlay_->contents(),
264 model_->height(), model_->height_units());
265 }
266 }
267
268 void InstantControllerImpl::FocusedOverlayContents() {
269 if (IsOverlayingSearchResults())
270 browser_->InstantOverlayFocused();
271 }
272
273 void InstantControllerImpl::RenderViewGone(
274 const content::WebContents* /* contents */) {
275 HideOverlay();
276 }
277
278 void InstantControllerImpl::InitSearchBox(
279 const content::WebContents* /* contents */) {
280 }
281
282 void InstantControllerImpl::InstantSupportDetermined(
283 const content::WebContents* /* contents */) {
284 if (!overlay_->page()->supports_instant())
285 HideOverlay();
286 service_->InstantSupportDetermined();
287 }
288
289 void InstantControllerImpl::SetSuggestion(
290 const content::WebContents* /* contents */,
291 const InstantSuggestion& suggestion) {
292 string16 text = suggestion.text;
293
294 if (StartsWith(text, last_omnibox_text_, true)) {
295 text.erase(0, last_omnibox_text_.size());
296 } else if (!InstantControllerUtils::NormalizeAndStripPrefix(
297 &text, last_omnibox_text_)) {
298 text.clear();
299 }
300
301 if (last_verbatim_)
302 text.clear();
303
304 if (!text.empty()) {
305 service_->LogDebugEvent(base::StringPrintf("%p SetSuggestion '%s'",
306 this,
307 UTF16ToUTF8(text).c_str()));
308 browser_->SetInstantSuggestion(InstantSuggestion(
309 text, INSTANT_COMPLETE_NOW, INSTANT_SUGGESTION_SEARCH));
310 }
311
312 model_->SetOverlayState(overlay_->contents(), 100, INSTANT_SIZE_PERCENT);
313 }
314
315 void InstantControllerImpl::NavigateToURL(
316 const content::WebContents* /* contents */,
317 const GURL& /* url */,
318 content::PageTransition /* transition */,
319 WindowOpenDisposition /* disposition */) {
320 }
321
322 void InstantControllerImpl::ShowOverlay(
323 const content::WebContents* /* contents */,
324 int /* height */,
325 InstantSizeUnits /* height_units */) {
326 }
327
328 void InstantControllerImpl::SetFocusState(
329 const content::WebContents* /* contents */,
330 OmniboxFocusState /* focus_state */) {
331 }
332
333 void InstantControllerImpl::DeleteMostVisitedItem(
334 const content::WebContents* /* contents */,
335 const GURL& /* url */) {
336 }
337
338 void InstantControllerImpl::UndoMostVisitedItemDeletion(
339 const content::WebContents* /* contents */,
340 const GURL& /* url */) {
341 }
342
343 void InstantControllerImpl::UndoAllMostVisitedItemDeletions(
344 const content::WebContents* /* contents */) {
345 }
346
347 void InstantControllerImpl::InstantStatusChanged() {
348 HideOverlay();
349 }
350
351 void InstantControllerImpl::ThemeInfoChanged() {
352 }
353
354 void InstantControllerImpl::MostVisitedItemsChanged() {
355 }
356
357 void InstantControllerImpl::HideOverlay() {
358 model_->SetOverlayState(NULL, 0, INSTANT_SIZE_PIXELS);
359 last_popup_bounds_ = gfx::Rect();
360 if (overlay_) {
361 overlay_->ReleaseContents();
362 MessageLoop::current()->DeleteSoon(FROM_HERE, overlay_.release());
363 }
364 }
365
366 void InstantControllerImpl::SendPopupBoundsToPage() {
367 if (!overlay_ || last_popup_bounds_ == popup_bounds_ ||
368 overlay_->is_pointer_down_from_activate())
369 return;
370
371 last_popup_bounds_ = popup_bounds_;
372
373 gfx::Rect overlay_bounds = browser_->GetInstantBounds();
374 gfx::Rect intersection = gfx::IntersectRects(popup_bounds_, overlay_bounds);
375
376 // Translate into window coordinates.
377 if (!intersection.IsEmpty()) {
378 intersection.Offset(-overlay_bounds.origin().x(),
379 -overlay_bounds.origin().y());
380 }
381
382 // In the current Chrome UI, these must always be true so they sanity check
383 // the above operations. In a future UI, these may be removed or adjusted.
384 // There is no point in sanity-checking intersection.y() because the omnibox
385 // can be placed anywhere vertically relative to the overlay (for example, in
386 // Mac fullscreen mode, the omnibox is fully enclosed by the overlay bounds).
387 DCHECK_LE(0, intersection.x());
388 DCHECK_LE(0, intersection.width());
389 DCHECK_LE(0, intersection.height());
390
391 overlay_->page()->PopupBounds(intersection);
392 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698