diff --git a/sw/source/core/text/EnhancedPDFExportHelper.cxx b/sw/source/core/text/EnhancedPDFExportHelper.cxx index 6f8dae771534..f4edc4482352 100644 --- a/sw/source/core/text/EnhancedPDFExportHelper.cxx +++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx @@ -224,7 +224,7 @@ constexpr OUString aLinkString = u"Link"_ustr; constexpr OUStringLiteral aNoteString = u"Note"; constexpr OUStringLiteral aAnnotString = u"Annot"; -// returns true if first paragraph in cell frame has 'table heading' style +// returns true if first paragraph in cell frame has 'table heading' style, or one derived from it bool lcl_IsHeadlineCell( const SwCellFrame& rCellFrame ) { bool bRet = false; @@ -233,11 +233,14 @@ bool lcl_IsHeadlineCell( const SwCellFrame& rCellFrame ) if ( pCnt && pCnt->IsTextFrame() ) { SwTextNode const*const pTextNode = static_cast(pCnt)->GetTextNodeForParaProps(); - const SwFormat* pTextFormat = pTextNode->GetFormatColl(); - - ProgName sStyleName; - SwStyleNameMapper::FillProgName( pTextFormat->GetName(), sStyleName, SwGetPoolIdFromName::TxtColl ); - bRet = sStyleName.toString() == aTableHeadingName; + for (const SwFormat* pFormat = pTextNode->GetFormatColl(); pFormat && !bRet; + pFormat = pFormat->DerivedFrom()) + { + ProgName sStyleName; + SwStyleNameMapper::FillProgName(pFormat->GetName(), sStyleName, + SwGetPoolIdFromName::TxtColl); + bRet = sStyleName == aTableHeadingName; + } } // tdf#153935 wild guessing for 1st row based on table autoformat diff --git a/vcl/qa/cppunit/pdfexport/data/TableHeadingDerived.fodt b/vcl/qa/cppunit/pdfexport/data/TableHeadingDerived.fodt new file mode 100644 index 000000000000..68d0fc923000 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/TableHeadingDerived.fodt @@ -0,0 +1,41 @@ + + + Table heading style and one derived from it + + + + + + + + + + + + + + + + + + + + + + + + + + + + head + one + + + derived + two + + + + + diff --git a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx index 43a41584acb0..11498d9d1cc1 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx @@ -2181,6 +2181,70 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf149140) CPPUNIT_ASSERT_EQUAL(6, nTH); } +// the structure element type of a table cell that a row's kid refers to +OString GetCellType(vcl::filter::PDFElement* pElement) +{ + auto pRef = dynamic_cast(pElement); + CPPUNIT_ASSERT(pRef); + auto pCell = pRef->LookupObject(); + CPPUNIT_ASSERT(pCell); + auto pS = dynamic_cast(pCell->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pS); + return pS->GetValue(); +} + +CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf173194) +{ + loadFromFile(u"TableHeadingDerived.fodt"); + + uno::Sequence aFilterData{ comphelper::makePropertyValue(u"PDFUACompliance"_ustr, true) }; + save(TestFilter::PDF_WRITER, + { comphelper::makePropertyValue(u"FilterData"_ustr, aFilterData) }); + + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + vcl::filter::PDFDocument aDocument; + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + vcl::filter::PDFObjectElement* pTableSE(nullptr); + for (const auto& rDocElement : aDocument.GetElements()) + { + auto pObject = dynamic_cast(rDocElement.get()); + if (!pObject) + continue; + auto pType = dynamic_cast(pObject->Lookup("Type"_ostr)); + auto pS = dynamic_cast(pObject->Lookup("S"_ostr)); + if (pType && pType->GetValue() == "StructElem" && pS && pS->GetValue() == "Table") + { + CPPUNIT_ASSERT(!pTableSE); + pTableSE = pObject; + } + } + CPPUNIT_ASSERT(pTableSE); + + auto pRows = dynamic_cast(pTableSE->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pRows); + CPPUNIT_ASSERT_EQUAL(size_t(2), pRows->GetElements().size()); + + // the first column is Table Heading in row one and a style derived from it in row two, + // so both rows read TH then TD + for (const auto pRowElement : pRows->GetElements()) + { + auto pRowRef = dynamic_cast(pRowElement); + CPPUNIT_ASSERT(pRowRef); + auto pRow = pRowRef->LookupObject(); + CPPUNIT_ASSERT(pRow); + auto pRowS = dynamic_cast(pRow->Lookup("S"_ostr)); + CPPUNIT_ASSERT(pRowS); + CPPUNIT_ASSERT_EQUAL("TR"_ostr, pRowS->GetValue()); + + auto pCells = dynamic_cast(pRow->Lookup("K"_ostr)); + CPPUNIT_ASSERT(pCells); + CPPUNIT_ASSERT_EQUAL(size_t(2), pCells->GetElements().size()); + CPPUNIT_ASSERT_EQUAL("TH"_ostr, GetCellType(pCells->GetElement(0))); + CPPUNIT_ASSERT_EQUAL("TD"_ostr, GetCellType(pCells->GetElement(1))); + } +} + CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf153935) { // tdf#153935: PDF/A-1 + PDF/UA must still emit /Scope on TH and /Tabs on