summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Sinclair <dsinclair@chromium.org>2018-05-29 19:42:39 +0000
committerChromium commit bot <commit-bot@chromium.org>2018-05-29 19:42:39 +0000
commit6af5369477ec05554ef9e73ae6762860095f09e9 (patch)
tree0a9d28f4e3f89ca5b141954913169fdff63bf59c
parent162a31a6af1538acf7ac9835111626161287d742 (diff)
downloadpdfium-6af5369477ec05554ef9e73ae6762860095f09e9.tar.xz
[xfa] Propagate the xfa change data for text to JS and back.
This CL adds the necessary plumbing to propagate the change information for a text widget from FWL out to JS and handle the returned value as necessary. Bug: pdfium:1066 Change-Id: I78fd81761b90294f1836e9f09dba12ed238963cc Reviewed-on: https://pdfium-review.googlesource.com/33070 Reviewed-by: Ryan Harrison <rharrison@chromium.org> Commit-Queue: dsinclair <dsinclair@chromium.org>
-rw-r--r--BUILD.gn4
-rw-r--r--fxjs/cfxjse_engine.h7
-rw-r--r--fxjs/cfxjse_formcalc_context_embeddertest.cpp91
-rw-r--r--xfa/fde/cfde_texteditengine.cpp85
-rw-r--r--xfa/fde/cfde_texteditengine.h16
-rw-r--r--xfa/fde/cfde_texteditengine_unittest.cpp3
-rw-r--r--xfa/fwl/README.md2
-rw-r--r--xfa/fwl/cfwl_barcode.cpp7
-rw-r--r--xfa/fwl/cfwl_barcode.h5
-rw-r--r--xfa/fwl/cfwl_combobox.cpp3
-rw-r--r--xfa/fwl/cfwl_edit.cpp29
-rw-r--r--xfa/fwl/cfwl_edit.h7
-rw-r--r--xfa/fwl/cfwl_event.h2
-rw-r--r--xfa/fwl/cfwl_eventtextchanged.cpp12
-rw-r--r--xfa/fwl/cfwl_eventtextchanged.h20
-rw-r--r--xfa/fwl/cfwl_eventtextwillchange.cpp12
-rw-r--r--xfa/fwl/cfwl_eventtextwillchange.h24
-rw-r--r--xfa/fxfa/cxfa_eventparam.cpp2
-rw-r--r--xfa/fxfa/cxfa_fftextedit.cpp48
-rw-r--r--xfa/fxfa/cxfa_fftextedit.h5
-rw-r--r--xfa/fxfa/parser/cxfa_node.cpp3
21 files changed, 239 insertions, 148 deletions
diff --git a/BUILD.gn b/BUILD.gn
index e9f21e0311..5bba3fe352 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1908,8 +1908,8 @@ if (pdf_enable_xfa) {
"xfa/fwl/cfwl_eventselectchanged.h",
"xfa/fwl/cfwl_eventtarget.cpp",
"xfa/fwl/cfwl_eventtarget.h",
- "xfa/fwl/cfwl_eventtextchanged.cpp",
- "xfa/fwl/cfwl_eventtextchanged.h",
+ "xfa/fwl/cfwl_eventtextwillchange.cpp",
+ "xfa/fwl/cfwl_eventtextwillchange.h",
"xfa/fwl/cfwl_eventvalidate.cpp",
"xfa/fwl/cfwl_eventvalidate.h",
"xfa/fwl/cfwl_form.cpp",
diff --git a/fxjs/cfxjse_engine.h b/fxjs/cfxjse_engine.h
index ca5f3ee098..33723ad8a9 100644
--- a/fxjs/cfxjse_engine.h
+++ b/fxjs/cfxjse_engine.h
@@ -11,6 +11,7 @@
#include <memory>
#include <vector>
+#include "core/fxcrt/unowned_ptr.h"
#include "fxjs/cfx_v8.h"
#include "fxjs/cfxjse_formcalc_context.h"
#include "v8/include/v8.h"
@@ -54,8 +55,8 @@ class CFXJSE_Engine : public CFX_V8 {
CFXJSE_Engine(CXFA_Document* pDocument, CFXJS_Engine* fxjs_engine);
~CFXJSE_Engine() override;
- void SetEventParam(CXFA_EventParam param) { m_eventParam = param; }
- CXFA_EventParam* GetEventParam() { return &m_eventParam; }
+ void SetEventParam(CXFA_EventParam* param) { m_eventParam = param; }
+ CXFA_EventParam* GetEventParam() { return m_eventParam.Get(); }
bool RunScript(CXFA_Script::Type eScriptType,
const WideStringView& wsScript,
CFXJSE_Value* pRetValue,
@@ -113,7 +114,7 @@ class CFXJSE_Engine : public CFX_V8 {
std::map<CXFA_Object*, std::unique_ptr<CFXJSE_Value>> m_mapObjectToValue;
std::map<CXFA_Object*, std::unique_ptr<CFXJSE_Context>>
m_mapVariableToContext;
- CXFA_EventParam m_eventParam;
+ UnownedPtr<CXFA_EventParam> m_eventParam;
std::vector<CXFA_Node*> m_upObjectArray;
// CacheList holds the List items so we can clean them up when we're done.
std::vector<std::unique_ptr<CXFA_List>> m_CacheList;
diff --git a/fxjs/cfxjse_formcalc_context_embeddertest.cpp b/fxjs/cfxjse_formcalc_context_embeddertest.cpp
index ed0c5bccc7..a227ac558d 100644
--- a/fxjs/cfxjse_formcalc_context_embeddertest.cpp
+++ b/fxjs/cfxjse_formcalc_context_embeddertest.cpp
@@ -1465,7 +1465,7 @@ TEST_F(CFXJSE_FormCalcContextEmbedderTest, GetXFAEventChange) {
params.m_wsChange = L"changed";
CFXJSE_Engine* context = GetScriptContext();
- context->SetEventParam(params);
+ context->SetEventParam(&params);
const char test[] = {"xfa.event.change"};
EXPECT_TRUE(Execute(test));
@@ -1473,6 +1473,7 @@ TEST_F(CFXJSE_FormCalcContextEmbedderTest, GetXFAEventChange) {
CFXJSE_Value* value = GetValue();
EXPECT_TRUE(value->IsString());
EXPECT_STREQ("changed", value->ToString().c_str());
+ context->SetEventParam(nullptr);
}
TEST_F(CFXJSE_FormCalcContextEmbedderTest, SetXFAEventChange) {
@@ -1480,11 +1481,12 @@ TEST_F(CFXJSE_FormCalcContextEmbedderTest, SetXFAEventChange) {
CXFA_EventParam params;
CFXJSE_Engine* context = GetScriptContext();
- context->SetEventParam(params);
+ context->SetEventParam(&params);
const char test[] = {"xfa.event.change = \"changed\""};
EXPECT_TRUE(Execute(test));
- EXPECT_EQ(L"changed", context->GetEventParam()->m_wsChange);
+ EXPECT_EQ(L"changed", params.m_wsChange);
+ context->SetEventParam(nullptr);
}
TEST_F(CFXJSE_FormCalcContextEmbedderTest, SetXFAEventFullTextFails) {
@@ -1494,11 +1496,12 @@ TEST_F(CFXJSE_FormCalcContextEmbedderTest, SetXFAEventFullTextFails) {
params.m_wsFullText = L"Original Full Text";
CFXJSE_Engine* context = GetScriptContext();
- context->SetEventParam(params);
+ context->SetEventParam(&params);
const char test[] = {"xfa.event.fullText = \"Changed Full Text\""};
EXPECT_TRUE(Execute(test));
- EXPECT_EQ(L"Original Full Text", context->GetEventParam()->m_wsFullText);
+ EXPECT_EQ(L"Original Full Text", params.m_wsFullText);
+ context->SetEventParam(nullptr);
}
TEST_F(CFXJSE_FormCalcContextEmbedderTest, EventChangeSelection) {
@@ -1510,49 +1513,51 @@ TEST_F(CFXJSE_FormCalcContextEmbedderTest, EventChangeSelection) {
params.m_iSelEnd = 3;
CFXJSE_Engine* context = GetScriptContext();
- context->SetEventParam(params);
+ context->SetEventParam(&params);
// Moving end to start works fine.
EXPECT_TRUE(Execute("xfa.event.selEnd = \"1\""));
- EXPECT_EQ(1, context->GetEventParam()->m_iSelStart);
- EXPECT_EQ(1, context->GetEventParam()->m_iSelEnd);
+ EXPECT_EQ(1, params.m_iSelStart);
+ EXPECT_EQ(1, params.m_iSelEnd);
// Moving end before end, forces start to move in response.
EXPECT_TRUE(Execute("xfa.event.selEnd = \"0\""));
- EXPECT_EQ(0, context->GetEventParam()->m_iSelStart);
- EXPECT_EQ(0, context->GetEventParam()->m_iSelEnd);
+ EXPECT_EQ(0, params.m_iSelStart);
+ EXPECT_EQ(0, params.m_iSelEnd);
// Negatives not allowed
EXPECT_TRUE(Execute("xfa.event.selEnd = \"-1\""));
- EXPECT_EQ(0, context->GetEventParam()->m_iSelStart);
- EXPECT_EQ(0, context->GetEventParam()->m_iSelEnd);
+ EXPECT_EQ(0, params.m_iSelStart);
+ EXPECT_EQ(0, params.m_iSelEnd);
// Negatives not allowed
EXPECT_TRUE(Execute("xfa.event.selStart = \"-1\""));
- EXPECT_EQ(0, context->GetEventParam()->m_iSelStart);
- EXPECT_EQ(0, context->GetEventParam()->m_iSelEnd);
+ EXPECT_EQ(0, params.m_iSelStart);
+ EXPECT_EQ(0, params.m_iSelEnd);
- context->GetEventParam()->m_iSelEnd = 1;
+ params.m_iSelEnd = 1;
// Moving start to end works fine.
EXPECT_TRUE(Execute("xfa.event.selStart = \"1\""));
- EXPECT_EQ(1, context->GetEventParam()->m_iSelStart);
- EXPECT_EQ(1, context->GetEventParam()->m_iSelEnd);
+ EXPECT_EQ(1, params.m_iSelStart);
+ EXPECT_EQ(1, params.m_iSelEnd);
// Moving start after end moves end.
EXPECT_TRUE(Execute("xfa.event.selStart = \"2\""));
- EXPECT_EQ(2, context->GetEventParam()->m_iSelStart);
- EXPECT_EQ(2, context->GetEventParam()->m_iSelEnd);
+ EXPECT_EQ(2, params.m_iSelStart);
+ EXPECT_EQ(2, params.m_iSelEnd);
// Setting End past end of string clamps to string length;
EXPECT_TRUE(Execute("xfa.event.selEnd = \"20\""));
- EXPECT_EQ(2, context->GetEventParam()->m_iSelStart);
- EXPECT_EQ(4, context->GetEventParam()->m_iSelEnd);
+ EXPECT_EQ(2, params.m_iSelStart);
+ EXPECT_EQ(4, params.m_iSelEnd);
// Setting Start past end of string clamps to string length;
EXPECT_TRUE(Execute("xfa.event.selStart = \"20\""));
- EXPECT_EQ(4, context->GetEventParam()->m_iSelStart);
- EXPECT_EQ(4, context->GetEventParam()->m_iSelEnd);
+ EXPECT_EQ(4, params.m_iSelStart);
+ EXPECT_EQ(4, params.m_iSelEnd);
+
+ context->SetEventParam(nullptr);
}
TEST_F(CFXJSE_FormCalcContextEmbedderTest, XFAEventCancelAction) {
@@ -1562,7 +1567,7 @@ TEST_F(CFXJSE_FormCalcContextEmbedderTest, XFAEventCancelAction) {
params.m_bCancelAction = false;
CFXJSE_Engine* context = GetScriptContext();
- context->SetEventParam(params);
+ context->SetEventParam(&params);
EXPECT_TRUE(Execute("xfa.event.cancelAction"));
@@ -1571,7 +1576,9 @@ TEST_F(CFXJSE_FormCalcContextEmbedderTest, XFAEventCancelAction) {
EXPECT_FALSE(value->ToBoolean());
EXPECT_TRUE(Execute("xfa.event.cancelAction = \"true\""));
- EXPECT_TRUE(context->GetEventParam()->m_bCancelAction);
+ EXPECT_TRUE(params.m_bCancelAction);
+
+ context->SetEventParam(nullptr);
}
TEST_F(CFXJSE_FormCalcContextEmbedderTest, ComplexTextChangeEvent) {
@@ -1584,29 +1591,31 @@ TEST_F(CFXJSE_FormCalcContextEmbedderTest, ComplexTextChangeEvent) {
params.m_iSelEnd = 3;
CFXJSE_Engine* context = GetScriptContext();
- context->SetEventParam(params);
+ context->SetEventParam(&params);
- EXPECT_EQ(L"abcd", context->GetEventParam()->m_wsPrevText);
- EXPECT_EQ(L"agd", context->GetEventParam()->GetNewText());
- EXPECT_EQ(L"g", context->GetEventParam()->m_wsChange);
- EXPECT_EQ(1, context->GetEventParam()->m_iSelStart);
- EXPECT_EQ(3, context->GetEventParam()->m_iSelEnd);
+ EXPECT_EQ(L"abcd", params.m_wsPrevText);
+ EXPECT_EQ(L"agd", params.GetNewText());
+ EXPECT_EQ(L"g", params.m_wsChange);
+ EXPECT_EQ(1, params.m_iSelStart);
+ EXPECT_EQ(3, params.m_iSelEnd);
const char change_event[] = {"xfa.event.change = \"xyz\""};
EXPECT_TRUE(Execute(change_event));
- EXPECT_EQ(L"abcd", context->GetEventParam()->m_wsPrevText);
- EXPECT_EQ(L"xyz", context->GetEventParam()->m_wsChange);
- EXPECT_EQ(L"axyzd", context->GetEventParam()->GetNewText());
- EXPECT_EQ(1, context->GetEventParam()->m_iSelStart);
- EXPECT_EQ(3, context->GetEventParam()->m_iSelEnd);
+ EXPECT_EQ(L"abcd", params.m_wsPrevText);
+ EXPECT_EQ(L"xyz", params.m_wsChange);
+ EXPECT_EQ(L"axyzd", params.GetNewText());
+ EXPECT_EQ(1, params.m_iSelStart);
+ EXPECT_EQ(3, params.m_iSelEnd);
const char sel_event[] = {"xfa.event.selEnd = \"1\""};
EXPECT_TRUE(Execute(sel_event));
- EXPECT_EQ(L"abcd", context->GetEventParam()->m_wsPrevText);
- EXPECT_EQ(L"xyz", context->GetEventParam()->m_wsChange);
- EXPECT_EQ(L"axyzbcd", context->GetEventParam()->GetNewText());
- EXPECT_EQ(1, context->GetEventParam()->m_iSelStart);
- EXPECT_EQ(1, context->GetEventParam()->m_iSelEnd);
+ EXPECT_EQ(L"abcd", params.m_wsPrevText);
+ EXPECT_EQ(L"xyz", params.m_wsChange);
+ EXPECT_EQ(L"axyzbcd", params.GetNewText());
+ EXPECT_EQ(1, params.m_iSelStart);
+ EXPECT_EQ(1, params.m_iSelEnd);
+
+ context->SetEventParam(nullptr);
}
diff --git a/xfa/fde/cfde_texteditengine.cpp b/xfa/fde/cfde_texteditengine.cpp
index 3363baa0cd..cfe844e656 100644
--- a/xfa/fde/cfde_texteditengine.cpp
+++ b/xfa/fde/cfde_texteditengine.cpp
@@ -262,11 +262,35 @@ size_t CFDE_TextEditEngine::CountCharsExceedingSize(const WideString& text,
}
void CFDE_TextEditEngine::Insert(size_t idx,
- const WideString& text,
+ const WideString& request_text,
RecordOperation add_operation) {
+ WideString text = request_text;
+ if (text.GetLength() == 0)
+ return;
if (idx > text_length_)
idx = text_length_;
+ TextChange change;
+ change.selection_start = idx;
+ change.selection_end = idx;
+ change.text = text;
+ change.previous_text = GetText();
+ change.cancelled = false;
+
+ if (delegate_ && (add_operation != RecordOperation::kSkipRecord &&
+ add_operation != RecordOperation::kSkipNotify)) {
+ delegate_->OnTextWillChange(&change);
+ if (change.cancelled)
+ return;
+
+ text = change.text;
+ idx = change.selection_start;
+
+ // JS extended the selection, so delete it before we insert.
+ if (change.selection_end != change.selection_start)
+ DeleteSelectedText(RecordOperation::kSkipRecord);
+ }
+
size_t length = text.GetLength();
if (length == 0)
return;
@@ -276,11 +300,11 @@ void CFDE_TextEditEngine::Insert(size_t idx,
bool exceeded_limit = false;
// Currently we allow inserting a number of characters over the text limit if
- // the text edit is already empty. This allows supporting text fields which
- // do formatting. Otherwise, if you enter 123456789 for an SSN into a field
+ // we're skipping notify. This means we're setting the formatted text into the
+ // engine. Otherwise, if you enter 123456789 for an SSN into a field
// with a 9 character limit and we reformat to 123-45-6789 we'll truncate
// the 89 when inserting into the text edit. See https://crbug.com/pdfium/1089
- if (has_character_limit_ && text_length_ > 0 &&
+ if (has_character_limit_ && add_operation != RecordOperation::kSkipNotify &&
text_length_ + length > character_limit_) {
exceeded_limit = true;
length = character_limit_ - text_length_;
@@ -348,7 +372,7 @@ void CFDE_TextEditEngine::Insert(size_t idx,
if (exceeded_limit)
delegate_->NotifyTextFull();
- delegate_->OnTextChanged(previous_text);
+ delegate_->OnTextChanged();
}
}
@@ -811,6 +835,23 @@ WideString CFDE_TextEditEngine::Delete(size_t start_idx,
if (start_idx >= text_length_)
return L"";
+ TextChange change;
+ change.text = L"";
+ change.cancelled = false;
+ if (delegate_ && (add_operation != RecordOperation::kSkipRecord &&
+ add_operation != RecordOperation::kSkipNotify)) {
+ change.previous_text = GetText();
+ change.selection_start = start_idx;
+ change.selection_end = start_idx + length;
+
+ delegate_->OnTextWillChange(&change);
+ if (change.cancelled)
+ return L"";
+
+ start_idx = change.selection_start;
+ length = change.selection_end - change.selection_start;
+ }
+
length = std::min(length, text_length_ - start_idx);
AdjustGap(start_idx + length, 0);
@@ -831,15 +872,37 @@ WideString CFDE_TextEditEngine::Delete(size_t start_idx,
is_dirty_ = true;
ClearSelection();
+ // The JS requested the insertion of text instead of just a deletion.
+ if (change.text != L"")
+ Insert(start_idx, change.text, RecordOperation::kSkipRecord);
+
if (delegate_)
- delegate_->OnTextChanged(previous_text);
+ delegate_->OnTextChanged();
return ret;
}
-void CFDE_TextEditEngine::ReplaceSelectedText(const WideString& rep) {
- size_t start_idx = selection_.start_idx;
+void CFDE_TextEditEngine::ReplaceSelectedText(const WideString& requested_rep) {
+ WideString rep = requested_rep;
+
+ if (delegate_) {
+ TextChange change;
+ change.selection_start = selection_.start_idx;
+ change.selection_end = selection_.start_idx + selection_.count;
+ change.text = rep;
+ change.previous_text = GetText();
+ change.cancelled = false;
+
+ delegate_->OnTextWillChange(&change);
+ if (change.cancelled)
+ return;
+
+ rep = change.text;
+ selection_.start_idx = change.selection_start;
+ selection_.count = change.selection_end - change.selection_start;
+ }
+ size_t start_idx = selection_.start_idx;
WideString txt = DeleteSelectedText(RecordOperation::kSkipRecord);
Insert(gap_position_, rep, RecordOperation::kSkipRecord);
@@ -1079,13 +1142,7 @@ void CFDE_TextEditEngine::RebuildPieces() {
if (IsAlignedRight() && bounds_smaller) {
delta = available_width_ - contents_bounding_box_.width;
} else if (IsAlignedCenter() && bounds_smaller) {
- // TODO(dsinclair): Old code used CombText here and set the space to
- // something unrelated to the available width .... Figure out if this is
- // needed and what it should do.
- // if (is_comb_text_) {
- // } else {
delta = (available_width_ - contents_bounding_box_.width) / 2.0f;
- // }
}
if (delta != 0.0) {
diff --git a/xfa/fde/cfde_texteditengine.h b/xfa/fde/cfde_texteditengine.h
index 58f77edf31..868be8866a 100644
--- a/xfa/fde/cfde_texteditengine.h
+++ b/xfa/fde/cfde_texteditengine.h
@@ -61,21 +61,27 @@ class CFDE_TextEditEngine {
virtual void Undo() const = 0;
};
+ struct TextChange {
+ WideString text;
+ WideString previous_text;
+ size_t selection_start;
+ size_t selection_end;
+ bool cancelled;
+ };
+
class Delegate {
public:
virtual ~Delegate() = default;
virtual void NotifyTextFull() = 0;
virtual void OnCaretChanged() = 0;
- virtual void OnTextChanged(const WideString& prevText) = 0;
+ virtual void OnTextWillChange(TextChange* change) = 0;
+ virtual void OnTextChanged() = 0;
virtual void OnSelChanged() = 0;
virtual bool OnValidate(const WideString& wsText) = 0;
virtual void SetScrollOffset(float fScrollOffset) = 0;
};
- enum class RecordOperation {
- kInsertRecord,
- kSkipRecord,
- };
+ enum class RecordOperation { kInsertRecord, kSkipRecord, kSkipNotify };
CFDE_TextEditEngine();
~CFDE_TextEditEngine();
diff --git a/xfa/fde/cfde_texteditengine_unittest.cpp b/xfa/fde/cfde_texteditengine_unittest.cpp
index 123d16ce4b..c5efe529e6 100644
--- a/xfa/fde/cfde_texteditengine_unittest.cpp
+++ b/xfa/fde/cfde_texteditengine_unittest.cpp
@@ -21,7 +21,8 @@ class CFDE_TextEditEngineTest : public testing::Test {
void NotifyTextFull() override { text_is_full = true; }
void OnCaretChanged() override {}
- void OnTextChanged(const WideString& prevText) override {}
+ void OnTextWillChange(CFDE_TextEditEngine::TextChange* change) override {}
+ void OnTextChanged() override {}
void OnSelChanged() override {}
bool OnValidate(const WideString& wsText) override {
return !fail_validation;
diff --git a/xfa/fwl/README.md b/xfa/fwl/README.md
index 95a0f4c92a..6460ff1fae 100644
--- a/xfa/fwl/README.md
+++ b/xfa/fwl/README.md
@@ -46,7 +46,7 @@ and CXFA classes.
* CFWL_EventMouse
* CFWL_EventScroll
* CFWL_EventSelectChanged
- * CFWL_EventTextChanged
+ * CFWL_EventTextWillChange
* CFWL_EventValidate
The widgets use IFWL_ThemeProvider for rendering everything, calling
diff --git a/xfa/fwl/cfwl_barcode.cpp b/xfa/fwl/cfwl_barcode.cpp
index 74ac7dd9c2..649dea0c8e 100644
--- a/xfa/fwl/cfwl_barcode.cpp
+++ b/xfa/fwl/cfwl_barcode.cpp
@@ -67,10 +67,11 @@ void CFWL_Barcode::SetType(BC_TYPE type) {
m_dwStatus = XFA_BCS_NeedUpdate;
}
-void CFWL_Barcode::SetText(const WideString& wsText) {
+void CFWL_Barcode::SetText(const WideString& wsText,
+ CFDE_TextEditEngine::RecordOperation op) {
m_pBarcodeEngine.reset();
m_dwStatus = XFA_BCS_NeedUpdate;
- CFWL_Edit::SetText(wsText);
+ CFWL_Edit::SetText(wsText, op);
}
bool CFWL_Barcode::IsProtectedType() const {
@@ -86,7 +87,7 @@ bool CFWL_Barcode::IsProtectedType() const {
}
void CFWL_Barcode::OnProcessEvent(CFWL_Event* pEvent) {
- if (pEvent->GetType() == CFWL_Event::Type::TextChanged) {
+ if (pEvent->GetType() == CFWL_Event::Type::TextWillChange) {
m_pBarcodeEngine.reset();
m_dwStatus = XFA_BCS_NeedUpdate;
}
diff --git a/xfa/fwl/cfwl_barcode.h b/xfa/fwl/cfwl_barcode.h
index 2fc79608b3..58484dfba1 100644
--- a/xfa/fwl/cfwl_barcode.h
+++ b/xfa/fwl/cfwl_barcode.h
@@ -49,7 +49,10 @@ class CFWL_Barcode : public CFWL_Edit {
void OnProcessEvent(CFWL_Event* pEvent) override;
// CFWL_Edit
- void SetText(const WideString& wsText) override;
+ void SetText(
+ const WideString& wsText,
+ CFDE_TextEditEngine::RecordOperation op =
+ CFDE_TextEditEngine::RecordOperation::kInsertRecord) override;
void SetType(BC_TYPE type);
bool IsProtectedType() const;
diff --git a/xfa/fwl/cfwl_combobox.cpp b/xfa/fwl/cfwl_combobox.cpp
index 8980dc312c..9cd2119aaf 100644
--- a/xfa/fwl/cfwl_combobox.cpp
+++ b/xfa/fwl/cfwl_combobox.cpp
@@ -16,7 +16,6 @@
#include "xfa/fwl/cfwl_app.h"
#include "xfa/fwl/cfwl_event.h"
#include "xfa/fwl/cfwl_eventselectchanged.h"
-#include "xfa/fwl/cfwl_eventtextchanged.h"
#include "xfa/fwl/cfwl_listbox.h"
#include "xfa/fwl/cfwl_messagekey.h"
#include "xfa/fwl/cfwl_messagekillfocus.h"
@@ -505,7 +504,7 @@ void CFWL_ComboBox::OnProcessEvent(CFWL_Event* pEvent) {
pScrollEv.m_iScrollCode = pScrollEvent->m_iScrollCode;
pScrollEv.m_fPos = pScrollEvent->m_fPos;
DispatchEvent(&pScrollEv);
- } else if (type == CFWL_Event::Type::TextChanged) {
+ } else if (type == CFWL_Event::Type::TextWillChange) {
CFWL_Event pTemp(CFWL_Event::Type::EditChanged, this);
DispatchEvent(&pTemp);
}
diff --git a/xfa/fwl/cfwl_edit.cpp b/xfa/fwl/cfwl_edit.cpp
index 7bdb818192..7c4f0e1607 100644
--- a/xfa/fwl/cfwl_edit.cpp
+++ b/xfa/fwl/cfwl_edit.cpp
@@ -19,7 +19,7 @@
#include "xfa/fwl/cfwl_app.h"
#include "xfa/fwl/cfwl_caret.h"
#include "xfa/fwl/cfwl_event.h"
-#include "xfa/fwl/cfwl_eventtextchanged.h"
+#include "xfa/fwl/cfwl_eventtextwillchange.h"
#include "xfa/fwl/cfwl_eventvalidate.h"
#include "xfa/fwl/cfwl_messagekey.h"
#include "xfa/fwl/cfwl_messagemouse.h"
@@ -171,9 +171,10 @@ void CFWL_Edit::SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) {
m_pProperties->m_pThemeProvider = pThemeProvider;
}
-void CFWL_Edit::SetText(const WideString& wsText) {
+void CFWL_Edit::SetText(const WideString& wsText,
+ CFDE_TextEditEngine::RecordOperation op) {
m_EdtEngine.Clear();
- m_EdtEngine.Insert(0, wsText);
+ m_EdtEngine.Insert(0, wsText, op);
}
int32_t CFWL_Edit::GetTextLength() const {
@@ -297,14 +298,26 @@ void CFWL_Edit::OnCaretChanged() {
}
}
-void CFWL_Edit::OnTextChanged(const WideString& prevText) {
- if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VAlignMask)
- UpdateVAlignment();
+void CFWL_Edit::OnTextWillChange(CFDE_TextEditEngine::TextChange* change) {
+ CFWL_EventTextWillChange event(this);
+ event.previous_text = change->previous_text;
+ event.change_text = change->text;
+ event.selection_start = change->selection_start;
+ event.selection_end = change->selection_end;
+ event.cancelled = false;
- CFWL_EventTextChanged event(this);
- event.wsPrevText = prevText;
DispatchEvent(&event);
+ change->text = event.change_text;
+ change->selection_start = event.selection_start;
+ change->selection_end = event.selection_end;
+ change->cancelled = event.cancelled;
+}
+
+void CFWL_Edit::OnTextChanged() {
+ if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VAlignMask)
+ UpdateVAlignment();
+
LayoutScrollBar();
RepaintRect(GetClientRect());
}
diff --git a/xfa/fwl/cfwl_edit.h b/xfa/fwl/cfwl_edit.h
index 894315de82..634ac225ad 100644
--- a/xfa/fwl/cfwl_edit.h
+++ b/xfa/fwl/cfwl_edit.h
@@ -65,7 +65,9 @@ class CFWL_Edit : public CFWL_Widget, public CFDE_TextEditEngine::Delegate {
void OnDrawWidget(CXFA_Graphics* pGraphics,
const CFX_Matrix& matrix) override;
- virtual void SetText(const WideString& wsText);
+ virtual void SetText(const WideString& wsText,
+ CFDE_TextEditEngine::RecordOperation op =
+ CFDE_TextEditEngine::RecordOperation::kInsertRecord);
int32_t GetTextLength() const;
WideString GetText() const;
@@ -93,7 +95,8 @@ class CFWL_Edit : public CFWL_Widget, public CFDE_TextEditEngine::Delegate {
// CFDE_TextEditEngine::Delegate
void NotifyTextFull() override;
void OnCaretChanged() override;
- void OnTextChanged(const WideString& prevText) override;
+ void OnTextWillChange(CFDE_TextEditEngine::TextChange* change) override;
+ void OnTextChanged() override;
void OnSelChanged() override;
bool OnValidate(const WideString& wsText) override;
void SetScrollOffset(float fScrollOffset) override;
diff --git a/xfa/fwl/cfwl_event.h b/xfa/fwl/cfwl_event.h
index 787f8c2640..8546447209 100644
--- a/xfa/fwl/cfwl_event.h
+++ b/xfa/fwl/cfwl_event.h
@@ -28,7 +28,7 @@ class CFWL_Event {
PreDropDown,
Scroll,
SelectChanged,
- TextChanged,
+ TextWillChange,
TextFull,
Validate
};
diff --git a/xfa/fwl/cfwl_eventtextchanged.cpp b/xfa/fwl/cfwl_eventtextchanged.cpp
deleted file mode 100644
index 439d99d927..0000000000
--- a/xfa/fwl/cfwl_eventtextchanged.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2016 PDFium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-
-#include "xfa/fwl/cfwl_eventtextchanged.h"
-
-CFWL_EventTextChanged::CFWL_EventTextChanged(CFWL_Widget* pSrcTarget)
- : CFWL_Event(CFWL_Event::Type::TextChanged, pSrcTarget) {}
-
-CFWL_EventTextChanged::~CFWL_EventTextChanged() {}
diff --git a/xfa/fwl/cfwl_eventtextchanged.h b/xfa/fwl/cfwl_eventtextchanged.h
deleted file mode 100644
index 4494f08075..0000000000
--- a/xfa/fwl/cfwl_eventtextchanged.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2016 PDFium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
-
-#ifndef XFA_FWL_CFWL_EVENTTEXTCHANGED_H_
-#define XFA_FWL_CFWL_EVENTTEXTCHANGED_H_
-
-#include "xfa/fwl/cfwl_event.h"
-
-class CFWL_EventTextChanged : public CFWL_Event {
- public:
- explicit CFWL_EventTextChanged(CFWL_Widget* pSrcTarget);
- ~CFWL_EventTextChanged() override;
-
- WideString wsPrevText;
-};
-
-#endif // XFA_FWL_CFWL_EVENTTEXTCHANGED_H_
diff --git a/xfa/fwl/cfwl_eventtextwillchange.cpp b/xfa/fwl/cfwl_eventtextwillchange.cpp
new file mode 100644
index 0000000000..22b1100f59
--- /dev/null
+++ b/xfa/fwl/cfwl_eventtextwillchange.cpp
@@ -0,0 +1,12 @@
+// Copyright 2016 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "xfa/fwl/cfwl_eventtextwillchange.h"
+
+CFWL_EventTextWillChange::CFWL_EventTextWillChange(CFWL_Widget* pSrcTarget)
+ : CFWL_Event(CFWL_Event::Type::TextWillChange, pSrcTarget) {}
+
+CFWL_EventTextWillChange::~CFWL_EventTextWillChange() = default;
diff --git a/xfa/fwl/cfwl_eventtextwillchange.h b/xfa/fwl/cfwl_eventtextwillchange.h
new file mode 100644
index 0000000000..4b2781f0d1
--- /dev/null
+++ b/xfa/fwl/cfwl_eventtextwillchange.h
@@ -0,0 +1,24 @@
+// Copyright 2016 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef XFA_FWL_CFWL_EVENTTEXTWILLCHANGE_H_
+#define XFA_FWL_CFWL_EVENTTEXTWILLCHANGE_H_
+
+#include "xfa/fwl/cfwl_event.h"
+
+class CFWL_EventTextWillChange : public CFWL_Event {
+ public:
+ explicit CFWL_EventTextWillChange(CFWL_Widget* pSrcTarget);
+ ~CFWL_EventTextWillChange() override;
+
+ WideString change_text;
+ WideString previous_text;
+ bool cancelled = false;
+ size_t selection_start = 0;
+ size_t selection_end = 0;
+};
+
+#endif // XFA_FWL_CFWL_EVENTTEXTWILLCHANGE_H_
diff --git a/xfa/fxfa/cxfa_eventparam.cpp b/xfa/fxfa/cxfa_eventparam.cpp
index 4e3cae9d1d..4746a6ad86 100644
--- a/xfa/fxfa/cxfa_eventparam.cpp
+++ b/xfa/fxfa/cxfa_eventparam.cpp
@@ -21,7 +21,7 @@ CXFA_EventParam::CXFA_EventParam()
m_bShift(false),
m_bIsFormReady(false) {}
-CXFA_EventParam::~CXFA_EventParam() {}
+CXFA_EventParam::~CXFA_EventParam() = default;
CXFA_EventParam::CXFA_EventParam(const CXFA_EventParam& other) = default;
diff --git a/xfa/fxfa/cxfa_fftextedit.cpp b/xfa/fxfa/cxfa_fftextedit.cpp
index 02787d579b..a8080d13d5 100644
--- a/xfa/fxfa/cxfa_fftextedit.cpp
+++ b/xfa/fxfa/cxfa_fftextedit.cpp
@@ -11,7 +11,7 @@
#include "xfa/fwl/cfwl_datetimepicker.h"
#include "xfa/fwl/cfwl_edit.h"
#include "xfa/fwl/cfwl_eventtarget.h"
-#include "xfa/fwl/cfwl_eventtextchanged.h"
+#include "xfa/fwl/cfwl_eventtextwillchange.h"
#include "xfa/fwl/cfwl_messagekillfocus.h"
#include "xfa/fwl/cfwl_messagesetfocus.h"
#include "xfa/fwl/cfwl_notedriver.h"
@@ -287,7 +287,7 @@ bool CXFA_FFTextEdit::UpdateFWLData() {
WideString wsText = m_pNode->GetValue(eType);
WideString wsOldText = pEdit->GetText();
if (wsText != wsOldText || (eType == XFA_VALUEPICTURE_Edit && bUpdate)) {
- pEdit->SetText(wsText);
+ pEdit->SetText(wsText, CFDE_TextEditEngine::RecordOperation::kSkipNotify);
bUpdate = true;
}
if (bUpdate)
@@ -296,28 +296,26 @@ bool CXFA_FFTextEdit::UpdateFWLData() {
return true;
}
-void CXFA_FFTextEdit::OnTextChanged(CFWL_Widget* pWidget,
- const WideString& wsChanged,
- const WideString& wsPrevText) {
+void CXFA_FFTextEdit::OnTextWillChange(CFWL_Widget* pWidget,
+ CFWL_EventTextWillChange* event) {
m_dwStatus |= XFA_WidgetStatus_TextEditValueChanged;
+
CXFA_EventParam eParam;
eParam.m_eType = XFA_EVENT_Change;
- eParam.m_wsChange = wsChanged;
+ eParam.m_wsChange = event->change_text;
eParam.m_pTarget = m_pNode.Get();
- eParam.m_wsPrevText = wsPrevText;
- if (m_pNode->GetFFWidgetType() == XFA_FFWidgetType::kDateTimeEdit) {
- auto* pDateTime = static_cast<CFWL_DateTimePicker*>(m_pNormalWidget.get());
- if (pDateTime->HasSelection()) {
- size_t count;
- std::tie(eParam.m_iSelStart, count) = pDateTime->GetSelection();
- eParam.m_iSelEnd = eParam.m_iSelStart + count;
- }
- } else {
- CFWL_Edit* pEdit = ToEdit(m_pNormalWidget.get());
- if (pEdit->HasSelection())
- std::tie(eParam.m_iSelStart, eParam.m_iSelEnd) = pEdit->GetSelection();
- }
+ eParam.m_wsPrevText = event->previous_text;
+ eParam.m_iSelStart = static_cast<int32_t>(event->selection_start);
+ eParam.m_iSelEnd = static_cast<int32_t>(event->selection_end);
+
m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Change, &eParam);
+
+ // Copy the data back out of the EventParam and into the TextChanged event so
+ // it can propagate back to the calling widget.
+ event->cancelled = eParam.m_bCancelAction;
+ event->change_text = eParam.m_wsChange;
+ event->selection_start = static_cast<size_t>(eParam.m_iSelStart);
+ event->selection_end = static_cast<size_t>(eParam.m_iSelEnd);
}
void CXFA_FFTextEdit::OnTextFull(CFWL_Widget* pWidget) {
@@ -334,17 +332,13 @@ void CXFA_FFTextEdit::OnProcessMessage(CFWL_Message* pMessage) {
void CXFA_FFTextEdit::OnProcessEvent(CFWL_Event* pEvent) {
CXFA_FFField::OnProcessEvent(pEvent);
switch (pEvent->GetType()) {
- case CFWL_Event::Type::TextChanged: {
- CFWL_EventTextChanged* event =
- static_cast<CFWL_EventTextChanged*>(pEvent);
- WideString wsChange;
- OnTextChanged(m_pNormalWidget.get(), wsChange, event->wsPrevText);
+ case CFWL_Event::Type::TextWillChange:
+ OnTextWillChange(m_pNormalWidget.get(),
+ static_cast<CFWL_EventTextWillChange*>(pEvent));
break;
- }
- case CFWL_Event::Type::TextFull: {
+ case CFWL_Event::Type::TextFull:
OnTextFull(m_pNormalWidget.get());
break;
- }
default:
break;
}
diff --git a/xfa/fxfa/cxfa_fftextedit.h b/xfa/fxfa/cxfa_fftextedit.h
index 7c19444ae6..9b61373df9 100644
--- a/xfa/fxfa/cxfa_fftextedit.h
+++ b/xfa/fxfa/cxfa_fftextedit.h
@@ -12,6 +12,7 @@
#include "xfa/fxfa/cxfa_fffield.h"
class CFWL_Event;
+class CFWL_EventTextWillChange;
class CFWL_Widget;
class CFX_Matrix;
class CXFA_FFWidget;
@@ -38,9 +39,7 @@ class CXFA_FFTextEdit : public CXFA_FFField {
void OnDrawWidget(CXFA_Graphics* pGraphics,
const CFX_Matrix& matrix) override;
- void OnTextChanged(CFWL_Widget* pWidget,
- const WideString& wsChanged,
- const WideString& wsPrevText);
+ void OnTextWillChange(CFWL_Widget* pWidget, CFWL_EventTextWillChange* change);
void OnTextFull(CFWL_Widget* pWidget);
// CXFA_FFWidget
diff --git a/xfa/fxfa/parser/cxfa_node.cpp b/xfa/fxfa/parser/cxfa_node.cpp
index 66c4fb99f4..6672e7fb29 100644
--- a/xfa/fxfa/parser/cxfa_node.cpp
+++ b/xfa/fxfa/parser/cxfa_node.cpp
@@ -2290,7 +2290,7 @@ std::pair<int32_t, bool> CXFA_Node::ExecuteBoolScript(
CXFA_FFDoc* pDoc = docView->GetDoc();
CFXJSE_Engine* pContext = pDoc->GetXFADoc()->GetScriptContext();
- pContext->SetEventParam(*pEventParam);
+ pContext->SetEventParam(pEventParam);
pContext->SetRunAtType(script->GetRunAt());
std::vector<CXFA_Node*> refNodes;
@@ -2344,6 +2344,7 @@ std::pair<int32_t, bool> CXFA_Node::ExecuteBoolScript(
}
}
pContext->SetNodesOfRunScript(nullptr);
+ pContext->SetEventParam(nullptr);
return {iRet, pTmpRetValue->IsBoolean() ? pTmpRetValue->ToBoolean() : false};
}