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);