diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs
index 6402a3b623c..284207ae214 100644
--- a/components/script/dom/htmlinputelement.rs
+++ b/components/script/dom/htmlinputelement.rs
@@ -2652,8 +2652,6 @@ impl VirtualMethods for HTMLInputElement {
event.type_() == atom!("compositionend")) &&
self.input_type().is_textual_or_password()
{
- // TODO: Update DOM on start and continue
- // and generally do proper CompositionEvent handling.
if let Some(compositionevent) = event.downcast::() {
if event.type_() == atom!("compositionend") {
let _ = self
@@ -2661,6 +2659,12 @@ impl VirtualMethods for HTMLInputElement {
.borrow_mut()
.handle_compositionend(compositionevent);
self.upcast::().dirty(NodeDamage::OtherNodeDamage);
+ } else if event.type_() == atom!("compositionupdate") {
+ let _ = self
+ .textinput
+ .borrow_mut()
+ .handle_compositionupdate(compositionevent);
+ self.upcast::().dirty(NodeDamage::OtherNodeDamage);
}
event.mark_as_handled();
}
diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs
index c18f245eb87..91a8cde54ff 100644
--- a/components/script/dom/htmltextareaelement.rs
+++ b/components/script/dom/htmltextareaelement.rs
@@ -668,8 +668,6 @@ impl VirtualMethods for HTMLTextAreaElement {
event.type_() == atom!("compositionupdate") ||
event.type_() == atom!("compositionend")
{
- // TODO: Update DOM on start and continue
- // and generally do proper CompositionEvent handling.
if let Some(compositionevent) = event.downcast::() {
if event.type_() == atom!("compositionend") {
let _ = self
@@ -677,6 +675,12 @@ impl VirtualMethods for HTMLTextAreaElement {
.borrow_mut()
.handle_compositionend(compositionevent);
self.upcast::().dirty(NodeDamage::OtherNodeDamage);
+ } else if event.type_() == atom!("compositionupdate") {
+ let _ = self
+ .textinput
+ .borrow_mut()
+ .handle_compositionupdate(compositionevent);
+ self.upcast::().dirty(NodeDamage::OtherNodeDamage);
}
event.mark_as_handled();
}
diff --git a/components/script/textinput.rs b/components/script/textinput.rs
index 4406984a34f..1a72c0d26f8 100644
--- a/components/script/textinput.rs
+++ b/components/script/textinput.rs
@@ -988,6 +988,17 @@ impl TextInput {
KeyReaction::DispatchInput
}
+ pub(crate) fn handle_compositionupdate(&mut self, event: &CompositionEvent) -> KeyReaction {
+ let start = self.selection_start_offset().0;
+ self.insert_string(event.data());
+ self.set_selection_range(
+ start as u32,
+ (start + event.data().len_utf8().0) as u32,
+ SelectionDirection::Forward,
+ );
+ KeyReaction::DispatchInput
+ }
+
/// Whether the content is empty.
pub(crate) fn is_empty(&self) -> bool {
self.lines.len() <= 1 && self.lines.first().map_or(true, |line| line.is_empty())
diff --git a/ports/servoshell/desktop/app_state.rs b/ports/servoshell/desktop/app_state.rs
index 9ef17477c95..1d8ffa578c1 100644
--- a/ports/servoshell/desktop/app_state.rs
+++ b/ports/servoshell/desktop/app_state.rs
@@ -527,6 +527,22 @@ impl WebViewDelegate for RunningAppState {
};
let _ = haptic_stop_sender.send(stopped);
}
+ fn show_ime(
+ &self,
+ _webview: WebView,
+ input_type: servo::InputMethodType,
+ text: Option<(String, i32)>,
+ multiline: bool,
+ position: servo::webrender_api::units::DeviceIntRect,
+ ) {
+ self.inner()
+ .window
+ .show_ime(input_type, text, multiline, position);
+ }
+
+ fn hide_ime(&self, _webview: WebView) {
+ self.inner().window.hide_ime();
+ }
}
#[cfg(target_os = "linux")]
diff --git a/ports/servoshell/desktop/headed_window.rs b/ports/servoshell/desktop/headed_window.rs
index 68dfc519888..e7f5026309b 100644
--- a/ports/servoshell/desktop/headed_window.rs
+++ b/ports/servoshell/desktop/headed_window.rs
@@ -631,6 +631,35 @@ impl WindowPortsMethods for Window {
WindowEvent::Moved(_new_position) => {
webview.notify_embedder_window_moved();
},
+ winit::event::WindowEvent::Ime(ime) => match ime {
+ winit::event::Ime::Enabled => {
+ webview.notify_input_event(InputEvent::Ime(servo::ImeEvent::Composition(
+ servo::CompositionEvent {
+ state: servo::CompositionState::Start,
+ data: String::new(),
+ },
+ )));
+ },
+ winit::event::Ime::Preedit(text, _) => {
+ webview.notify_input_event(InputEvent::Ime(servo::ImeEvent::Composition(
+ servo::CompositionEvent {
+ state: servo::CompositionState::Update,
+ data: text,
+ },
+ )));
+ },
+ winit::event::Ime::Commit(text) => {
+ webview.notify_input_event(InputEvent::Ime(servo::ImeEvent::Composition(
+ servo::CompositionEvent {
+ state: servo::CompositionState::End,
+ data: text,
+ },
+ )));
+ },
+ winit::event::Ime::Disabled => {
+ webview.notify_input_event(InputEvent::Ime(servo::ImeEvent::Dismissed));
+ },
+ },
_ => {},
}
}
@@ -673,6 +702,19 @@ impl WindowPortsMethods for Window {
fn rendering_context(&self) -> Rc {
self.rendering_context.clone()
}
+ fn show_ime(
+ &self,
+ _input_type: servo::InputMethodType,
+ _text: Option<(String, i32)>,
+ _multiline: bool,
+ _position: servo::webrender_api::units::DeviceIntRect,
+ ) {
+ self.winit_window.set_ime_allowed(true);
+ }
+
+ fn hide_ime(&self) {
+ self.winit_window.set_ime_allowed(false);
+ }
}
impl WindowMethods for Window {
diff --git a/ports/servoshell/desktop/window_trait.rs b/ports/servoshell/desktop/window_trait.rs
index 915cd502eb4..4c7b794412a 100644
--- a/ports/servoshell/desktop/window_trait.rs
+++ b/ports/servoshell/desktop/window_trait.rs
@@ -47,4 +47,14 @@ pub trait WindowPortsMethods: WindowMethods {
fn toolbar_height(&self) -> Length;
fn set_toolbar_height(&self, height: Length);
fn rendering_context(&self) -> Rc;
+ fn show_ime(
+ &self,
+ _input_type: servo::InputMethodType,
+ _text: Option<(String, i32)>,
+ _multiline: bool,
+ _position: servo::webrender_api::units::DeviceIntRect,
+ ) {
+ }
+
+ fn hide_ime(&self) {}
}