Fix undo counting in CPWL_EditImpl::ReplaceSelection for cut operations
When cutting all text and undoing, only partial text was restored due
to incorrect undo counting logic. Add special case handling for cut
operations (selection cleared + empty text inserted) to ensure proper
undo behavior.
Bug: 413695642
Change-Id: I67bff754183f118537aca0ab3ba4726fe63de689
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/132350
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/fpdfsdk/fpdf_formfill_embeddertest.cpp b/fpdfsdk/fpdf_formfill_embeddertest.cpp
index 2b6eda7..386109f 100644
--- a/fpdfsdk/fpdf_formfill_embeddertest.cpp
+++ b/fpdfsdk/fpdf_formfill_embeddertest.cpp
@@ -3591,3 +3591,32 @@
ASSERT_FALSE(
FORM_OnKeyDown(form_handle(), page(), FWL_VKEY_Control, modifier));
}
+
+TEST_F(FPDFFormFillTextFormEmbedderTest, CutAllTextUndoRestoresAllCharacters) {
+ ClickOnFormFieldAtPoint(RegularFormBegin());
+ CheckCanUndo(false);
+ CheckCanRedo(false);
+
+ // Type "ABC"
+ TypeTextIntoTextField(3, RegularFormBegin());
+ CheckFocusedFieldText("ABC");
+ CheckSelection("");
+ CheckCanUndo(true);
+
+ // Select all text
+ SelectAllRegularFormTextWithMouse();
+ CheckSelection("ABC");
+
+ // Cut all text (equivalent to ctrl+x) by replacing selection with empty
+ // string
+ FORM_ReplaceSelection(form_handle(), page(), nullptr);
+ CheckFocusedFieldText("");
+ CheckCanUndo(true);
+ CheckCanRedo(false);
+
+ // Undo the cut operation - should restore all 3 characters "ABC"
+ PerformUndo();
+ CheckFocusedFieldText("ABC");
+ CheckCanUndo(true);
+ CheckCanRedo(true);
+}
diff --git a/fpdfsdk/pwl/cpwl_edit_impl.cpp b/fpdfsdk/pwl/cpwl_edit_impl.cpp
index 18aa66d..1a56f9e 100644
--- a/fpdfsdk/pwl/cpwl_edit_impl.cpp
+++ b/fpdfsdk/pwl/cpwl_edit_impl.cpp
@@ -1855,7 +1855,9 @@
bool is_insert_undo_clear = ClearSelection();
// It is necessary to determine whether the value of `undo_remaining_` is 2 or
// 3 based on ClearSelection().
- if (!is_insert_undo_clear) {
+ // Special case: when cutting (clearing selection and inserting empty text),
+ // we need to ensure proper undo counting to restore all characters.
+ if (!is_insert_undo_clear || text.IsEmpty()) {
undo_.GetLastAddItem()->set_undo_remaining(2);
}
// Select the inserted text.
@@ -1865,7 +1867,7 @@
sel_state_.Set(caret_before_insert, caret_after_insert);
AddEditUndoItem(std::make_unique<UndoReplaceSelection>(this, true));
- if (!is_insert_undo_clear) {
+ if (!is_insert_undo_clear || text.IsEmpty()) {
undo_.GetLastAddItem()->set_undo_remaining(2);
}
}
@@ -1875,12 +1877,14 @@
bool is_insert_undo_clear = ClearSelection();
// It is necessary to determine whether the value of `undo_remaining_` is 2 or
// 3 based on ClearSelection().
- if (!is_insert_undo_clear) {
+ // Special case: when cutting (clearing selection and inserting empty text),
+ // we need to ensure proper undo counting to restore all characters.
+ if (!is_insert_undo_clear || text.IsEmpty()) {
undo_.GetLastAddItem()->set_undo_remaining(2);
}
InsertText(text, FX_Charset::kDefault);
AddEditUndoItem(std::make_unique<UndoReplaceSelection>(this, true));
- if (!is_insert_undo_clear) {
+ if (!is_insert_undo_clear || text.IsEmpty()) {
undo_.GetLastAddItem()->set_undo_remaining(2);
}
}