From a8b9ecfd09027c2b95846394c8a17a8d0bc13757 Mon Sep 17 00:00:00 2001 From: Tony Qu Date: Fri, 20 Feb 2026 22:27:09 +0800 Subject: [PATCH] POI Bug 69720 --- OpenXmlFormats/Wordprocessing/Paragraph.cs | 5 ++ ooxml/XWPF/Usermodel/XWPFParagraph.cs | 81 +++++++++++++----- testcases/ooxml/XWPF/TestXWPFBugs.cs | 15 ++++ .../ooxml/XWPF/UserModel/TestXWPFParagraph.cs | 31 ++++--- .../document/bug-paragraph-alignment.docx | Bin 0 -> 11916 bytes 5 files changed, 100 insertions(+), 32 deletions(-) create mode 100644 testcases/test-data/document/bug-paragraph-alignment.docx diff --git a/OpenXmlFormats/Wordprocessing/Paragraph.cs b/OpenXmlFormats/Wordprocessing/Paragraph.cs index 4369db897..5ec6569b8 100644 --- a/OpenXmlFormats/Wordprocessing/Paragraph.cs +++ b/OpenXmlFormats/Wordprocessing/Paragraph.cs @@ -1229,6 +1229,11 @@ public bool IsSetSectPr() { return this.sectPr != null; } + + public void UnsetJc() + { + this.jc=null; + } } diff --git a/ooxml/XWPF/Usermodel/XWPFParagraph.cs b/ooxml/XWPF/Usermodel/XWPFParagraph.cs index c3b522752..fa983d410 100644 --- a/ooxml/XWPF/Usermodel/XWPFParagraph.cs +++ b/ooxml/XWPF/Usermodel/XWPFParagraph.cs @@ -569,18 +569,27 @@ public String FootnoteText /// /// Returns the paragraph alignment which shall be applied to text in this paragraph. /// - public ParagraphAlignment Alignment + public ParagraphAlignment? Alignment { get { - CT_PPr pr = GetCTPPr(); - return pr == null || !pr.IsSetJc() ? ParagraphAlignment.LEFT : EnumConverter.ValueOf(pr.jc.val); + CT_PPr pr = GetCTPPr(false); + return (pr == null || !pr.IsSetJc()) ? ParagraphAlignment.LEFT : EnumConverter.ValueOf(pr.jc.val); } set { - CT_PPr pr = GetCTPPr(); - CT_Jc jc = pr.IsSetJc() ? pr.jc : pr.AddNewJc(); - jc.val = EnumConverter.ValueOf(value); + if(value==null) + { + CT_PPr pr = GetCTPPr(false); + if(pr!=null) + pr.UnsetJc(); + } + else + { + CT_PPr pr = GetCTPPr(true); + CT_Jc jc = pr.IsSetJc() ? pr.jc : pr.AddNewJc(); + jc.val = EnumConverter.ValueOf((ParagraphAlignment) value); + } } } @@ -621,7 +630,7 @@ public TextAlignment VerticalAlignment { get { - CT_PPr pr = GetCTPPr(); + CT_PPr pr = GetCTPPr(false); return (pr == null || !pr.IsSetTextAlignment()) ? TextAlignment.AUTO : EnumConverter.ValueOf(pr.textAlignment.val); } @@ -1242,8 +1251,8 @@ public bool IsWordWrapped { get { - CT_OnOff wordWrap = GetCTPPr().IsSetWordWrap() ? GetCTPPr() - .wordWrap : null; + var ppr = GetCTPPr(false); + CT_OnOff wordWrap = ppr!=null && ppr.IsSetWordWrap() ? ppr.wordWrap : null; if (wordWrap != null) { return wordWrap.val; @@ -1274,15 +1283,28 @@ public String Style { get { - CT_PPr pr = GetCTPPr(); + CT_PPr pr = GetCTPPr(false); + if(pr==null) + { + return null; + } CT_String style = pr.IsSetPStyle() ? pr.pStyle : null; return style != null ? style.val : null; } set { - CT_PPr pr = GetCTPPr(); - CT_String style = pr.pStyle != null ? pr.pStyle : pr.AddNewPStyle(); - style.val = value; + if(value==null) + { + var pr= GetCTPPr(false); + if(pr!=null) + pr.jc = null; + } + else + { + CT_PPr pr = GetCTPPr(true); + CT_String style = pr.pStyle != null ? pr.pStyle : pr.AddNewPStyle(); + style.val = value; + } } } @@ -1292,12 +1314,15 @@ public String Style */ private CT_PBdr GetCTPBrd(bool create) { - CT_PPr pr = GetCTPPr(); + CT_PPr pr = GetCTPPr(create); + if(pr==null) + { + return null; + } CT_PBdr ct = pr.IsSetPBdr() ? pr.pBdr : null; - if (create && ct == null) + if(create && ct == null) ct = pr.AddNewPBdr(); return ct; - } /** @@ -1306,7 +1331,7 @@ private CT_PBdr GetCTPBrd(bool create) */ private CT_Spacing GetCTSpacing(bool create) { - CT_PPr pr = GetCTPPr(); + CT_PPr pr = GetCTPPr(create); CT_Spacing ct = pr.spacing == null ? null : pr.spacing; if (create && ct == null) ct = pr.AddNewSpacing(); @@ -1319,20 +1344,23 @@ private CT_Spacing GetCTSpacing(bool create) */ private CT_Ind GetCTInd(bool create) { - CT_PPr pr = GetCTPPr(); + CT_PPr pr = GetCTPPr(create); CT_Ind ct = pr.ind == null ? null : pr.ind; if (create && ct == null) ct = pr.AddNewInd(); return ct; } - + internal CT_PPr GetCTPPr() + { + return GetCTPPr(true); + } /** * Get a copy of the currently used CTPPr, if none is used, return * a new instance. */ - internal CT_PPr GetCTPPr() + internal CT_PPr GetCTPPr(bool create) { - CT_PPr pr = paragraph.pPr == null ? paragraph.AddNewPPr() + CT_PPr pr = (paragraph.pPr == null||!create) ? paragraph.AddNewPPr() : paragraph.pPr; return pr; } @@ -1862,6 +1890,17 @@ private bool IsTheOnlyCTFieldInRuns(XWPFFieldRun run) && ctField == ((XWPFFieldRun) r).GetCTField()); return count <= 1; } + + /// + /// Returns true if the paragraph has a paragraph alignment value of its own + /// or false in case it should fall back to the alignment value set by the paragraph style. + /// + /// + public bool IsAlignmentSet() + { + var pr = GetCTPPr(false); + return pr != null && pr.IsSetJc(); + } } } diff --git a/testcases/ooxml/XWPF/TestXWPFBugs.cs b/testcases/ooxml/XWPF/TestXWPFBugs.cs index 21d1ff2f0..b6e6b4017 100644 --- a/testcases/ooxml/XWPF/TestXWPFBugs.cs +++ b/testcases/ooxml/XWPF/TestXWPFBugs.cs @@ -27,6 +27,7 @@ namespace TestCases.XWPF using NUnit.Framework;using NUnit.Framework.Legacy; using System; using System.IO; + using System.Reflection.Metadata; using System.Xml; using TestCases; @@ -287,6 +288,20 @@ private static void addNumberingWithAbstractId(XWPFNumbering documentNumbering, documentNumbering.AddNum(abstractNumID); } + + [Test] + public void CorrectParagraphAlignment() + { + using (var document = XWPFTestDataSamples.OpenSampleDocument("bug-paragraph-alignment.docx")) { + XWPFParagraph centeredParagraph = document.GetParagraphArray(0); + ClassicAssert.IsFalse(centeredParagraph.IsAlignmentSet()); + ClassicAssert.AreEqual(ParagraphAlignment.LEFT, centeredParagraph.Alignment); // LEFT is a fallback value here. + + XWPFParagraph leftParagraph = document.GetParagraphArray(1); + ClassicAssert.IsTrue(leftParagraph.IsAlignmentSet()); + ClassicAssert.AreEqual(ParagraphAlignment.LEFT, leftParagraph.Alignment); // LEFT is the real alignment value. + } + } } } diff --git a/testcases/ooxml/XWPF/UserModel/TestXWPFParagraph.cs b/testcases/ooxml/XWPF/UserModel/TestXWPFParagraph.cs index 1947b95d0..229eb2179 100644 --- a/testcases/ooxml/XWPF/UserModel/TestXWPFParagraph.cs +++ b/testcases/ooxml/XWPF/UserModel/TestXWPFParagraph.cs @@ -105,23 +105,32 @@ public void TestSetBorderTop() } [Test] - public void TestSetAlignment() + public void TestSetGetAlignment() { //new clean instance of paragraph - XWPFDocument doc = new XWPFDocument(); - XWPFParagraph p = doc.CreateParagraph(); + using(XWPFDocument doc = new XWPFDocument()) + { + XWPFParagraph p = doc.CreateParagraph(); - ClassicAssert.AreEqual(ParagraphAlignment.LEFT, p.Alignment); + ClassicAssert.AreEqual(ParagraphAlignment.LEFT, p.Alignment); + ClassicAssert.IsFalse(p.IsAlignmentSet()); - CT_P ctp = p.GetCTP(); - CT_PPr ppr = ctp.pPr == null ? ctp.AddNewPPr() : ctp.pPr; + CT_P ctp = p.GetCTP(); + CT_PPr ppr = ctp.pPr == null ? ctp.AddNewPPr() : ctp.pPr; - CT_Jc align = ppr.AddNewJc(); - align.val = (ST_Jc.center); - ClassicAssert.AreEqual(ParagraphAlignment.CENTER, p.Alignment); + CT_Jc align = ppr.AddNewJc(); + align.val = (ST_Jc.center); + ClassicAssert.AreEqual(ParagraphAlignment.CENTER, p.Alignment); + ClassicAssert.IsTrue(p.IsAlignmentSet()); - p.Alignment = (ParagraphAlignment.BOTH); - ClassicAssert.AreEqual((int)ST_Jc.both, (int)ppr.jc.val); + p.Alignment = (ParagraphAlignment.BOTH); + ClassicAssert.AreEqual((int) ST_Jc.both, (int) ppr.jc.val); + ClassicAssert.IsTrue(p.IsAlignmentSet()); + + p.Alignment=null; + ClassicAssert.AreEqual(ParagraphAlignment.LEFT, p.Alignment); + ClassicAssert.IsFalse(p.IsAlignmentSet()); + } } [Test] diff --git a/testcases/test-data/document/bug-paragraph-alignment.docx b/testcases/test-data/document/bug-paragraph-alignment.docx new file mode 100644 index 0000000000000000000000000000000000000000..de4a468552ff002cc6519843489416f6c730abeb GIT binary patch literal 11916 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 w75<+57x