Retain layout item in a few more places where text changes.
Although these methods are not explicitly called On*(), they have
the same inplications for triggering callbacks.
Bug: chromium:1055869
Change-Id: I6bb8f31bf94cf414e14b09201a3f58340b260866
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/67170
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 18851c0..de891f7 100644
--- a/fpdfsdk/fpdf_formfill_embeddertest.cpp
+++ b/fpdfsdk/fpdf_formfill_embeddertest.cpp
@@ -2553,3 +2553,20 @@
CheckCanUndo(true);
CheckCanRedo(false);
}
+
+class FPDFXFAFormEmbedderTest : public FPDFFormFillInteractiveEmbedderTest {
+ protected:
+ FPDFXFAFormEmbedderTest() = default;
+ ~FPDFXFAFormEmbedderTest() override = default;
+
+ const char* GetDocumentName() const override { return "bug_1055869.pdf"; }
+
+ int GetFormType() const override { return FORMTYPE_XFA_FULL; }
+};
+
+TEST_F(FPDFXFAFormEmbedderTest, Paste) {
+ CFX_PointF where(100, 100);
+ ScopedFPDFWideString text_to_insert = GetFPDFWideString(L"XYZ");
+ DoubleClickOnFormFieldAtPoint(where);
+ FORM_ReplaceSelection(form_handle(), page(), text_to_insert.get());
+}
diff --git a/testing/resources/bug_1055869.in b/testing/resources/bug_1055869.in
new file mode 100644
index 0000000..26cbf5f
--- /dev/null
+++ b/testing/resources/bug_1055869.in
@@ -0,0 +1,62 @@
+{{header}}
+{{include xfa_catalog_1_0.fragment}}
+{{include xfa_object_2_0.fragment}}
+{{include xfa_preamble_3_0.fragment}}
+{{include xfa_config_4_0.fragment}}
+{{object 5 0}} <<
+ {{streamlen}}
+>>
+stream
+<template xmlns="http://www.xfa.org/schema/xfa-template/2.6/">
+ <subform layout="tb" locale="en_US" name="form1" restoreState="auto">
+ <pageSet>
+ <pageArea id="Page1" name="Page1">
+ <contentArea h="10.5in" w="8in" x="0.25in" y="0.25in"/>
+ <medium long="11in" short="8.5in" stock="letter"/>
+ </pageArea>
+ </pageSet>
+ <subform h="10.5in" w="8in" name="subform2">
+ <field h="10mm" name="choiceList0" w="50mm" x="5mm" y="50mm">
+ <ui>
+ <choiceList/>
+ </ui>
+ <items>
+ <text>Single</text>
+ </items>
+ </field>
+ <field name="choiceList1" h="200mm" w="200mm" x="1mm" y="1mm">
+ <ui>
+ <textEdit/>
+ </ui>
+ <value>
+ <text>pdfium</text>
+ </value>
+ <event activity="change">
+ <script contentType="application/x-javascript">
+ change_count += 1;
+ if (change_count == 2) {
+ f1 = xfa.resolveNode("xfa.form..choiceList0");
+ xfa.host.setFocus(f1);
+ xfa.template.remerge();
+ xfa.host.openList(f1);
+ }
+ </script>
+ </event>
+ </field>
+ </subform>
+ <event activity="docReady">
+ <script contentType="application/x-javascript">
+ change_count = 0;
+ </script>
+ </event>
+ </subform>
+</template>
+endstream
+endobj
+{{include xfa_locale_6_0.fragment}}
+{{include xfa_postamble_7_0.fragment}}
+{{include xfa_pages_8_0.fragment}}
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/bug_1055869.pdf b/testing/resources/bug_1055869.pdf
new file mode 100644
index 0000000..a25ec90
--- /dev/null
+++ b/testing/resources/bug_1055869.pdf
@@ -0,0 +1,271 @@
+%PDF-1.7
+% ò¤ô
+1 0 obj <<
+ /AcroForm 2 0 R
+ /Extensions <<
+ /ADBE <<
+ /BaseVersion /1.7
+ /ExtensionLevel 8
+ >>
+ >>
+ /NeedsRendering true
+ /Pages 8 0 R
+ /Type /Catalog
+>>
+endobj
+2 0 obj <<
+ /XFA [
+ (preamble)
+ 3 0 R
+ (config)
+ 4 0 R
+ (template)
+ 5 0 R
+ (localeSet)
+ 6 0 R
+ (postamble)
+ 7 0 R
+ ]
+>>
+endobj
+3 0 obj <<
+ /Length 124
+>>
+stream
+<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/" timeStamp="2018-02-23T21:37:11Z" uuid="21482798-7bf0-40a4-bc5d-3cefdccf32b5">
+endstream
+endobj
+4 0 obj <<
+ /Length 642
+>>
+stream
+<config xmlns="http://www.xfa.org/schema/xci/3.0/">
+<agent name="designer">
+ <destination>pdf</destination>
+ <pdf>
+ <fontInfo/>
+ </pdf>
+</agent>
+<present>
+ <pdf>
+ <version>1.7</version>
+ <adobeExtensionLevel>8</adobeExtensionLevel>
+ <renderPolicy>client</renderPolicy>
+ <scriptModel>XFA</scriptModel>
+ <interactive>1</interactive>
+ </pdf>
+ <xdp>
+ <packets>*</packets>
+ </xdp>
+ <destination>pdf</destination>
+ <script>
+ <runScripts>server</runScripts>
+ </script>
+</present>
+<acrobat>
+ <acrobat7>
+ <dynamicRender>required</dynamicRender>
+ </acrobat7>
+ <validate>preSubmit</validate>
+</acrobat>
+</config>
+endstream
+endobj
+5 0 obj <<
+ /Length 1361
+>>
+stream
+<template xmlns="http://www.xfa.org/schema/xfa-template/2.6/">
+ <subform layout="tb" locale="en_US" name="form1" restoreState="auto">
+ <pageSet>
+ <pageArea id="Page1" name="Page1">
+ <contentArea h="10.5in" w="8in" x="0.25in" y="0.25in"/>
+ <medium long="11in" short="8.5in" stock="letter"/>
+ </pageArea>
+ </pageSet>
+ <subform h="10.5in" w="8in" name="subform2">
+ <field h="10mm" name="choiceList0" w="50mm" x="5mm" y="50mm">
+ <ui>
+ <choiceList/>
+ </ui>
+ <items>
+ <text>Single</text>
+ </items>
+ </field>
+ <field name="choiceList1" h="200mm" w="200mm" x="1mm" y="1mm">
+ <ui>
+ <textEdit/>
+ </ui>
+ <value>
+ <text>pdfium</text>
+ </value>
+ <event activity="change">
+ <script contentType="application/x-javascript">
+ change_count += 1;
+ if (change_count == 2) {
+ f1 = xfa.resolveNode("xfa.form..choiceList0");
+ xfa.host.setFocus(f1);
+ xfa.template.remerge();
+ xfa.host.openList(f1);
+ }
+ </script>
+ </event>
+ </field>
+ </subform>
+ <event activity="docReady">
+ <script contentType="application/x-javascript">
+ change_count = 0;
+ </script>
+ </event>
+ </subform>
+</template>
+endstream
+endobj
+6 0 obj <<
+ /Length 3455
+>>
+stream
+<localeSet xmlns="http://www.xfa.org/schema/xfa-locale-set/2.7/">
+ <locale name="en_US" desc="English (United States)">
+ <calendarSymbols name="gregorian">
+ <monthNames>
+ <month>January</month>
+ <month>February</month>
+ <month>March</month>
+ <month>April</month>
+ <month>May</month>
+ <month>June</month>
+ <month>July</month>
+ <month>August</month>
+ <month>September</month>
+ <month>October</month>
+ <month>November</month>
+ <month>December</month>
+ </monthNames>
+ <monthNames abbr="1">
+ <month>Jan</month>
+ <month>Feb</month>
+ <month>Mar</month>
+ <month>Apr</month>
+ <month>May</month>
+ <month>Jun</month>
+ <month>Jul</month>
+ <month>Aug</month>
+ <month>Sep</month>
+ <month>Oct</month>
+ <month>Nov</month>
+ <month>Dec</month>
+ </monthNames>
+ <dayNames>
+ <day>Sunday</day>
+ <day>Monday</day>
+ <day>Tuesday</day>
+ <day>Wednesday</day>
+ <day>Thursday</day>
+ <day>Friday</day>
+ <day>Saturday</day>
+ </dayNames>
+ <dayNames abbr="1">
+ <day>Sun</day>
+ <day>Mon</day>
+ <day>Tue</day>
+ <day>Wed</day>
+ <day>Thu</day>
+ <day>Fri</day>
+ <day>Sat</day>
+ </dayNames>
+ <meridiemNames>
+ <meridiem>AM</meridiem>
+ <meridiem>PM</meridiem>
+ </meridiemNames>
+ <eraNames>
+ <era>BC</era>
+ <era>AD</era>
+ </eraNames>
+ </calendarSymbols>
+ <datePatterns>
+ <datePattern name="full">EEEE, MMMM D, YYYY</datePattern>
+ <datePattern name="long">MMMM D, YYYY</datePattern>
+ <datePattern name="med">MMM D, YYYY</datePattern>
+ <datePattern name="short">M/D/YY</datePattern>
+ </datePatterns>
+ <timePatterns>
+ <timePattern name="full">h:MM:SS A Z</timePattern>
+ <timePattern name="long">h:MM:SS A Z</timePattern>
+ <timePattern name="med">h:MM:SS A</timePattern>
+ <timePattern name="short">h:MM A</timePattern>
+ </timePatterns>
+ <dateTimeSymbols>GyMdkHmsSEDFwWahKzZ</dateTimeSymbols>
+ <numberPatterns>
+ <numberPattern name="numeric">z,zz9.zzz</numberPattern>
+ <numberPattern name="currency">$z,zz9.99|($z,zz9.99)</numberPattern>
+ <numberPattern name="percent">z,zz9%</numberPattern>
+ </numberPatterns>
+ <numberSymbols>
+ <numberSymbol name="decimal">.</numberSymbol>
+ <numberSymbol name="grouping">,</numberSymbol>
+ <numberSymbol name="percent">%</numberSymbol>
+ <numberSymbol name="minus">-</numberSymbol>
+ <numberSymbol name="zero">0</numberSymbol>
+ </numberSymbols>
+ <currencySymbols>
+ <currencySymbol name="symbol">$</currencySymbol>
+ <currencySymbol name="isoname">USD</currencySymbol>
+ <currencySymbol name="decimal">.</currencySymbol>
+ </currencySymbols>
+ <typefaces>
+ <typeface name="Myriad Pro"/>
+ <typeface name="Minion Pro"/>
+ <typeface name="Courier Std"/>
+ <typeface name="Adobe Pi Std"/>
+ <typeface name="Adobe Hebrew"/>
+ <typeface name="Adobe Arabic"/>
+ <typeface name="Adobe Thai"/>
+ <typeface name="Kozuka Gothic Pro-VI M"/>
+ <typeface name="Kozuka Mincho Pro-VI R"/>
+ <typeface name="Adobe Ming Std L"/>
+ <typeface name="Adobe Song Std L"/>
+ <typeface name="Adobe Myungjo Std M"/>
+ </typefaces>
+ </locale>
+</localeSet>
+endstream
+endobj
+7 0 obj <<
+ /Length 11
+>>
+stream
+</xdp:xdp>
+endstream
+endobj
+8 0 obj <<
+ /Type /Pages
+ /Count 1
+ /Kids [9 0 R]
+>>
+endobj
+9 0 obj <<
+ /Type /Page
+ /Parent 2 0 R
+ /MediaBox [0 0 612 792]
+>>
+endobj
+xref
+0 10
+0000000000 65535 f
+0000000015 00000 n
+0000000199 00000 n
+0000000358 00000 n
+0000000534 00000 n
+0000001228 00000 n
+0000002642 00000 n
+0000006150 00000 n
+0000006212 00000 n
+0000006275 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 10
+>>
+startxref
+6352
+%%EOF
diff --git a/xfa/fxfa/cxfa_fftextedit.cpp b/xfa/fxfa/cxfa_fftextedit.cpp
index 6f8d732..3c6b0fc 100644
--- a/xfa/fxfa/cxfa_fftextedit.cpp
+++ b/xfa/fxfa/cxfa_fftextedit.cpp
@@ -399,14 +399,6 @@
return ToEdit(GetNormalWidget())->CanRedo();
}
-bool CXFA_FFTextEdit::Undo() {
- return ToEdit(GetNormalWidget())->Undo();
-}
-
-bool CXFA_FFTextEdit::Redo() {
- return ToEdit(GetNormalWidget())->Redo();
-}
-
bool CXFA_FFTextEdit::CanCopy() {
return ToEdit(GetNormalWidget())->HasSelection();
}
@@ -426,27 +418,59 @@
return ToEdit(GetNormalWidget())->GetTextLength() > 0;
}
+bool CXFA_FFTextEdit::Undo() {
+ // Prevents destruction of the CXFA_ContentLayoutItem that owns |this|.
+ RetainPtr<CXFA_ContentLayoutItem> retain_layout(m_pLayoutItem.Get());
+
+ return ToEdit(GetNormalWidget())->Undo();
+}
+
+bool CXFA_FFTextEdit::Redo() {
+ // Prevents destruction of the CXFA_ContentLayoutItem that owns |this|.
+ RetainPtr<CXFA_ContentLayoutItem> retain_layout(m_pLayoutItem.Get());
+
+ return ToEdit(GetNormalWidget())->Redo();
+}
+
Optional<WideString> CXFA_FFTextEdit::Copy() {
+ // Prevents destruction of the CXFA_ContentLayoutItem that owns |this|.
+ RetainPtr<CXFA_ContentLayoutItem> retain_layout(m_pLayoutItem.Get());
+
return ToEdit(GetNormalWidget())->Copy();
}
Optional<WideString> CXFA_FFTextEdit::Cut() {
+ // Prevents destruction of the CXFA_ContentLayoutItem that owns |this|.
+ RetainPtr<CXFA_ContentLayoutItem> retain_layout(m_pLayoutItem.Get());
+
return ToEdit(GetNormalWidget())->Cut();
}
bool CXFA_FFTextEdit::Paste(const WideString& wsPaste) {
+ // Prevents destruction of the CXFA_ContentLayoutItem that owns |this|.
+ RetainPtr<CXFA_ContentLayoutItem> retain_layout(m_pLayoutItem.Get());
+
return ToEdit(GetNormalWidget())->Paste(wsPaste);
}
void CXFA_FFTextEdit::SelectAll() {
+ // Prevents destruction of the CXFA_ContentLayoutItem that owns |this|.
+ RetainPtr<CXFA_ContentLayoutItem> retain_layout(m_pLayoutItem.Get());
+
ToEdit(GetNormalWidget())->SelectAll();
}
void CXFA_FFTextEdit::Delete() {
+ // Prevents destruction of the CXFA_ContentLayoutItem that owns |this|.
+ RetainPtr<CXFA_ContentLayoutItem> retain_layout(m_pLayoutItem.Get());
+
ToEdit(GetNormalWidget())->ClearText();
}
void CXFA_FFTextEdit::DeSelect() {
+ // Prevents destruction of the CXFA_ContentLayoutItem that owns |this|.
+ RetainPtr<CXFA_ContentLayoutItem> retain_layout(m_pLayoutItem.Get());
+
ToEdit(GetNormalWidget())->ClearSelection();
}
diff --git a/xfa/fxfa/cxfa_fftextedit.h b/xfa/fxfa/cxfa_fftextedit.h
index 09b9434..47c8570 100644
--- a/xfa/fxfa/cxfa_fftextedit.h
+++ b/xfa/fxfa/cxfa_fftextedit.h
@@ -46,12 +46,12 @@
// CXFA_FFWidget
bool CanUndo() override;
bool CanRedo() override;
- bool Undo() override;
- bool Redo() override;
bool CanCopy() override;
bool CanCut() override;
bool CanPaste() override;
bool CanSelectAll() override;
+ bool Undo() override;
+ bool Redo() override;
Optional<WideString> Copy() override;
Optional<WideString> Cut() override;
bool Paste(const WideString& wsPaste) override;
diff --git a/xfa/fxfa/cxfa_ffwidget.cpp b/xfa/fxfa/cxfa_ffwidget.cpp
index b0c5ee6..45045a8 100644
--- a/xfa/fxfa/cxfa_ffwidget.cpp
+++ b/xfa/fxfa/cxfa_ffwidget.cpp
@@ -488,14 +488,6 @@
return false;
}
-bool CXFA_FFWidget::Undo() {
- return false;
-}
-
-bool CXFA_FFWidget::Redo() {
- return false;
-}
-
bool CXFA_FFWidget::CanCopy() {
return false;
}
@@ -520,6 +512,14 @@
return CanCopy();
}
+bool CXFA_FFWidget::Undo() {
+ return false;
+}
+
+bool CXFA_FFWidget::Redo() {
+ return false;
+}
+
Optional<WideString> CXFA_FFWidget::Copy() {
return {};
}
diff --git a/xfa/fxfa/cxfa_ffwidget.h b/xfa/fxfa/cxfa_ffwidget.h
index 55461d3..008adfa 100644
--- a/xfa/fxfa/cxfa_ffwidget.h
+++ b/xfa/fxfa/cxfa_ffwidget.h
@@ -125,14 +125,14 @@
virtual FWL_WidgetHit HitTest(const CFX_PointF& point);
virtual bool CanUndo();
virtual bool CanRedo();
- virtual bool Undo();
- virtual bool Redo();
virtual bool CanCopy();
virtual bool CanCut();
virtual bool CanPaste();
virtual bool CanSelectAll();
virtual bool CanDelete();
virtual bool CanDeSelect();
+ virtual bool Undo();
+ virtual bool Redo();
virtual Optional<WideString> Copy();
virtual Optional<WideString> Cut();
virtual bool Paste(const WideString& wsPaste);