summaryrefslogtreecommitdiffstats
path: root/chrome/browser/instant/instant_loader.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/instant/instant_loader.cc')
-rw-r--r--chrome/browser/instant/instant_loader.cc287
1 files changed, 100 insertions, 187 deletions
diff --git a/chrome/browser/instant/instant_loader.cc b/chrome/browser/instant/instant_loader.cc
index 3c561b3..7147b7c 100644
--- a/chrome/browser/instant/instant_loader.cc
+++ b/chrome/browser/instant/instant_loader.cc
@@ -7,8 +7,10 @@
#include <algorithm>
#include <utility>
+#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/string_number_conversions.h"
+#include "base/timer.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/favicon_service.h"
@@ -24,6 +26,7 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
@@ -34,104 +37,19 @@
#include "ipc/ipc_message.h"
namespace {
-
-// Script sent as the user is typing and the provider supports instant.
-// Params:
-// . the text the user typed.
-// TODO: add support for the 2nd and 3rd params.
-const char kUserInputScript[] =
- "if (window.chrome.userInput) window.chrome.userInput(\"$1\", 0, 0);";
-
-// Script sent when the page is committed and the provider supports instant.
-// Params:
-// . the text the user typed.
-// . boolean indicating if the user pressed enter to accept the text.
-const char kUserDoneScript[] =
- "if (window.chrome.userWantsQuery) "
- "window.chrome.userWantsQuery(\"$1\", $2);";
-
-// Script sent when the bounds of the omnibox changes and the provider supports
-// instant. The params are the bounds relative to the origin of the preview
-// (x, y, width, height).
-const char kSetOmniboxBoundsScript[] =
- "if (window.chrome.setDropdownDimensions) "
- "window.chrome.setDropdownDimensions($1, $2, $3, $4);";
-
-// Script sent to see if the page really supports instant.
-const char kSupportsInstantScript[] =
- "if (window.chrome.setDropdownDimensions) true; else false;";
-
// Number of ms to delay before updating the omnibox bounds. This is a bit long
// as updating the bounds ends up being quite expensive.
const int kUpdateBoundsDelayMS = 500;
-
-// Escapes quotes in the |text| so that it be passed to JavaScript as a quoted
-// string.
-string16 EscapeUserText(const string16& text) {
- string16 escaped_text(text);
- ReplaceSubstringsAfterOffset(&escaped_text, 0L, ASCIIToUTF16("\""),
- ASCIIToUTF16("\\\""));
- return escaped_text;
-}
-
-// Sends the script for when the user commits the preview. |pressed_enter| is
-// true if the user pressed enter to commit.
-void SendDoneScript(TabContents* tab_contents,
- const string16& text,
- bool pressed_enter) {
- std::vector<string16> params;
- params.push_back(EscapeUserText(text));
- params.push_back(pressed_enter ? ASCIIToUTF16("true") :
- ASCIIToUTF16("false"));
- string16 script = ReplaceStringPlaceholders(ASCIIToUTF16(kUserDoneScript),
- params,
- NULL);
- tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
- std::wstring(),
- UTF16ToWide(script));
-}
-
-// Sends the user input script to |tab_contents|. |text| is the text the user
-// input into the omnibox.
-void SendUserInputScript(TabContents* tab_contents, const string16& text) {
- string16 script = ReplaceStringPlaceholders(ASCIIToUTF16(kUserInputScript),
- EscapeUserText(text),
- NULL);
- tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
- std::wstring(),
- UTF16ToWide(script));
-}
-
-// Sends the script for setting the bounds of the omnibox to |tab_contents|.
-void SendOmniboxBoundsScript(TabContents* tab_contents,
- const gfx::Rect& bounds) {
- std::vector<string16> bounds_vector;
- bounds_vector.push_back(base::IntToString16(bounds.x()));
- bounds_vector.push_back(base::IntToString16(bounds.y()));
- bounds_vector.push_back(base::IntToString16(bounds.width()));
- bounds_vector.push_back(base::IntToString16(bounds.height()));
- string16 script = ReplaceStringPlaceholders(
- ASCIIToUTF16(kSetOmniboxBoundsScript),
- bounds_vector,
- NULL);
- tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
- std::wstring(),
- UTF16ToWide(script));
-}
-
} // namespace
-// FrameLoadObserver is responsible for waiting for the TabContents to finish
-// loading and when done sending the necessary script down to the page.
+// FrameLoadObserver is responsible for determining if the page supports
+// instant after it has loaded.
class InstantLoader::FrameLoadObserver : public NotificationObserver {
public:
- FrameLoadObserver(InstantLoader* loader, const string16& text)
- : loader_(loader),
- tab_contents_(loader->preview_contents()),
- unique_id_(tab_contents_->controller().pending_entry()->unique_id()),
+ FrameLoadObserver(TabContents* tab_contents, const string16& text)
+ : tab_contents_(tab_contents),
text_(text),
- initial_text_(text),
- execute_js_id_(0) {
+ unique_id_(tab_contents_->controller().pending_entry()->unique_id()) {
registrar_.Add(this, NotificationType::LOAD_COMPLETED_MAIN_FRAME,
Source<TabContents>(tab_contents_));
}
@@ -152,29 +70,10 @@ class InstantLoader::FrameLoadObserver : public NotificationObserver {
active_entry->unique_id() != unique_id_) {
return;
}
-
- DetermineIfPageSupportsInstant();
+ tab_contents_->render_view_host()->DetermineIfPageSupportsInstant(
+ text_);
break;
}
-
- case NotificationType::EXECUTE_JAVASCRIPT_RESULT: {
- typedef std::pair<int, Value*> ExecuteDetailType;
- ExecuteDetailType* result =
- (static_cast<Details<ExecuteDetailType > >(details)).ptr();
- if (result->first != execute_js_id_)
- return;
-
- DCHECK(loader_);
- bool bool_result;
- if (!result->second || !result->second->IsType(Value::TYPE_BOOLEAN) ||
- !result->second->GetAsBoolean(&bool_result) || !bool_result) {
- DoesntSupportInstant();
- return;
- }
- SupportsInstant();
- return;
- }
-
default:
NOTREACHED();
break;
@@ -182,66 +81,18 @@ class InstantLoader::FrameLoadObserver : public NotificationObserver {
}
private:
- // Executes the javascript to determine if the page supports script. The
- // results are passed back to us by way of NotificationObserver.
- void DetermineIfPageSupportsInstant() {
- DCHECK_EQ(0, execute_js_id_);
-
- RenderViewHost* rvh = tab_contents_->render_view_host();
- registrar_.Add(this, NotificationType::EXECUTE_JAVASCRIPT_RESULT,
- Source<RenderViewHost>(rvh));
- execute_js_id_ = rvh->ExecuteJavascriptInWebFrameNotifyResult(
- string16(),
- ASCIIToUTF16(kSupportsInstantScript));
- }
-
- // Invoked when we determine the page doesn't really support instant.
- void DoesntSupportInstant() {
- DCHECK(loader_);
-
- loader_->PageDoesntSupportInstant(text_ != initial_text_);
-
- // WARNING: we've been deleted.
- }
-
- // Invoked when we determine the page really supports instant.
- void SupportsInstant() {
- DCHECK(loader_);
-
- gfx::Rect bounds = loader_->GetOmniboxBoundsInTermsOfPreview();
- loader_->last_omnibox_bounds_ = loader_->omnibox_bounds_;
- if (!bounds.IsEmpty())
- SendOmniboxBoundsScript(tab_contents_, bounds);
-
- SendUserInputScript(tab_contents_, text_);
-
- loader_->PageFinishedLoading();
-
- // WARNING: we've been deleted.
- }
-
- // InstantLoader that created us.
- InstantLoader* loader_;
-
// The TabContents we're listening for changes on.
TabContents* tab_contents_;
- // unique_id of the NavigationEntry we're waiting on.
- const int unique_id_;
-
// Text to send down to the page.
string16 text_;
- // Initial text supplied to constructor.
- const string16 initial_text_;
+ // unique_id of the NavigationEntry we're waiting on.
+ const int unique_id_;
// Registers and unregisters us for notifications.
NotificationRegistrar registrar_;
- // ID of the javascript that was executed to determine if the page supports
- // instant.
- int execute_js_id_;
-
DISALLOW_COPY_AND_ASSIGN(FrameLoadObserver);
};
@@ -274,11 +125,13 @@ class InstantLoader::TabContentsDelegateImpl : public TabContentsDelegate {
: loader_(loader),
installed_paint_observer_(false),
waiting_for_new_page_(true),
- is_mouse_down_from_activate_(false) {
+ is_mouse_down_from_activate_(false),
+ user_typed_before_load_(false) {
}
// Invoked prior to loading a new URL.
void PrepareForNewLoad() {
+ user_typed_before_load_ = false;
waiting_for_new_page_ = true;
add_page_vector_.clear();
}
@@ -294,6 +147,8 @@ class InstantLoader::TabContentsDelegateImpl : public TabContentsDelegate {
return is_mouse_down_from_activate_;
}
+ void set_user_typed_before_load() { user_typed_before_load_ = true; }
+
// Commits the currently buffered history.
void CommitHistory() {
TabContents* tab = loader_->preview_contents();
@@ -353,7 +208,7 @@ class InstantLoader::TabContentsDelegateImpl : public TabContentsDelegate {
virtual bool IsPopup(const TabContents* source) const {
return false;
}
- virtual bool ShouldFocusConstrainedWindow(TabContents* source) {
+ virtual bool ShouldFocusConstrainedWindow() {
// Return false so that constrained windows are not initially focused. If
// we did otherwise the preview would prematurely get committed when focus
// goes to the constrained window.
@@ -460,12 +315,33 @@ class InstantLoader::TabContentsDelegateImpl : public TabContentsDelegate {
virtual void UpdatePreferredSize(const gfx::Size& pref_size) {}
virtual void ContentTypeChanged(TabContents* source) {}
- virtual void OnSetSuggestResult(int32 page_id, const std::string& result) {
+ virtual void OnSetSuggestions(int32 page_id,
+ const std::vector<std::string>& suggestions) {
TabContents* source = loader_->preview_contents();
+ if (!source->controller().GetActiveEntry() ||
+ page_id != source->controller().GetActiveEntry()->page_id())
+ return;
+
// TODO: only allow for default search provider.
- if (source->controller().GetActiveEntry() &&
- page_id == source->controller().GetActiveEntry()->page_id()) {
- loader_->SetCompleteSuggestedText(UTF8ToUTF16(result));
+ // TODO(sky): Handle multiple suggestions.
+ if (suggestions.empty())
+ loader_->SetCompleteSuggestedText(string16());
+ else
+ loader_->SetCompleteSuggestedText(UTF8ToUTF16(suggestions[0]));
+ }
+
+ virtual void OnInstantSupportDetermined(int32 page_id, bool result) {
+ TabContents* source = loader_->preview_contents();
+ if (!source->controller().GetActiveEntry() ||
+ page_id != source->controller().GetActiveEntry()->page_id())
+ return;
+
+ if (result) {
+ gfx::Rect bounds = loader_->GetOmniboxBoundsInTermsOfPreview();
+ loader_->last_omnibox_bounds_ = loader_->omnibox_bounds_;
+ loader_->PageFinishedLoading();
+ } else {
+ loader_->PageDoesntSupportInstant(user_typed_before_load_);
}
}
@@ -496,9 +372,12 @@ class InstantLoader::TabContentsDelegateImpl : public TabContentsDelegate {
// NEW_PAGE navigation we don't add history items to add_page_vector_.
bool waiting_for_new_page_;
- // Returns true if the mouse is down from an activate.
+ // True if the mouse is down from an activate.
bool is_mouse_down_from_activate_;
+ // True if the user typed in the search box before the page loaded.
+ bool user_typed_before_load_;
+
DISALLOW_COPY_AND_ASSIGN(TabContentsDelegateImpl);
};
@@ -563,23 +442,40 @@ void InstantLoader::Update(TabContents* tab_contents,
if (is_waiting_for_load()) {
// The page hasn't loaded yet. We'll send the script down when it does.
frame_load_observer_->set_text(user_text_);
+ preview_tab_contents_delegate_->set_user_typed_before_load();
return;
}
- SendUserInputScript(preview_contents_.get(), user_text_);
- if (complete_suggested_text_.size() > user_text_.size() &&
- !complete_suggested_text_.compare(0, user_text_.size(), user_text_)) {
+ preview_contents_->render_view_host()->SearchBoxChange(
+ user_text_, false, 0, 0);
+
+ string16 complete_suggested_text_lower = l10n_util::ToLower(
+ complete_suggested_text_);
+ string16 user_text_lower = l10n_util::ToLower(user_text_);
+ if (complete_suggested_text_lower.size() > user_text_lower.size() &&
+ !complete_suggested_text_lower.compare(0, user_text_lower.size(),
+ user_text_lower)) {
*suggested_text = complete_suggested_text_.substr(user_text_.size());
}
} else {
// Load the instant URL. We don't reflect the url we load in url() as
// callers expect that we're loading the URL they tell us to.
+ //
+ // This uses an empty string for the replacement text as the url doesn't
+ // really have the search params, but we need to use the replace
+ // functionality so that embeded tags (like {google:baseURL}) are escaped
+ // correctly.
+ // TODO(sky): having to use a replaceable url is a bit of a hack here.
GURL instant_url(
template_url->instant_url()->ReplaceSearchTerms(
- *template_url, UTF16ToWideHack(user_text), -1, std::wstring()));
+ *template_url, std::wstring(), -1, std::wstring()));
+ CommandLine* cl = CommandLine::ForCurrentProcess();
+ if (cl->HasSwitch(switches::kInstantURL))
+ instant_url = GURL(cl->GetSwitchValueASCII(switches::kInstantURL));
initial_instant_url_ = url;
preview_contents_->controller().LoadURL(
instant_url, GURL(), transition_type);
- frame_load_observer_.reset(new FrameLoadObserver(this, user_text_));
+ frame_load_observer_.reset(
+ new FrameLoadObserver(preview_contents(), user_text_));
}
} else {
DCHECK(template_url_id_ == 0);
@@ -619,9 +515,11 @@ TabContents* InstantLoader::ReleasePreviewContents(InstantCommitType type) {
DCHECK(type == INSTANT_COMMIT_DESTROY || !frame_load_observer_.get());
if (type != INSTANT_COMMIT_DESTROY && is_showing_instant()) {
- SendDoneScript(preview_contents_.get(),
- user_text_,
- type == INSTANT_COMMIT_PRESSED_ENTER);
+ if (type == INSTANT_COMMIT_FOCUS_LOST)
+ preview_contents_->render_view_host()->SearchBoxCancel();
+ else
+ preview_contents_->render_view_host()->SearchBoxSubmit(
+ user_text_, type == INSTANT_COMMIT_PRESSED_ENTER);
}
omnibox_bounds_ = gfx::Rect();
last_omnibox_bounds_ = gfx::Rect();
@@ -678,8 +576,12 @@ void InstantLoader::SetCompleteSuggestedText(
if (complete_suggested_text == complete_suggested_text_)
return;
- if (user_text_.compare(0, user_text_.size(), complete_suggested_text,
- 0, user_text_.size())) {
+ string16 user_text_lower = l10n_util::ToLower(user_text_);
+ string16 complete_suggested_text_lower = l10n_util::ToLower(
+ complete_suggested_text);
+ if (user_text_lower.compare(0, user_text_lower.size(),
+ complete_suggested_text_lower,
+ 0, user_text_lower.size())) {
// The user text no longer contains the suggested text, ignore it.
complete_suggested_text_.clear();
delegate_->SetSuggestedTextFor(this, string16());
@@ -718,15 +620,26 @@ void InstantLoader::PageFinishedLoading() {
// date by the time we show it.
}
+// TODO(tonyg): This method only fires when the omnibox bounds change. It also
+// needs to fire when the preview bounds change (e.g. open/close info bar).
gfx::Rect InstantLoader::GetOmniboxBoundsInTermsOfPreview() {
- if (omnibox_bounds_.IsEmpty())
- return omnibox_bounds_;
-
gfx::Rect preview_bounds(delegate_->GetInstantBounds());
- return gfx::Rect(omnibox_bounds_.x() - preview_bounds.x(),
- omnibox_bounds_.y() - preview_bounds.y(),
- omnibox_bounds_.width(),
- omnibox_bounds_.height());
+ gfx::Rect intersection(omnibox_bounds_.Intersect(preview_bounds));
+
+ // Translate into window's coordinates.
+ if (!intersection.IsEmpty()) {
+ intersection.Offset(-preview_bounds.origin().x(),
+ -preview_bounds.origin().y());
+ }
+
+ // In the current Chrome UI, these must always be true so they sanity check
+ // the above operations. In a future UI, these may be removed or adjusted.
+ DCHECK_EQ(0, intersection.y());
+ DCHECK_LE(0, intersection.x());
+ DCHECK_LE(0, intersection.width());
+ DCHECK_LE(0, intersection.height());
+
+ return intersection;
}
void InstantLoader::PageDoesntSupportInstant(bool needs_reload) {
@@ -749,7 +662,7 @@ void InstantLoader::ProcessBoundsChange() {
last_omnibox_bounds_ = omnibox_bounds_;
if (preview_contents_.get() && is_showing_instant() &&
!is_waiting_for_load()) {
- SendOmniboxBoundsScript(preview_contents_.get(),
- GetOmniboxBoundsInTermsOfPreview());
+ preview_contents_->render_view_host()->SearchBoxResize(
+ GetOmniboxBoundsInTermsOfPreview());
}
}