diff --git a/sw/source/core/txtnode/swfont.cxx b/sw/source/core/txtnode/swfont.cxx index 9539fd4bc80d..a4c294b6b679 100644 --- a/sw/source/core/txtnode/swfont.cxx +++ b/sw/source/core/txtnode/swfont.cxx @@ -1232,14 +1232,30 @@ void SwSubFont::DrawText_( SwDrawTextInfo &rInf, const bool bGrey ) const SwScriptInfo* pSI = rInf.GetScriptInfo(); + auto pKashida = pSI ? pSI->GetKashidaPositions() : std::span{}; + auto fnIsKashida = [&](TextFrameIndex nIdx) -> bool + { + while (!pKashida.empty()) + { + if (pKashida[0] >= nIdx) + { + return pKashida[0] == nIdx; + } + + pKashida = pKashida.subspan(1); + } + + return false; + }; + const bool bAsianFont = ( rInf.GetFont() && SwFontScript::CJK == rInf.GetFont()->GetActual() ); for (TextFrameIndex nTmp = nOldIdx; nTmp < nTmpEnd; ++nTmp) { - if (CH_BLANK == oldStr[sal_Int32(nTmp)] || bAsianFont || - (nTmp + TextFrameIndex(1) < TextFrameIndex(oldStr.getLength()) - && pSI - && i18n::ScriptType::ASIAN == pSI->ScriptType(nTmp + TextFrameIndex(1)))) + if (CH_BLANK == oldStr[sal_Int32(nTmp)] || bAsianFont + || (nTmp + TextFrameIndex(1) < TextFrameIndex(oldStr.getLength()) && pSI + && i18n::ScriptType::ASIAN == pSI->ScriptType(nTmp + TextFrameIndex(1))) + || fnIsKashida(nTmp)) { ++nSpace; } diff --git a/vcl/qa/cppunit/pdfexport/data/tdf155557-underline-kashida-portion.fodt b/vcl/qa/cppunit/pdfexport/data/tdf155557-underline-kashida-portion.fodt new file mode 100644 index 000000000000..b65dc0cbc474 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf155557-underline-kashida-portion.fodt @@ -0,0 +1,118 @@ + + + 2026-04-30T02:34:03.3723585612026-04-30T02:35:54.419652989PT1M52S1LibreOfficeDev/26.8.0.0.alpha0$Linux_X86_64 LibreOffice_project/5c2d2aa9e760a7d133ead2350b575a38959015eb + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ممم + + + \ No newline at end of file diff --git a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx index 5f52c7b1767c..a76b6f27e7b2 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx @@ -6472,6 +6472,45 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, tdf150076BackgroundPdf) CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFPageObjectType::Form, pPageObject->getType()); } +CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf155557UnderlineKashidaPortion) +{ + loadFromFile(u"tdf155557-underline-kashida-portion.fodt"); + save(TestFilter::PDF_WRITER); + + std::unique_ptr pPdfDocument = parsePDFExport(); + + CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); + + auto pPdfPage = pPdfDocument->openPage(0); + CPPUNIT_ASSERT(pPdfPage); + + std::vector aStrokeRect; + + int nPageObjectCount = pPdfPage->getObjectCount(); + for (int i = 0; i < nPageObjectCount; ++i) + { + auto pPageObject = pPdfPage->getObject(i); + CPPUNIT_ASSERT_MESSAGE("no object", pPageObject != nullptr); + if (pPageObject->getType() == vcl::pdf::PDFPageObjectType::Path) + { + aStrokeRect.push_back(pPageObject->getBounds()); + } + } + + CPPUNIT_ASSERT_EQUAL(size_t(2), aStrokeRect.size()); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(547.8, aStrokeRect.at(0).getMinX(), /*delta*/ 1.0); + CPPUNIT_ASSERT_DOUBLES_EQUAL(555.9, aStrokeRect.at(0).getMaxX(), /*delta*/ 1.0); + + // Without the fix in place, this fails with: + // double equality assertion failed + // - Expected: 56.1 + // - Actual : 534.2 + // - Delta : 1 + CPPUNIT_ASSERT_DOUBLES_EQUAL(56.1, aStrokeRect.at(1).getMinX(), /*delta*/ 1.0); + CPPUNIT_ASSERT_DOUBLES_EQUAL(548.9, aStrokeRect.at(1).getMaxX(), /*delta*/ 1.0); +} + } // end anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT();