summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsuzhe@google.com <suzhe@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-13 00:30:18 +0000
committersuzhe@google.com <suzhe@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-13 00:30:18 +0000
commit28ea1c9ba0131ea88ae51c8487477e31c11ad8c6 (patch)
tree0f2ba7a91f49fb5f0169655e13409d66159a20f0
parent883025fbdea24cd612344a6953b9ddac49dcc0eb (diff)
downloadchromium_src-28ea1c9ba0131ea88ae51c8487477e31c11ad8c6.zip
chromium_src-28ea1c9ba0131ea88ae51c8487477e31c11ad8c6.tar.gz
chromium_src-28ea1c9ba0131ea88ae51c8487477e31c11ad8c6.tar.bz2
Fix several omnibox issues related to keyword mode and IME support.
This CL contains following changes to omnibox code: 1. Make sure |keyword_ui_state_| is always updated correctly, i.e. it should always be KEYWORD when keyword UI is visible. 2. Make sure |keyword_ui_state_| will never be changed during IME composition. 3. Make sure OnInlineAutocompleteTextMaybeChanged() will only be called when inline autocomplete suggest is changed. This CL fixes following bugs. Old fix for bug 2720 and 3798 has been removed. BUG=2720 BUG=3798 BUG=39947 BUG=62426 TEST=See bug reports. Review URL: http://codereview.chromium.org/6131005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71268 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit.cc85
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit.h7
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_unittest.cc1
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view.h3
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc21
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_gtk.h2
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_mac.h6
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_mac.mm40
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_win.cc98
-rw-r--r--chrome/browser/autocomplete/autocomplete_edit_view_win.h12
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_model.cc5
-rw-r--r--chrome/browser/autocomplete/autocomplete_popup_model.h3
-rw-r--r--chrome/browser/autocomplete/keyword_provider.cc18
-rw-r--r--chrome/browser/autocomplete/keyword_provider.h11
14 files changed, 147 insertions, 165 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc
index f08a2e4..5bf0c21 100644
--- a/chrome/browser/autocomplete/autocomplete_edit.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit.cc
@@ -308,7 +308,8 @@ void AutocompleteEditModel::StartAutocomplete(
popup_->StartAutocomplete(user_text_, GetDesiredTLD(),
prevent_inline_autocomplete || just_deleted_text_ ||
(has_selected_text && inline_autocomplete_text_.empty()) ||
- (paste_state_ != NONE), keyword_ui_state_ == KEYWORD);
+ (paste_state_ != NONE), keyword_ui_state_ == KEYWORD,
+ keyword_ui_state_ != NO_KEYWORD);
}
bool AutocompleteEditModel::CanPasteAndGo(const std::wstring& text) const {
@@ -568,11 +569,6 @@ void AutocompleteEditModel::OnUpOrDownKeyPressed(int count) {
// normally.
popup_->Move(count);
}
-
- // NOTE: We need to reset the keyword_ui_state_ after the popup updates, since
- // Move() will eventually call back to OnPopupDataChanged(), which needs to
- // save off the current keyword_ui_state_.
- keyword_ui_state_ = NORMAL;
}
void AutocompleteEditModel::OnPopupDataChanged(
@@ -580,6 +576,8 @@ void AutocompleteEditModel::OnPopupDataChanged(
GURL* destination_for_temporary_text_change,
const std::wstring& keyword,
bool is_keyword_hint) {
+ KeywordUIState old_keyword_ui_state = keyword_ui_state_;
+
// Update keyword/hint-related local state.
bool keyword_state_changed = (keyword_ != keyword) ||
((is_keyword_hint_ != is_keyword_hint) && !keyword.empty());
@@ -588,6 +586,13 @@ void AutocompleteEditModel::OnPopupDataChanged(
is_keyword_hint_ = is_keyword_hint;
}
+ // Update |keyword_ui_state_| only when necessary. It may be changed even if
+ // |keyword_state_changed| is false.
+ if (keyword_ui_state_ != NO_KEYWORD) {
+ keyword_ui_state_ = (is_keyword_hint_ || keyword_.empty()) ?
+ NORMAL : KEYWORD;
+ }
+
// Handle changes to temporary text.
if (destination_for_temporary_text_change != NULL) {
const bool save_original_selection = !has_temporary_text_;
@@ -595,7 +600,8 @@ void AutocompleteEditModel::OnPopupDataChanged(
// Save the original selection and URL so it can be reverted later.
has_temporary_text_ = true;
original_url_ = *destination_for_temporary_text_change;
- original_keyword_ui_state_ = keyword_ui_state_;
+ original_keyword_ui_state_ = old_keyword_ui_state;
+ inline_autocomplete_text_.clear();
}
if (control_key_state_ == DOWN_WITHOUT_CHANGE) {
// Arrowing around the popup cancels control-enter.
@@ -612,23 +618,15 @@ void AutocompleteEditModel::OnPopupDataChanged(
return;
}
- // TODO(suzhe): Instead of messing with |inline_autocomplete_text_| here,
- // we should probably do it inside Observe(), and save/restore it around
- // changes to the temporary text. This will let us remove knowledge of
- // inline autocompletions from the popup code.
- //
- // Handle changes to inline autocomplete text. Don't make changes if the user
- // is showing temporary text. Making display changes would be obviously
- // wrong; making changes to the inline_autocomplete_text_ itself turns out to
- // be more subtlely wrong, because it means hitting esc will no longer revert
- // to the original state before arrowing.
- if (!has_temporary_text_) {
- inline_autocomplete_text_ = text;
- if (view_->OnInlineAutocompleteTextMaybeChanged(
- DisplayTextFromUserText(user_text_ + inline_autocomplete_text_),
- DisplayTextFromUserText(user_text_).length()))
- return;
- }
+ // All cases that can result in |has_temporary_text_| being set should have
+ // been handled by the conditional above.
+ DCHECK(!has_temporary_text_);
+
+ inline_autocomplete_text_ = text;
+ if (view_->OnInlineAutocompleteTextMaybeChanged(
+ DisplayTextFromUserText(user_text_ + inline_autocomplete_text_),
+ DisplayTextFromUserText(user_text_).length()))
+ return;
// All other code paths that return invoke OnChanged. We need to invoke
// OnChanged in case the destination url changed (as could happen when control
@@ -636,11 +634,12 @@ void AutocompleteEditModel::OnPopupDataChanged(
controller_->OnChanged();
}
-bool AutocompleteEditModel::OnAfterPossibleChange(const std::wstring& new_text,
- bool selection_differs,
- bool text_differs,
- bool just_deleted_text,
- bool at_end_of_edit) {
+bool AutocompleteEditModel::OnAfterPossibleChange(
+ const std::wstring& new_text,
+ bool selection_differs,
+ bool text_differs,
+ bool just_deleted_text,
+ bool allow_keyword_ui_change) {
// Update the paste state as appropriate: if we're just finishing a paste
// that replaced all the text, preserve that information; otherwise, if we've
// made some other edit, clear paste tracking.
@@ -680,24 +679,17 @@ bool AutocompleteEditModel::OnAfterPossibleChange(const std::wstring& new_text,
}
// Disable the fancy keyword UI if the user didn't already have a visible
- // keyword and is not at the end of the edit. This prevents us from showing
- // the fancy UI (and interrupting the user's editing) if the user happens to
- // have a keyword for 'a', types 'ab' then puts a space between the 'a' and
- // the 'b'.
+ // keyword and the view doesn't want us to change the keyword UI state.
+ // This prevents us from showing the fancy UI and interrupting the user's
+ // editing if, for example, the user happens to have a keyword for 'a',
+ // types 'ab' then puts a space between the 'a' and the 'b'.
+ // If |keyword_ui_state_| is set to NORMAL here, then it will be updated
+ // to a proper value in OnPopupDataChanged() method according to the new
+ // match result.
if (!had_keyword)
- keyword_ui_state_ = at_end_of_edit ? NORMAL : NO_KEYWORD;
+ keyword_ui_state_ = allow_keyword_ui_change ? NORMAL : NO_KEYWORD;
view_->UpdatePopup();
-
- if (had_keyword) {
- if (is_keyword_hint_ || keyword_.empty())
- keyword_ui_state_ = NORMAL;
- } else if ((keyword_ui_state_ != NO_KEYWORD) && !is_keyword_hint_ &&
- !keyword_.empty()) {
- // Went from no selected keyword to a selected keyword.
- keyword_ui_state_ = KEYWORD;
- }
-
return true;
}
@@ -770,14 +762,13 @@ void AutocompleteEditModel::InternalSetUserText(const std::wstring& text) {
}
bool AutocompleteEditModel::KeywordIsSelected() const {
- return ((keyword_ui_state_ != NO_KEYWORD) && !is_keyword_hint_ &&
- !keyword_.empty());
+ return keyword_ui_state_ == KEYWORD;
}
std::wstring AutocompleteEditModel::DisplayTextFromUserText(
const std::wstring& text) const {
return KeywordIsSelected() ?
- KeywordProvider::SplitReplacementStringFromInput(text) : text;
+ KeywordProvider::SplitReplacementStringFromInput(text, false) : text;
}
std::wstring AutocompleteEditModel::UserTextFromDisplayText(
diff --git a/chrome/browser/autocomplete/autocomplete_edit.h b/chrome/browser/autocomplete/autocomplete_edit.h
index 1a8da22..83c87c3 100644
--- a/chrome/browser/autocomplete/autocomplete_edit.h
+++ b/chrome/browser/autocomplete/autocomplete_edit.h
@@ -325,11 +325,16 @@ class AutocompleteEditModel : public NotificationObserver {
// Called by the AutocompleteEditView after something changes, with details
// about what state changes occured. Updates internal state, updates the
// popup if necessary, and returns true if any significant changes occurred.
+ // If |allow_keyword_ui_change| is false then the change should not affect
+ // keyword ui state, even if the text matches a keyword exactly. This value
+ // may be false when:
+ // 1) The insert caret is not at the end of the edit box
+ // 2) The user is composing a text with an IME
bool OnAfterPossibleChange(const std::wstring& new_text,
bool selection_differs,
bool text_differs,
bool just_deleted_text,
- bool at_end_of_edit);
+ bool allow_keyword_ui_change);
// Invoked when the popup is going to change its bounds to |bounds|.
void PopupBoundsChangedTo(const gfx::Rect& bounds);
diff --git a/chrome/browser/autocomplete/autocomplete_edit_unittest.cc b/chrome/browser/autocomplete/autocomplete_edit_unittest.cc
index fe4c23b..bff0815 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_unittest.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit_unittest.cc
@@ -56,6 +56,7 @@ class TestingAutocompleteEditView : public AutocompleteEditView {
virtual CommandUpdater* GetCommandUpdater() { return NULL; }
virtual void SetInstantSuggestion(const string16& input) {}
virtual int TextWidth() const { return 0; }
+ virtual bool IsImeComposing() const { return false; }
#if defined(TOOLKIT_VIEWS)
virtual views::View* AddToView(views::View* parent) { return NULL; }
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view.h b/chrome/browser/autocomplete/autocomplete_edit_view.h
index 3fe7c48..4432882 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view.h
+++ b/chrome/browser/autocomplete/autocomplete_edit_view.h
@@ -165,6 +165,9 @@ class AutocompleteEditView {
// returned value includes margins.
virtual int TextWidth() const = 0;
+ // Returns true if the user is composing something in an IME.
+ virtual bool IsImeComposing() const = 0;
+
#if defined(TOOLKIT_VIEWS)
// Adds the autocomplete edit view to view hierarchy and
// returns the views::View of the edit view.
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
index 576638b..4ebd199 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc
@@ -605,10 +605,7 @@ void AutocompleteEditViewGtk::UpdatePopup() {
// the text, or in the middle of composition.
CharRange sel = GetSelection();
bool no_inline_autocomplete =
- std::max(sel.cp_max, sel.cp_min) < GetTextLength();
-#if GTK_CHECK_VERSION(2, 20, 0)
- no_inline_autocomplete = no_inline_autocomplete || preedit_.size();
-#endif
+ std::max(sel.cp_max, sel.cp_min) < GetTextLength() || IsImeComposing();
model_->StartAutocomplete(sel.cp_min != sel.cp_max, no_inline_autocomplete);
}
@@ -726,8 +723,10 @@ bool AutocompleteEditViewGtk::OnAfterPossibleChange() {
delete_at_end_pressed_ = false;
+ bool allow_keyword_ui_change = at_end_of_edit && !IsImeComposing();
bool something_changed = model_->OnAfterPossibleChange(new_text,
- selection_differs, text_changed_, just_deleted_text, at_end_of_edit);
+ selection_differs, text_changed_, just_deleted_text,
+ allow_keyword_ui_change);
// If only selection was changed, we don't need to call |controller_|'s
// OnChanged() method, which is called in TextChanged().
@@ -818,6 +817,14 @@ int AutocompleteEditViewGtk::TextWidth() const {
return text_width + horizontal_border_size;
}
+bool AutocompleteEditViewGtk::IsImeComposing() const {
+#if GTK_CHECK_VERSION(2, 20, 0)
+ return !preedit_.empty();
+#else
+ return false;
+#endif
+}
+
#if defined(TOOLKIT_VIEWS)
views::View* AutocompleteEditViewGtk::AddToView(views::View* parent) {
views::NativeViewHost* host = new views::NativeViewHost;
@@ -1841,9 +1848,7 @@ AutocompleteEditViewGtk::CharRange AutocompleteEditViewGtk::GetSelection() {
void AutocompleteEditViewGtk::ItersFromCharRange(const CharRange& range,
GtkTextIter* iter_min,
GtkTextIter* iter_max) {
-#if GTK_CHECK_VERSION(2, 20, 0)
- DCHECK(preedit_.empty());
-#endif
+ DCHECK(!IsImeComposing());
gtk_text_buffer_get_iter_at_offset(text_buffer_, iter_min, range.cp_min);
gtk_text_buffer_get_iter_at_offset(text_buffer_, iter_max, range.cp_max);
}
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
index e03ff1d..190fa27 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h
@@ -145,6 +145,8 @@ class AutocompleteEditViewGtk : public AutocompleteEditView,
virtual CommandUpdater* GetCommandUpdater();
virtual void SetInstantSuggestion(const string16& suggestion);
virtual int TextWidth() const;
+ virtual bool IsImeComposing() const;
+
#if defined(TOOLKIT_VIEWS)
virtual views::View* AddToView(views::View* parent);
virtual bool CommitInstantSuggestion(const std::wstring& typed_text,
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h
index 05a6158..0135f1d 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.h
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.h
@@ -85,6 +85,7 @@ class AutocompleteEditViewMac : public AutocompleteEditView,
virtual CommandUpdater* GetCommandUpdater();
virtual void SetInstantSuggestion(const string16& input);
virtual int TextWidth() const;
+ virtual bool IsImeComposing() const;
// Implement the AutocompleteTextFieldObserver interface.
virtual NSRange SelectionRangeForProposedRange(NSRange proposed_range);
@@ -131,6 +132,10 @@ class AutocompleteEditViewMac : public AutocompleteEditView,
// field has focus.
NSRange GetSelectedRange() const;
+ // Returns the field's currently marked range. Only valid if the field has
+ // focus.
+ NSRange GetMarkedRange() const;
+
// Returns true if |field_| is first-responder in the window. Used
// in various DCHECKS to make sure code is running in appropriate
// situations.
@@ -185,6 +190,7 @@ class AutocompleteEditViewMac : public AutocompleteEditView,
// to model_.
NSRange selection_before_change_;
std::wstring text_before_change_;
+ NSRange marked_range_before_change_;
// Length of the suggest text. The suggest text always appears at the end of
// the field.
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
index 261a823..19040b5 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_mac.mm
@@ -329,6 +329,11 @@ NSRange AutocompleteEditViewMac::GetSelectedRange() const {
return [[field_ currentEditor] selectedRange];
}
+NSRange AutocompleteEditViewMac::GetMarkedRange() const {
+ DCHECK([field_ currentEditor]);
+ return [(NSTextView*)[field_ currentEditor] markedRange];
+}
+
void AutocompleteEditViewMac::SetSelectedRange(const NSRange range) {
// This can be called when we don't have focus. For instance, when
// the user clicks the "Go" button.
@@ -403,12 +408,6 @@ void AutocompleteEditViewMac::SelectAll(bool reversed) {
void AutocompleteEditViewMac::RevertAll() {
ClosePopup();
model_->Revert();
-
- // TODO(shess): This should be a no-op, the results from GetText()
- // could only get there via UpdateAndStyleText() in the first place.
- // Dig into where this code can be called from and see if this line
- // can be removed.
- EmphasizeURLComponents();
controller_->OnChanged();
[field_ clearUndoChain];
}
@@ -424,16 +423,12 @@ void AutocompleteEditViewMac::UpdatePopup() {
// * The caret/selection isn't at the end of the text
// * The user has just pasted in something that replaced all the text
// * The user is trying to compose something in an IME
- bool prevent_inline_autocomplete = false;
+ bool prevent_inline_autocomplete = IsImeComposing();
NSTextView* editor = (NSTextView*)[field_ currentEditor];
if (editor) {
- if ([editor hasMarkedText])
- prevent_inline_autocomplete = true;
-
if (NSMaxRange([editor selectedRange]) <
- [[editor textStorage] length] - suggest_text_length_) {
+ [[editor textStorage] length] - suggest_text_length_)
prevent_inline_autocomplete = true;
- }
}
model_->StartAutocomplete([editor selectedRange].length != 0,
@@ -605,8 +600,10 @@ void AutocompleteEditViewMac::OnTemporaryTextMaybeChanged(
}
void AutocompleteEditViewMac::OnStartingIME() {
- if (model_->is_keyword_hint() && !model_->keyword().empty())
- model_->AcceptKeyword();
+ // Reset the suggest text just before starting an IME composition session,
+ // otherwise the IME composition may be interrupted when the suggest text
+ // gets reset by the IME composition change.
+ SetInstantSuggestion(string16());
}
bool AutocompleteEditViewMac::OnInlineAutocompleteTextMaybeChanged(
@@ -614,9 +611,8 @@ bool AutocompleteEditViewMac::OnInlineAutocompleteTextMaybeChanged(
// TODO(shess): Make sure that this actually works. The round trip
// to native form and back may mean that it's the same but not the
// same.
- if (display_text == GetText()) {
+ if (display_text == GetText())
return false;
- }
DCHECK_LE(user_text_length, display_text.size());
const NSRange range =
@@ -642,6 +638,7 @@ void AutocompleteEditViewMac::OnBeforePossibleChange() {
selection_before_change_ = GetSelectedRange();
text_before_change_ = GetText();
+ marked_range_before_change_ = GetMarkedRange();
}
bool AutocompleteEditViewMac::OnAfterPossibleChange() {
@@ -655,7 +652,8 @@ bool AutocompleteEditViewMac::OnAfterPossibleChange() {
const bool selection_differs = !NSEqualRanges(new_selection,
selection_before_change_);
const bool at_end_of_edit = (length == new_selection.location);
- const bool text_differs = (new_text != text_before_change_);
+ const bool text_differs = (new_text != text_before_change_) ||
+ !NSEqualRanges(marked_range_before_change_, GetMarkedRange());
// When the user has deleted text, we don't allow inline
// autocomplete. This is assumed if the text has gotten shorter AND
@@ -673,8 +671,10 @@ bool AutocompleteEditViewMac::OnAfterPossibleChange() {
delete_at_end_pressed_ = false;
+ const bool allow_keyword_ui_change = at_end_of_edit && !IsImeComposing();
const bool something_changed = model_->OnAfterPossibleChange(new_text,
- selection_differs, text_differs, just_deleted_text, at_end_of_edit);
+ selection_differs, text_differs, just_deleted_text,
+ allow_keyword_ui_change);
if (delete_was_pressed_ && at_end_of_edit)
delete_at_end_pressed_ = true;
@@ -729,6 +729,10 @@ int AutocompleteEditViewMac::TextWidth() const {
return 0;
}
+bool AutocompleteEditViewMac::IsImeComposing() const {
+ return [(NSTextView*)[field_ currentEditor] hasMarkedText];
+}
+
void AutocompleteEditViewMac::OnDidBeginEditing() {
// We should only arrive here when the field is focussed.
DCHECK([field_ currentEditor]);
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc
index 8d4d4e2..fb8e740 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_win.cc
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.cc
@@ -843,6 +843,11 @@ void AutocompleteEditViewWin::OnBeforePossibleChange() {
}
bool AutocompleteEditViewWin::OnAfterPossibleChange() {
+ return OnAfterPossibleChangeInternal(false);
+}
+
+bool AutocompleteEditViewWin::OnAfterPossibleChangeInternal(
+ bool force_text_changed) {
// Prevent the user from selecting the "phantom newline" at the end of the
// edit. If they try, we just silently move the end of the selection back to
// the end of the real text.
@@ -863,7 +868,8 @@ bool AutocompleteEditViewWin::OnAfterPossibleChange() {
// See if the text or selection have changed since OnBeforePossibleChange().
const std::wstring new_text(GetText());
- const bool text_differs = (new_text != text_before_change_);
+ const bool text_differs = (new_text != text_before_change_) ||
+ force_text_changed;
// When the user has deleted text, we don't allow inline autocomplete. Make
// sure to not flag cases like selecting part of the text and then pasting
@@ -875,9 +881,10 @@ bool AutocompleteEditViewWin::OnAfterPossibleChange() {
(new_sel.cpMin <= std::min(sel_before_change_.cpMin,
sel_before_change_.cpMax));
-
+ const bool allow_keyword_ui_change = at_end_of_edit && !IsImeComposing();
const bool something_changed = model_->OnAfterPossibleChange(new_text,
- selection_differs, text_differs, just_deleted_text, at_end_of_edit);
+ selection_differs, text_differs, just_deleted_text,
+ allow_keyword_ui_change);
if (selection_differs)
controller_->OnSelectionBoundsChanged();
@@ -918,6 +925,16 @@ int AutocompleteEditViewWin::TextWidth() const {
return WidthNeededToDisplay(GetText());
}
+bool AutocompleteEditViewWin::IsImeComposing() const {
+ bool ime_composing = false;
+ HIMC context = ImmGetContext(m_hWnd);
+ if (context) {
+ ime_composing = !!ImmGetCompositionString(context, GCS_COMPSTR, NULL, 0);
+ ImmReleaseContext(m_hWnd, context);
+ }
+ return ime_composing;
+}
+
views::View* AutocompleteEditViewWin::AddToView(views::View* parent) {
views::NativeViewHost* host = new views::NativeViewHost;
parent->AddChildView(host);
@@ -1301,70 +1318,13 @@ LRESULT AutocompleteEditViewWin::OnImeComposition(UINT message,
ScopedFreeze freeze(this, GetTextObjectModel());
OnBeforePossibleChange();
LRESULT result = DefWindowProc(message, wparam, lparam);
-
- // Some IMEs insert whitespace characters instead of input characters while
- // they are composing text, and trimming these whitespace characters at the
- // beginning of this control (in OnAfterPossibleChange()) prevents users from
- // inputting text on these IMEs.
- // To prevent this problem, we should not start auto-complete if the
- // composition string starts with whitespace characters.
- // (When we type a space key to insert a whitespace character, IMEs don't
- // insert the whitespace character to their composition string but their
- // result string. So, this code doesn't prevent us from updating autocomplete
- // when we insert a whitespace character.)
- if (lparam & GCS_COMPSTR) {
- std::wstring text;
- HIMC context = ImmGetContext(m_hWnd);
- if (context) {
- int size = ImmGetCompositionString(context, GCS_COMPSTR, NULL, 0);
- if (size > 0) {
- wchar_t* text_data = WriteInto(&text, size / sizeof(wchar_t) + 1);
- if (text_data)
- ImmGetCompositionString(context, GCS_COMPSTR, text_data, size);
- }
- ImmReleaseContext(m_hWnd, context);
- }
- if (!text.empty() && IsWhitespace(text[0]))
- return result;
- }
-
- if (!OnAfterPossibleChange() && (lparam & GCS_RESULTSTR)) {
- // The result string changed, but the text in the popup didn't actually
- // change. This means the user finalized the composition. Rerun
- // autocomplete so that we can now trigger inline autocomplete if
- // applicable.
- //
- // Note that if we're in the midst of losing focus, UpdatePopup() won't
- // actually rerun autocomplete, but will just set local state correctly.
- UpdatePopup();
- }
+ // Force an IME composition confirmation operation to trigger the text_changed
+ // code in OnAfterPossibleChange(), even if identical contents are confirmed,
+ // to make sure the model can update its internal states correctly.
+ OnAfterPossibleChangeInternal((lparam & GCS_RESULTSTR) != 0);
return result;
}
-LRESULT AutocompleteEditViewWin::OnImeNotify(UINT message,
- WPARAM wparam,
- LPARAM lparam) {
- // NOTE: I'm not sure this is ever reached with |ignore_ime_messages_| set,
- // but if it is, the safe thing to do is to only call DefWindowProc().
- if (!ignore_ime_messages_ && (wparam == IMN_SETOPENSTATUS)) {
- // A user has activated (or deactivated) IMEs (but not started a
- // composition).
- // Some IMEs get confused when we accept keywords while they are composing
- // text. To prevent this situation, we accept keywords when an IME is
- // activated.
- HIMC imm_context = ImmGetContext(m_hWnd);
- if (imm_context) {
- if (ImmGetOpenStatus(imm_context) &&
- model_->is_keyword_hint() && !model_->keyword().empty()) {
- ScopedFreeze freeze(this, GetTextObjectModel());
- model_->AcceptKeyword();
- }
- ImmReleaseContext(m_hWnd, imm_context);
- }
- }
- return DefWindowProc(message, wparam, lparam);
-}
-
void AutocompleteEditViewWin::OnKeyDown(TCHAR key,
UINT repeat_count,
UINT flags) {
@@ -2607,13 +2567,3 @@ int AutocompleteEditViewWin::WidthNeededToDisplay(
// PosFromChar(i) might return 0 when i is greater than 1.
return font_.GetStringWidth(text) + GetHorizontalMargin();
}
-
-bool AutocompleteEditViewWin::IsImeComposing() const {
- bool ime_composing = false;
- HIMC context = ImmGetContext(m_hWnd);
- if (context) {
- ime_composing = !!ImmGetCompositionString(context, GCS_COMPSTR, NULL, 0);
- ImmReleaseContext(m_hWnd, context);
- }
- return ime_composing;
-}
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_win.h b/chrome/browser/autocomplete/autocomplete_edit_view_win.h
index b551862..c4b642a 100644
--- a/chrome/browser/autocomplete/autocomplete_edit_view_win.h
+++ b/chrome/browser/autocomplete/autocomplete_edit_view_win.h
@@ -135,6 +135,8 @@ class AutocompleteEditViewWin
virtual CommandUpdater* GetCommandUpdater();
virtual void SetInstantSuggestion(const string16& suggestion);
virtual int TextWidth() const;
+ virtual bool IsImeComposing() const;
+
virtual views::View* AddToView(views::View* parent);
virtual bool CommitInstantSuggestion(const std::wstring& typed_text,
const std::wstring& suggested_text);
@@ -179,7 +181,6 @@ class AutocompleteEditViewWin
MSG_WM_CUT(OnCut)
MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeComposition)
- MESSAGE_HANDLER_EX(WM_IME_NOTIFY, OnImeNotify)
MSG_WM_KEYDOWN(OnKeyDown)
MSG_WM_KEYUP(OnKeyUp)
MSG_WM_KILLFOCUS(OnKillFocus)
@@ -215,9 +216,6 @@ class AutocompleteEditViewWin
virtual std::wstring GetLabelForCommandId(int command_id) const;
virtual void ExecuteCommand(int command_id);
- // Returns true if the user is composing something in an IME.
- bool IsImeComposing() const;
-
private:
enum MouseButton {
kLeft = 0,
@@ -275,7 +273,6 @@ class AutocompleteEditViewWin
void OnCut();
LRESULT OnGetObject(UINT uMsg, WPARAM wparam, LPARAM lparam);
LRESULT OnImeComposition(UINT message, WPARAM wparam, LPARAM lparam);
- LRESULT OnImeNotify(UINT message, WPARAM wparam, LPARAM lparam);
void OnKeyDown(TCHAR key, UINT repeat_count, UINT flags);
void OnKeyUp(TCHAR key, UINT repeat_count, UINT flags);
void OnKillFocus(HWND focus_wnd);
@@ -408,6 +405,11 @@ class AutocompleteEditViewWin
// Returns the width in pixels needed to display |text|.
int WidthNeededToDisplay(const std::wstring& text) const;
+ // Real implementation of OnAfterPossibleChange() method.
+ // If |force_text_changed| is true, then the text_changed code will always be
+ // triggerred no matter if the text is actually changed or not.
+ bool OnAfterPossibleChangeInternal(bool force_text_changed);
+
scoped_ptr<AutocompleteEditModel> model_;
scoped_ptr<AutocompletePopupView> popup_view_;
diff --git a/chrome/browser/autocomplete/autocomplete_popup_model.cc b/chrome/browser/autocomplete/autocomplete_popup_model.cc
index 2ea4068..8af3572 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_model.cc
+++ b/chrome/browser/autocomplete/autocomplete_popup_model.cc
@@ -51,14 +51,15 @@ void AutocompletePopupModel::StartAutocomplete(
const std::wstring& text,
const std::wstring& desired_tld,
bool prevent_inline_autocomplete,
- bool prefer_keyword) {
+ bool prefer_keyword,
+ bool allow_exact_keyword_match) {
// The user is interacting with the edit, so stop tracking hover.
SetHoveredLine(kNoMatch);
manually_selected_match_.Clear();
controller_->Start(text, desired_tld, prevent_inline_autocomplete,
- prefer_keyword, true, false);
+ prefer_keyword, allow_exact_keyword_match, false);
}
void AutocompletePopupModel::StopAutocomplete() {
diff --git a/chrome/browser/autocomplete/autocomplete_popup_model.h b/chrome/browser/autocomplete/autocomplete_popup_model.h
index 9c5384f..ee1fef0 100644
--- a/chrome/browser/autocomplete/autocomplete_popup_model.h
+++ b/chrome/browser/autocomplete/autocomplete_popup_model.h
@@ -33,7 +33,8 @@ class AutocompletePopupModel : public NotificationObserver {
void StartAutocomplete(const std::wstring& text,
const std::wstring& desired_tld,
bool prevent_inline_autocomplete,
- bool prefer_keyword);
+ bool prefer_keyword,
+ bool allow_exact_keyword_match);
// Closes the window and cancels any pending asynchronous queries.
void StopAutocomplete();
diff --git a/chrome/browser/autocomplete/keyword_provider.cc b/chrome/browser/autocomplete/keyword_provider.cc
index 71a8f40..a1be35a 100644
--- a/chrome/browser/autocomplete/keyword_provider.cc
+++ b/chrome/browser/autocomplete/keyword_provider.cc
@@ -42,14 +42,16 @@ class KeywordProvider::ScopedEndExtensionKeywordMode {
// static
std::wstring KeywordProvider::SplitReplacementStringFromInput(
- const std::wstring& input) {
+ const std::wstring& input,
+ bool trim_leading_whitespace) {
// The input may contain leading whitespace, strip it.
std::wstring trimmed_input;
TrimWhitespace(input, TRIM_LEADING, &trimmed_input);
// And extract the replacement string.
std::wstring remaining_input;
- SplitKeywordFromInput(trimmed_input, &remaining_input);
+ SplitKeywordFromInput(trimmed_input, trim_leading_whitespace,
+ &remaining_input);
return remaining_input;
}
@@ -275,13 +277,14 @@ bool KeywordProvider::ExtractKeywordFromInput(const AutocompleteInput& input,
return false;
*keyword = TemplateURLModel::CleanUserInputKeyword(
- SplitKeywordFromInput(input.text(), remaining_input));
+ SplitKeywordFromInput(input.text(), true, remaining_input));
return !keyword->empty();
}
// static
std::wstring KeywordProvider::SplitKeywordFromInput(
const std::wstring& input,
+ bool trim_leading_whitespace,
std::wstring* remaining_input) {
// Find end of first token. The AutocompleteController has trimmed leading
// whitespace, so we need not skip over that.
@@ -292,10 +295,11 @@ std::wstring KeywordProvider::SplitKeywordFromInput(
// Set |remaining_input| to everything after the first token.
DCHECK(remaining_input != NULL);
- const size_t first_nonwhite(input.find_first_not_of(kWhitespaceWide,
- first_white));
- if (first_nonwhite != std::wstring::npos)
- remaining_input->assign(input.begin() + first_nonwhite, input.end());
+ const size_t remaining_start = trim_leading_whitespace ?
+ input.find_first_not_of(kWhitespaceWide, first_white) : first_white + 1;
+
+ if (remaining_start < input.length())
+ remaining_input->assign(input.begin() + remaining_start, input.end());
// Return first token as keyword.
return input.substr(0, first_white);
diff --git a/chrome/browser/autocomplete/keyword_provider.h b/chrome/browser/autocomplete/keyword_provider.h
index 4a6ad90..7adb9b5 100644
--- a/chrome/browser/autocomplete/keyword_provider.h
+++ b/chrome/browser/autocomplete/keyword_provider.h
@@ -58,8 +58,11 @@ class KeywordProvider : public AutocompleteProvider,
// Returns the replacement string from the user input. The replacement
// string is the portion of the input that does not contain the keyword.
// For example, the replacement string for "b blah" is blah.
+ // If |trim_leading_whitespace| is true then leading whitespace in
+ // replacement string will be trimmed.
static std::wstring SplitReplacementStringFromInput(
- const std::wstring& input);
+ const std::wstring& input,
+ bool trim_leading_whitespace);
// Returns the matching substituting keyword for |input|, or NULL if there
// is no keyword for the specified input.
@@ -84,14 +87,18 @@ class KeywordProvider : public AutocompleteProvider,
// extract the keyword and remaining string, and uses
// TemplateURLModel::CleanUserInputKeyword to remove unnecessary characters.
// In general use this instead of SplitKeywordFromInput.
+ // Leading whitespace in |*remaining_input| will be trimmed.
static bool ExtractKeywordFromInput(const AutocompleteInput& input,
std::wstring* keyword,
std::wstring* remaining_input);
// Extracts the next whitespace-delimited token from input and returns it.
// Sets |remaining_input| to everything after the first token (skipping over
- // intervening whitespace).
+ // the first intervening whitespace).
+ // If |trim_leading_whitespace| is true then leading whitespace in
+ // |*remaining_input| will be trimmed.
static std::wstring SplitKeywordFromInput(const std::wstring& input,
+ bool trim_leading_whitespace,
std::wstring* remaining_input);
// Fills in the "destination_url" and "contents" fields of |match| with the