Skip to content

Commit c9d30bf

Browse files
committed
core: Prevent pasting empty string when the clipboard is empty
1 parent d4ad9fa commit c9d30bf

File tree

4 files changed

+27
-7
lines changed

4 files changed

+27
-7
lines changed

core/src/backend/ui.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ pub trait UiBackend: Downcast {
7373
/// Get the clipboard content
7474
fn clipboard_content(&mut self) -> String;
7575

76+
/// Check if the clipboard is available and not empty
77+
fn clipboard_available(&mut self) -> bool {
78+
!self.clipboard_content().is_empty()
79+
}
80+
7681
/// Sets the clipboard to the given content.
7782
fn set_clipboard_content(&mut self, content: String);
7883

core/src/context_menu.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use crate::display_object::{EditText, Stage};
1111
use crate::display_object::{InteractiveObject, TDisplayObject};
1212
use crate::events::TextControlCode;
1313
use crate::i18n::core_text;
14-
use fluent_templates::LanguageIdentifier;
1514
use gc_arena::Collect;
1615
use ruffle_render::quality::StageQuality;
1716
use serde::Serialize;
@@ -54,7 +53,7 @@ impl<'gc> ContextMenuState<'gc> {
5453
// show the copy/paste menu.
5554
if let Some(text) = context.focus_tracker.get_as_edit_text() {
5655
if InteractiveObject::option_ptr_eq(context.mouse_data.hovered, text.as_interactive()) {
57-
self.build_text_items(text, language);
56+
self.build_text_items(text, context);
5857
return;
5958
}
6059
}
@@ -139,8 +138,9 @@ impl<'gc> ContextMenuState<'gc> {
139138
}
140139
}
141140

142-
fn build_text_items(&mut self, text: EditText<'gc>, language: &LanguageIdentifier) {
143-
let flags = TextItemFlags::for_edit_text(text);
141+
fn build_text_items(&mut self, text: EditText<'gc>, context: &mut UpdateContext<'_, 'gc>) {
142+
let language = &context.ui.language();
143+
let flags = TextItemFlags::for_edit_text(text, context);
144144
self.push(
145145
ContextMenuItem {
146146
enabled: flags.cut,
@@ -292,16 +292,17 @@ struct TextItemFlags {
292292
}
293293

294294
impl TextItemFlags {
295-
pub fn for_edit_text(text: EditText<'_>) -> Self {
295+
pub fn for_edit_text<'gc>(text: EditText<'gc>, context: &mut UpdateContext<'_, 'gc>) -> Self {
296296
let editable = text.is_editable();
297297
let selectable = text.is_selectable();
298298
let any_text_selected = selectable && text.selection().is_some_and(|s| !s.is_caret());
299299
let pastable = editable && text.selection().is_some();
300+
let clipboard_available = context.ui.clipboard_available();
300301

301302
Self {
302303
cut: any_text_selected && editable,
303304
copy: any_text_selected,
304-
paste: pastable,
305+
paste: pastable && clipboard_available,
305306
delete: any_text_selected && editable,
306307
select_all: selectable,
307308
}

core/src/display_object/edit_text.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1502,8 +1502,16 @@ impl<'gc> EditText<'gc> {
15021502
context.ui.set_clipboard_content(text.to_string());
15031503
}
15041504
}
1505-
TextControlCode::Paste => {
1505+
TextControlCode::Paste => 'paste: {
15061506
let text = context.ui.clipboard_content();
1507+
if text.is_empty() {
1508+
// When the clipboard is empty, nothing is pasted
1509+
// and the already selected text is not removed.
1510+
// Note that if the clipboard is not empty, but does not have
1511+
// any allowed characters, the selected text is removed.
1512+
break 'paste;
1513+
}
1514+
15071515
let mut text = self.0.read().restrict.filter_allowed(&text);
15081516

15091517
if text.len() > self.available_chars() && self.available_chars() > 0 {

web/src/ui.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,12 @@ impl UiBackend for WebUiBackend {
222222
self.clipboard_content.to_owned()
223223
}
224224

225+
fn clipboard_available(&mut self) -> bool {
226+
// On web, we have to assume that the clipboard
227+
// is available due to the JS `paste` event.
228+
true
229+
}
230+
225231
fn set_clipboard_content(&mut self, content: String) {
226232
self.clipboard_content = content.to_owned();
227233
// We use `document.execCommand("copy")` as `navigator.clipboard.writeText("string")`

0 commit comments

Comments
 (0)