Index: chrome/browser/renderer_host/gtk_im_context_wrapper.cc |
diff --git a/chrome/browser/renderer_host/gtk_im_context_wrapper.cc b/chrome/browser/renderer_host/gtk_im_context_wrapper.cc |
index 5135d464f3e0bed9c882cee94dc12d217939844a..fc46a9861fb2dac3feec2e416bb67b7ace7bee9f 100644 |
--- a/chrome/browser/renderer_host/gtk_im_context_wrapper.cc |
+++ b/chrome/browser/renderer_host/gtk_im_context_wrapper.cc |
@@ -22,6 +22,8 @@ |
#include "content/common/native_web_keyboard_event.h" |
#include "grit/generated_resources.h" |
#include "third_party/skia/include/core/SkColor.h" |
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderline.h" |
+#include "ui/base/gtk/gtk_im_context_util.h" |
#include "ui/base/l10n/l10n_util.h" |
#include "ui/gfx/gtk_util.h" |
#include "ui/gfx/rect.h" |
@@ -46,6 +48,14 @@ namespace { |
const int kCompositionEventKeyCode = 229; |
} // namespace |
+// ui::CompositionUnderline should be identical to |
+// WebKit::WebCompositionUnderline, so that we can do reinterpret_cast safely. |
+// TODO(suzhe): remove it after migrating all code in chrome to use |
+// ui::CompositionUnderline. |
+COMPILE_ASSERT(sizeof(ui::CompositionUnderline) == |
+ sizeof(WebKit::WebCompositionUnderline), |
+ ui_CompositionUnderline__WebKit_WebCompositionUnderline_diff); |
+ |
GtkIMContextWrapper::GtkIMContextWrapper(RenderWidgetHostViewGtk* host_view) |
: host_view_(host_view), |
context_(gtk_im_multicontext_new()), |
@@ -54,9 +64,7 @@ GtkIMContextWrapper::GtkIMContextWrapper(RenderWidgetHostViewGtk* host_view) |
is_composing_text_(false), |
is_enabled_(false), |
is_in_key_event_handler_(false), |
- preedit_selection_start_(0), |
- preedit_selection_end_(0), |
- is_preedit_changed_(false), |
+ is_composition_changed_(false), |
suppress_next_commit_(false), |
last_key_code_(0), |
last_key_was_up_(false), |
@@ -114,7 +122,7 @@ void GtkIMContextWrapper::ProcessKeyEvent(GdkEventKey* event) { |
is_in_key_event_handler_ = true; |
// Reset this flag so that we can know if preedit is changed after |
// processing this key event. |
- is_preedit_changed_ = false; |
+ is_composition_changed_ = false; |
// Clear it so that we can know if something needs committing after |
// processing this key event. |
commit_text_.clear(); |
@@ -345,8 +353,7 @@ void GtkIMContextWrapper::CancelComposition() { |
} |
is_composing_text_ = false; |
- preedit_text_.clear(); |
- preedit_underlines_.clear(); |
+ composition_.Clear(); |
commit_text_.clear(); |
is_in_key_event_handler_ = false; |
@@ -362,7 +369,7 @@ bool GtkIMContextWrapper::NeedCommitByForwardingCharEvent() const { |
} |
bool GtkIMContextWrapper::HasInputMethodResult() const { |
- return commit_text_.length() || is_preedit_changed_; |
+ return commit_text_.length() || is_composition_changed_; |
} |
void GtkIMContextWrapper::ProcessFilteredKeyPressEvent( |
@@ -444,12 +451,18 @@ void GtkIMContextWrapper::ProcessInputMethodResult(const GdkEventKey* event, |
// Send preedit text only if it's changed. |
// If a text has been committed, then we don't need to send the empty |
// preedit text again. |
- if (is_preedit_changed_) { |
- if (preedit_text_.length()) { |
+ if (is_composition_changed_) { |
+ if (composition_.text.length()) { |
// Another composition session has been started. |
is_composing_text_ = true; |
- host->ImeSetComposition(preedit_text_, preedit_underlines_, |
- preedit_selection_start_, preedit_selection_end_); |
+ // TODO(suzhe): convert both renderer_host and renderer to use |
+ // ui::CompositionText. |
+ const std::vector<WebKit::WebCompositionUnderline>& underlines = |
+ reinterpret_cast<const std::vector<WebKit::WebCompositionUnderline>&>( |
+ composition_.underlines); |
+ host->ImeSetComposition(composition_.text, underlines, |
+ composition_.selection.start(), |
+ composition_.selection.end()); |
} else if (!committed) { |
host->ImeCancelComposition(); |
} |
@@ -508,21 +521,21 @@ void GtkIMContextWrapper::HandlePreeditChanged(const gchar* text, |
if (suppress_next_commit_) |
return; |
- // Don't set is_preedit_changed_ to false if there is no change, because |
+ // Don't set is_composition_changed_ to false if there is no change, because |
// this handler might be called multiple times with the same data. |
- is_preedit_changed_ = true; |
- preedit_text_.clear(); |
- preedit_underlines_.clear(); |
- preedit_selection_start_ = 0; |
- preedit_selection_end_ = 0; |
+ is_composition_changed_ = true; |
+ composition_.Clear(); |
- ExtractCompositionInfo(text, attrs, cursor_position, &preedit_text_, |
- &preedit_underlines_, &preedit_selection_start_, |
- &preedit_selection_end_); |
+ ui::ExtractCompositionTextFromGtkPreedit(text, attrs, cursor_position, |
+ &composition_); |
+ |
+ // TODO(suzhe): due to a bug of webkit, we currently can't use selection range |
+ // with composition string. See: https://bugs.webkit.org/show_bug.cgi?id=40805 |
+ composition_.selection = ui::Range(cursor_position); |
// In case we are using a buggy input method which doesn't fire |
// "preedit_start" signal. |
- if (preedit_text_.length()) |
+ if (composition_.text.length()) |
is_composing_text_ = true; |
// Nothing needs to do, if it's currently in ProcessKeyEvent() |
@@ -532,19 +545,23 @@ void GtkIMContextWrapper::HandlePreeditChanged(const gchar* text, |
host_view_->GetRenderWidgetHost()) { |
// Workaround http://crbug.com/45478 by sending fake key down/up events. |
SendFakeCompositionKeyEvent(WebKit::WebInputEvent::RawKeyDown); |
+ // TODO(suzhe): convert both renderer_host and renderer to use |
+ // ui::CompositionText. |
+ const std::vector<WebKit::WebCompositionUnderline>& underlines = |
+ reinterpret_cast<const std::vector<WebKit::WebCompositionUnderline>&>( |
+ composition_.underlines); |
host_view_->GetRenderWidgetHost()->ImeSetComposition( |
- preedit_text_, preedit_underlines_, preedit_selection_start_, |
- preedit_selection_end_); |
+ composition_.text, underlines, composition_.selection.start(), |
+ composition_.selection.end()); |
SendFakeCompositionKeyEvent(WebKit::WebInputEvent::KeyUp); |
} |
} |
void GtkIMContextWrapper::HandlePreeditEnd() { |
- if (preedit_text_.length()) { |
+ if (composition_.text.length()) { |
// The composition session has been finished. |
- preedit_text_.clear(); |
- preedit_underlines_.clear(); |
- is_preedit_changed_ = true; |
+ composition_.Clear(); |
+ is_composition_changed_ = true; |
// If there is still a preedit text when firing "preedit-end" signal, |
// we need inform webkit to clear it. |
@@ -616,97 +633,3 @@ void GtkIMContextWrapper::HandleHostViewUnrealizeThunk( |
GtkWidget* widget, GtkIMContextWrapper* self) { |
self->HandleHostViewUnrealize(); |
} |
- |
-void GtkIMContextWrapper::ExtractCompositionInfo( |
- const gchar* utf8_text, |
- PangoAttrList* attrs, |
- int cursor_position, |
- string16* utf16_text, |
- std::vector<WebKit::WebCompositionUnderline>* underlines, |
- int* selection_start, |
- int* selection_end) { |
- *utf16_text = UTF8ToUTF16(utf8_text); |
- |
- if (utf16_text->empty()) |
- return; |
- |
- // Gtk/Pango uses character index for cursor position and byte index for |
- // attribute range, but we use char16 offset for them. So we need to do |
- // conversion here. |
- std::vector<int> char16_offsets; |
- int length = static_cast<int>(utf16_text->length()); |
- for (int offset = 0; offset < length; ++offset) { |
- char16_offsets.push_back(offset); |
- if (CBU16_IS_SURROGATE((*utf16_text)[offset])) |
- ++offset; |
- } |
- |
- // The text length in Unicode characters. |
- int char_length = static_cast<int>(char16_offsets.size()); |
- // Make sure we can convert the value of |char_length| as well. |
- char16_offsets.push_back(length); |
- |
- int cursor_offset = |
- char16_offsets[std::max(0, std::min(char_length, cursor_position))]; |
- |
- // TODO(suzhe): due to a bug of webkit, we currently can't use selection range |
- // with composition string. See: https://bugs.webkit.org/show_bug.cgi?id=40805 |
- *selection_start = *selection_end = cursor_offset; |
- |
- if (attrs) { |
- int utf8_length = strlen(utf8_text); |
- PangoAttrIterator* iter = pango_attr_list_get_iterator(attrs); |
- |
- // We only care about underline and background attributes and convert |
- // background attribute into selection if possible. |
- do { |
- gint start, end; |
- pango_attr_iterator_range(iter, &start, &end); |
- |
- start = std::min(start, utf8_length); |
- end = std::min(end, utf8_length); |
- if (start >= end) |
- continue; |
- |
- start = g_utf8_pointer_to_offset(utf8_text, utf8_text + start); |
- end = g_utf8_pointer_to_offset(utf8_text, utf8_text + end); |
- |
- // Double check, in case |utf8_text| is not a valid utf-8 string. |
- start = std::min(start, char_length); |
- end = std::min(end, char_length); |
- if (start >= end) |
- continue; |
- |
- PangoAttribute* background_attr = |
- pango_attr_iterator_get(iter, PANGO_ATTR_BACKGROUND); |
- PangoAttribute* underline_attr = |
- pango_attr_iterator_get(iter, PANGO_ATTR_UNDERLINE); |
- |
- if (background_attr || underline_attr) { |
- // Use a black thin underline by default. |
- WebKit::WebCompositionUnderline underline( |
- char16_offsets[start], char16_offsets[end], SK_ColorBLACK, false); |
- |
- // Always use thick underline for a range with background color, which |
- // is usually the selection range. |
- if (background_attr) |
- underline.thick = true; |
- if (underline_attr) { |
- int type = reinterpret_cast<PangoAttrInt*>(underline_attr)->value; |
- if (type == PANGO_UNDERLINE_DOUBLE) |
- underline.thick = true; |
- else if (type == PANGO_UNDERLINE_ERROR) |
- underline.color = SK_ColorRED; |
- } |
- underlines->push_back(underline); |
- } |
- } while (pango_attr_iterator_next(iter)); |
- pango_attr_iterator_destroy(iter); |
- } |
- |
- // Use a black thin underline by default. |
- if (underlines->empty()) { |
- underlines->push_back( |
- WebKit::WebCompositionUnderline(0, length, SK_ColorBLACK, false)); |
- } |
-} |