editeng/qa/unit/core-test.cxx | 14 +++---- editeng/source/editeng/impedit3.cxx | 48 ++++++++++++------------ include/vcl/outdev.hxx | 10 ----- vcl/qa/cppunit/pdfexport/data/tdf151748.fodt | 53 ++++++++++++--------------- vcl/qa/cppunit/pdfexport/pdfexport2.cxx | 16 ++++---- vcl/source/outdev/font.cxx | 47 ----------------------- 6 files changed, 64 insertions(+), 124 deletions(-)
New commits: commit 3c9fdd9aeb74d76ef7f1c0581582439c8a135532 Author: Jonathan Clark <jonat...@libreoffice.org> AuthorDate: Wed Apr 16 05:00:25 2025 -0600 Commit: Jonathan Clark <jonat...@libreoffice.org> CommitDate: Wed Apr 16 17:38:33 2025 +0200 tdf#163618 editeng: Fix excessive overlap in justified Arabic script Fixes a bug causing editeng to insert kashida glyphs in positions where there is not enough space for them. The root cause was failing to account for the extra space used by blanks while rejecting candidate kashida positions. Change-Id: I1e22f758af0a88c2070f31cca040570f3a730c08 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184282 Tested-by: Jenkins Reviewed-by: Jonathan Clark <jonat...@libreoffice.org> diff --git a/editeng/qa/unit/core-test.cxx b/editeng/qa/unit/core-test.cxx index 029df4439dee..5484593ad9c5 100644 --- a/editeng/qa/unit/core-test.cxx +++ b/editeng/qa/unit/core-test.cxx @@ -2251,9 +2251,9 @@ void Test::testTdf151748StaleKashidaArray() EditEngine aEditEngine(mpItemPool.get()); aEditEngine.SetRefDevice(pVirtualDevice.get()); - aEditEngine.SetPaperSize(Size(1500, 500)); + aEditEngine.SetPaperSize(Size(1600, 500)); aEditEngine.SetDefaultHorizontalTextDirection(EEHorizontalTextDirection::R2L); - aEditEngine.SetText(u"خط تخوردگی و توسط"_ustr); + aEditEngine.SetText(u"خط تخوردگی وتوسسسسط"_ustr); CPPUNIT_ASSERT_EQUAL(true, aEditEngine.IsFormatted()); CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEditEngine.GetParagraphCount()); @@ -2280,7 +2280,7 @@ void Test::testTdf151748StaleKashidaArray() CPPUNIT_ASSERT_EQUAL(sal_Int32(11), rLine.GetEnd()); std::vector<sal_Bool> const& rArray = rLine.GetKashidaArray(); - CPPUNIT_ASSERT_EQUAL(size_t(17), rArray.size()); + CPPUNIT_ASSERT_EQUAL(size_t(19), rArray.size()); } // Resize the paper so there is no longer room for kashida @@ -2313,9 +2313,9 @@ void Test::testTdf162803StaleKashidaArray() EditEngine aEditEngine(mpItemPool.get()); aEditEngine.SetRefDevice(pVirtualDevice.get()); - aEditEngine.SetPaperSize(Size(1500, 500)); + aEditEngine.SetPaperSize(Size(1600, 500)); aEditEngine.SetDefaultHorizontalTextDirection(EEHorizontalTextDirection::R2L); - aEditEngine.SetText(u"خط تخوردگی و توسط"_ustr); + aEditEngine.SetText(u"خط تخوردگی وتوسسسسط"_ustr); CPPUNIT_ASSERT_EQUAL(true, aEditEngine.IsFormatted()); CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEditEngine.GetParagraphCount()); @@ -2342,7 +2342,7 @@ void Test::testTdf162803StaleKashidaArray() CPPUNIT_ASSERT_EQUAL(sal_Int32(11), rLine.GetEnd()); std::vector<sal_Bool> const& rArray = rLine.GetKashidaArray(); - CPPUNIT_ASSERT_EQUAL(size_t(17), rArray.size()); + CPPUNIT_ASSERT_EQUAL(size_t(19), rArray.size()); } // Resize the paper so the entire text fits on a single line @@ -2358,7 +2358,7 @@ void Test::testTdf162803StaleKashidaArray() EditLine const& rLine = rLines[0]; CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rLine.GetStart()); - CPPUNIT_ASSERT_EQUAL(sal_Int32(17), rLine.GetEnd()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(19), rLine.GetEnd()); std::vector<sal_Bool> const& rArray = rLine.GetKashidaArray(); diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx index eafcab1673a1..fac82269ce59 100644 --- a/editeng/source/editeng/impedit3.cxx +++ b/editeng/source/editeng/impedit3.cxx @@ -2236,10 +2236,6 @@ void ImpEditEngine::ImpAdjustBlocks(ParaPortion& rParaPortion, EditLine& rLine, // Search blanks or Kashidas... std::vector<sal_Int32> aPositions; - // Kashidas ? - ImpFindKashidas(pNode, nFirstChar, nLastChar, aPositions, nRemainingSpace); - auto nKashidas = aPositions.size(); - sal_uInt16 nLastScript = i18n::ScriptType::LATIN; for ( sal_Int32 nChar = nFirstChar; nChar <= nLastChar; nChar++ ) { @@ -2269,6 +2265,11 @@ void ImpEditEngine::ImpAdjustBlocks(ParaPortion& rParaPortion, EditLine& rLine, nLastScript = nScript; } + // Kashidas ? + auto nKashidaStart = aPositions.size(); + ImpFindKashidas(pNode, nFirstChar, nLastChar, aPositions, nRemainingSpace); + auto nKashidas = aPositions.size() - nKashidaStart; + if ( aPositions.empty() ) return; @@ -2313,7 +2314,7 @@ void ImpEditEngine::ImpAdjustBlocks(ParaPortion& rParaPortion, EditLine& rLine, rLine.GetKashidaArray().resize(rLine.GetCharPosArray().size(), false); for (size_t i = 0; i < nKashidas; i++) { - auto nChar = aPositions[i]; + auto nChar = aPositions[nKashidaStart + i]; if ( nChar < nLastChar ) rLine.GetKashidaArray()[nChar-nFirstChar] = 1 /*sal_True*/; } @@ -2371,7 +2372,6 @@ void ImpEditEngine::ImpFindKashidas(ContentNode* pNode, sal_Int32 nStart, sal_In std::vector<bool> aValidPositions; std::vector<sal_Int32> aKashidaArray; std::vector<sal_Int32> aMinKashidaArray; - sal_Int32 nTotalMinKashida = 0U; // the search has to be performed on a per word base @@ -2403,7 +2403,6 @@ void ImpEditEngine::ImpFindKashidas(ContentNode* pNode, sal_Int32 nStart, sal_In aTmpFont.SetPhysFont(*GetRefDevice()); auto nMinKashidaWidth = GetRefDevice()->GetMinKashida(); - nTotalMinKashida += nMinKashidaWidth; aMinKashidaArray.push_back(nMinKashidaWidth); aKashidaArray.push_back(nKashidaPos); @@ -2413,28 +2412,29 @@ void ImpEditEngine::ImpFindKashidas(ContentNode* pNode, sal_Int32 nStart, sal_In aWordSel = SelectWord( aWordSel, css::i18n::WordType::DICTIONARY_WORD ); } - // Greedily reject kashida positions from start-to-end until there is enough room. - // This will push kashida justification away from the start of the line. + // Every kashida and blank in the block will be given the same amount of extra space. + // Greedily reject kashida positions from start-to-end until there is enough room + // for all of the remaining kashida. This will push kashida justification away from + // the start of the line. std::reverse(aKashidaArray.begin(), aKashidaArray.end()); std::reverse(aMinKashidaArray.begin(), aMinKashidaArray.end()); - while (!aKashidaArray.empty() && nTotalMinKashida > nRemainingSpace) - { - nTotalMinKashida -= aMinKashidaArray.back(); - aMinKashidaArray.pop_back(); - aKashidaArray.pop_back(); - } - std::reverse(aKashidaArray.begin(), aKashidaArray.end()); + auto nGaps = aKashidaArray.size() + rArray.size(); + auto nGapSize = nGaps ? (nRemainingSpace / nGaps) : 0; + for (size_t i = 0; i < aKashidaArray.size(); ++i) + { + auto nEmRequiredSize = aMinKashidaArray[i]; + while (aKashidaArray.size() > i && std::cmp_less(nGapSize, nEmRequiredSize)) + { + aMinKashidaArray.pop_back(); + aKashidaArray.pop_back(); - // Validate - std::vector<sal_Int32> aDropped; - GetRefDevice()->ValidateKashidas(pNode->GetString(), nStart, nEnd - nStart, - /*nPartIdx=*/nStart, /*nPartLen=*/nEnd - nStart, aKashidaArray, - &aDropped); + --nGaps; + nGapSize = nGaps ? (nRemainingSpace / nGaps) : 0; + } + } - for (auto const& pos : aKashidaArray) - if (std::find(aDropped.begin(), aDropped.end(), pos) == aDropped.end()) - rArray.push_back(pos); + std::copy(aKashidaArray.rbegin(), aKashidaArray.rend(), std::back_inserter(rArray)); } sal_Int32 ImpEditEngine::SplitTextPortion(ParaPortion& rParaPortion, sal_Int32 nPos, EditLine* pCurLine) diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx index da73268f4b69..f156b86ef295 100644 --- a/include/vcl/outdev.hxx +++ b/include/vcl/outdev.hxx @@ -1153,16 +1153,6 @@ public: tools::Long GetMinKashida() const; - // i60594 - // validate kashida positions against the current font - // returns count of invalid kashida positions - sal_Int32 - ValidateKashidas(const OUString& rTxt, sal_Int32 nIdx, sal_Int32 nLen, sal_Int32 nPartIdx, - sal_Int32 nPartLen, - std::span<const sal_Int32> pKashidaPos, // suggested kashida positions (in) - std::vector<sal_Int32>* pKashidaPosDropped // invalid kashida positions (out) - ) const; - // tdf#163105: Get map of valid kashida positions for a single word void GetWordKashidaPositions(const OUString& rText, std::vector<bool>* pOutMap) const; diff --git a/vcl/qa/cppunit/pdfexport/data/tdf151748.fodt b/vcl/qa/cppunit/pdfexport/data/tdf151748.fodt index 93c12a655fff..7851e97ac328 100644 --- a/vcl/qa/cppunit/pdfexport/data/tdf151748.fodt +++ b/vcl/qa/cppunit/pdfexport/data/tdf151748.fodt @@ -1,24 +1,23 @@ <?xml version='1.0' encoding='UTF-8'?> -<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:c alcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns: meta:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> - <office:meta><meta:initial-creator>Eyal Rozenberg</meta:initial-creator><meta:creation-date>2024-08-16T21:34:46.833527525</meta:creation-date><dc:date>2024-08-30T01:36:34.697764958</dc:date><meta:editing-duration>PT9M57S</meta:editing-duration><meta:editing-cycles>6</meta:editing-cycles><meta:generator>LibreOfficeDev/25.2.0.0.alpha0$Linux_X86_64 LibreOffice_project/87ae339de7d1f83235a180dc50293f2857ef37a8</meta:generator><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="4" meta:word-count="0" meta:character-count="0" meta:non-whitespace-character-count="0"/></office:meta> +<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:c alcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns: meta:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:meta><meta:initial-creator>Eyal Rozenberg</meta:initial-creator><meta:creation-date>2024-08-16T21:34:46.833527525</meta:creation-date><dc:date>2025-04-16T06:58:25.099932475</dc:date><meta:editing-duration>PT12M14S</meta:editing-duration><meta:editing-cycles>10</meta:editing-cycles><meta:generator>LibreOfficeDev/25.8.0.0.alpha0$Linux_X86_64 LibreOffice_project/5fbd402f70ef6b71f3c7812fe06e40f003416e8e</meta:generator><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="4" meta:word-count="0" meta:character-count="0" meta:non-whitespace-character-count="0"/></office:meta> <office:font-face-decls> - <style:font-face style:name="David CLM1" svg:font-family="'David CLM'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="David CLM" svg:font-family="'David CLM'" style:font-family-generic="system" style:font-pitch="variable"/> <style:font-face style:name="DejaVu Sans" svg:font-family="'DejaVu Sans'" style:font-adornments="Book" style:font-family-generic="swiss" style:font-pitch="variable"/> <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> - <style:font-face style:name="Noto Sans Arabic" svg:font-family="'Noto Sans Arabic'" style:font-adornments="Regular" style:font-family-generic="swiss" style:font-pitch="variable"/> <style:font-face style:name="Noto Serif CJK SC" svg:font-family="'Noto Serif CJK SC'" style:font-family-generic="system" style:font-pitch="variable"/> </office:font-face-decls> <office:styles> <style:default-style style:family="graphic"> <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.1181in" draw:shadow-offset-y="0.1181in" draw:start-line-spacing-horizontal="0.1114in" draw:start-line-spacing-vertical="0.1114in" draw:end-line-spacing-horizontal="0.1114in" draw:end-line-spacing-vertical="0.1114in" style:writing-mode="lr-tb" style:flow-with-text="false"/> - <style:paragraph-properties fo:text-align="end" style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0in" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> + <style:paragraph-properties fo:text-align="end" style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0in" style:font-independent-line-spacing="false"> <style:tab-stops/> </style:paragraph-properties> - <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="IL" style:letter-kerning="true" style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="David CLM1" style:font-size-complex="12pt" style:language-complex="he" style:country-complex="IL"/> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="IL" style:letter-kerning="true" style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="David CLM" style:font-size-complex="12pt" style:language-complex="he" style:country-complex="IL"/> </style:default-style> <style:default-style style:family="paragraph"> - <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" fo:hyphenation-keep="auto" loext:hyphenation-keep-type="column" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="0.4925in" style:writing-mode="page"/> - <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="IL" style:letter-kerning="true" style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="David CLM1" style:font-size-complex="12pt" style:language-complex="he" style:country-complex="IL" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/> + <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" fo:hyphenation-keep="auto" loext:hyphenation-keep-type="column" loext:hyphenation-keep-line="false" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="0.4925in" style:writing-mode="page"/> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="IL" style:letter-kerning="true" style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="David CLM" style:font-size-complex="12pt" style:language-complex="he" style:country-complex="IL" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/> </style:default-style> <style:default-style style:family="table"> <style:table-properties table:border-model="collapsing"/> @@ -87,30 +86,28 @@ <text:linenumbering-configuration text:number-lines="false" text:offset="0.1965in" style:num-format="1" text:number-position="left" text:increment="5"/> </office:styles> <office:automatic-styles> - <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard"> - <style:text-properties/> - </style:style> - <style:style style:name="P2" style:family="paragraph"> + <style:style style:name="P1" style:family="paragraph"> <style:paragraph-properties fo:text-align="justify" style:writing-mode="rl-tb"/> </style:style> - <style:style style:name="P3" style:family="paragraph"> + <style:style style:name="P2" style:family="paragraph"> <loext:graphic-properties draw:fill="none" draw:fill-color="#ffffff"/> <style:paragraph-properties fo:text-align="justify"/> - <style:text-properties style:font-name-complex="Noto Sans Arabic" style:language-complex="ar" style:country-complex="SA" style:font-style-complex="normal" style:font-weight-complex="normal"/> - </style:style> - <style:style style:name="P4" style:family="paragraph" style:parent-style-name="Standard"> - <style:text-properties/> + <style:text-properties style:font-family-complex="'Noto Sans Arabic'" style:font-style-name-complex="Regular" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:language-complex="ar" style:country-complex="SA" style:font-style-complex="normal" style:font-weight-complex="normal"/> </style:style> <style:style style:name="T1" style:family="text"> - <style:text-properties style:font-name-complex="Noto Sans Arabic" style:language-complex="ar" style:country-complex="SA" style:font-style-complex="normal" style:font-weight-complex="normal"/> + <style:text-properties style:font-family-complex="'Noto Sans Arabic'" style:font-style-name-complex="Regular" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:language-complex="ar" style:country-complex="SA" style:font-style-complex="normal" style:font-weight-complex="normal"/> </style:style> <style:style style:name="T2" style:family="text"> - <style:text-properties fo:font-size="26pt" style:font-size-asian="26pt" style:font-name-complex="Noto Sans Arabic" style:font-size-complex="26pt" style:language-complex="ar" style:country-complex="SA" style:font-style-complex="normal" style:font-weight-complex="normal"/> + <style:text-properties fo:font-size="26pt" style:font-size-asian="26pt" style:font-family-complex="'Noto Sans Arabic'" style:font-style-name-complex="Regular" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="26pt" style:language-complex="ar" style:country-complex="SA" style:font-style-complex="normal" style:font-weight-complex="normal"/> </style:style> <style:style style:name="gr1" style:family="graphic"> <style:graphic-properties draw:stroke="solid" svg:stroke-color="#000000" draw:fill="none" draw:fill-color="#ffffff" fo:min-height="0.7047in" loext:decorative="false" style:run-through="foreground" style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="middle" style:vertical-rel="baseline" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" draw:wrap-influence-on-position="once-concurrent" loext:allow-overlap="true" style:flow-with-text="false"/> <style:paragraph-properties style:writing-mode="lr-tb"/> </style:style> + <style:style style:name="gr2" style:family="graphic"> + <style:graphic-properties draw:stroke="solid" svg:stroke-color="#000000" draw:fill="none" draw:fill-color="#ffffff" fo:min-height="1.1161in" loext:decorative="false" style:run-through="foreground" style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="middle" style:vertical-rel="baseline" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" draw:wrap-influence-on-position="once-concurrent" loext:allow-overlap="true" style:flow-with-text="false"/> + <style:paragraph-properties style:writing-mode="lr-tb"/> + </style:style> <style:page-layout style:name="pm1"> <style:page-layout-properties fo:page-width="8.2681in" fo:page-height="11.6929in" style:num-format="1" style:print-orientation="portrait" fo:margin-top="0.7874in" fo:margin-bottom="0.7874in" fo:margin-left="0.7874in" fo:margin-right="0.7874in" style:writing-mode="rl-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" style:layout-grid-base-height="0.278in" style:layout-grid-ruby-height="0.139in" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:footnote-max-height="0in" loext:margin-gutter="0in"> <style:footnote-sep style:width="0.0071in" style:distance-before-sep="0.0398in" style:distance-after-sep="0.0398in" style:line-style="solid" style:adjustment="right" style:rel-width="25%" style:color="#000000"/> @@ -134,27 +131,27 @@ <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> </text:sequence-decls> - <text:p text:style-name="P1"><draw:frame text:anchor-type="as-char" draw:z-index="0" draw:name="Text Frame 1" draw:style-name="gr1" draw:text-style-name="P3" svg:width="0.9606in" svg:height="0.7051in"> + <text:p text:style-name="Standard"><draw:frame text:anchor-type="as-char" draw:z-index="0" draw:name="Text Frame 1" draw:style-name="gr1" draw:text-style-name="P2" svg:width="0.865in" svg:height="0.7051in"> <draw:text-box> - <text:p text:style-name="P2"><text:span text:style-name="T1">خط تخوردگی و توسط</text:span></text:p> + <text:p text:style-name="P1"><text:span text:style-name="T1">خط تخوردگی وتوسط</text:span></text:p> </draw:text-box> </draw:frame></text:p> - <text:p text:style-name="P4"><draw:frame text:anchor-type="as-char" draw:z-index="1" draw:name="Text Frame 2" draw:style-name="gr1" draw:text-style-name="P3" svg:width="1.0394in" svg:height="0.7051in"> + <text:p text:style-name="Standard"><draw:frame text:anchor-type="as-char" draw:z-index="1" draw:name="Text Frame 2" draw:style-name="gr1" draw:text-style-name="P2" svg:width="1.0016in" svg:height="0.7051in"> <draw:text-box> - <text:p text:style-name="P2"><text:span text:style-name="T1">خط تخوردگی و توسط</text:span></text:p> + <text:p text:style-name="P1"><text:span text:style-name="T1">خط تخوردگی وتوسط</text:span></text:p> </draw:text-box> </draw:frame></text:p> - <text:p text:style-name="P4"><draw:frame text:anchor-type="as-char" draw:z-index="2" draw:name="Text Frame 3" draw:style-name="gr1" draw:text-style-name="P3" svg:width="1.2949in" svg:height="0.7051in"> + <text:p text:style-name="Standard"><draw:frame text:anchor-type="as-char" draw:z-index="2" draw:name="Text Frame 3" draw:style-name="gr1" draw:text-style-name="P2" svg:width="1.2949in" svg:height="0.7051in"> <draw:text-box> - <text:p text:style-name="P2"><text:span text:style-name="T1">خط تخوردگی و توسط</text:span></text:p> + <text:p text:style-name="P1"><text:span text:style-name="T1">خط تخوردگی وتوسط</text:span></text:p> </draw:text-box> </draw:frame></text:p> - <text:p text:style-name="P4"><draw:frame text:anchor-type="as-char" draw:z-index="3" draw:name="Text Frame 4" draw:style-name="gr1" draw:text-style-name="P3" svg:width="1.2949in" svg:height="1.1161in"> + <text:p text:style-name="Standard"><draw:frame text:anchor-type="as-char" draw:z-index="3" draw:name="Text Frame 4" draw:style-name="gr2" draw:text-style-name="P2" svg:width="1.2949in" svg:height="1.1161in"> <draw:text-box> - <text:p text:style-name="P2"><text:span text:style-name="T2">خط</text:span><text:span text:style-name="T1"> تخوردگی و توسط</text:span></text:p> + <text:p text:style-name="P1"><text:span text:style-name="T2">خط</text:span><text:span text:style-name="T1"> تخوردگی وتوسط</text:span></text:p> </draw:text-box> </draw:frame></text:p> - <text:p text:style-name="P4"/> + <text:p text:style-name="Standard"/> </office:text> </office:body> </office:document> \ No newline at end of file diff --git a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx index 514280ac930f..1dc24cb8aeca 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx @@ -5677,29 +5677,29 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf151748KashidaSpace) CPPUNIT_ASSERT_EQUAL(17, nTextObjectCount); // Box 1: Not enough room for kashida - CPPUNIT_ASSERT_EQUAL(u"خط تخوردگی و"_ustr, aText.at(0).trim()); - CPPUNIT_ASSERT_EQUAL(u"توسط"_ustr, aText.at(1).trim()); + CPPUNIT_ASSERT_EQUAL(u"خط تخوردگی"_ustr, aText.at(0).trim()); + CPPUNIT_ASSERT_EQUAL(u"وتوسط"_ustr, aText.at(1).trim()); // Box 2: One kashida toward end - CPPUNIT_ASSERT_EQUAL(u"وردگی و"_ustr, aText.at(2).trim()); + CPPUNIT_ASSERT_EQUAL(u"وردگی"_ustr, aText.at(2).trim()); CPPUNIT_ASSERT_EQUAL(u""_ustr, aText.at(3).trim()); // Kashida CPPUNIT_ASSERT_EQUAL(u"خط تخ"_ustr, aText.at(4).trim()); - CPPUNIT_ASSERT_EQUAL(u"توسط"_ustr, aText.at(5).trim()); + CPPUNIT_ASSERT_EQUAL(u"وتوسط"_ustr, aText.at(5).trim()); // Box 3: Two kashida - CPPUNIT_ASSERT_EQUAL(u"وردگی و"_ustr, aText.at(6).trim()); + CPPUNIT_ASSERT_EQUAL(u"وردگی"_ustr, aText.at(6).trim()); CPPUNIT_ASSERT_EQUAL(u""_ustr, aText.at(7).trim()); // Kashida CPPUNIT_ASSERT_EQUAL(u"ط تخ"_ustr, aText.at(8).trim()); CPPUNIT_ASSERT_EQUAL(u""_ustr, aText.at(9).trim()); // Kashida CPPUNIT_ASSERT_EQUAL(u"خ"_ustr, aText.at(10).trim()); - CPPUNIT_ASSERT_EQUAL(u"توسط"_ustr, aText.at(11).trim()); + CPPUNIT_ASSERT_EQUAL(u"وتوسط"_ustr, aText.at(11).trim()); // Box 4: One kashida (text size change) CPPUNIT_ASSERT_EQUAL(u"خط"_ustr, aText.at(12).trim()); - CPPUNIT_ASSERT_EQUAL(u"وردگی و"_ustr, aText.at(13).trim()); + CPPUNIT_ASSERT_EQUAL(u"وردگی"_ustr, aText.at(13).trim()); CPPUNIT_ASSERT_EQUAL(u""_ustr, aText.at(14).trim()); // Kashida CPPUNIT_ASSERT_EQUAL(u"تخ"_ustr, aText.at(15).trim()); - CPPUNIT_ASSERT_EQUAL(u"توسط"_ustr, aText.at(16).trim()); + CPPUNIT_ASSERT_EQUAL(u"وتوسط"_ustr, aText.at(16).trim()); } // tdf#163105 - Writer kashida justification should expand spaces diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx index b75a7863bcb2..b3d4022eb53b 100644 --- a/vcl/source/outdev/font.cxx +++ b/vcl/source/outdev/font.cxx @@ -1159,53 +1159,6 @@ tools::Long OutputDevice::GetMinKashida() const return ImplDevicePixelToLogicWidth(nKashidaWidth); } -sal_Int32 OutputDevice::ValidateKashidas(const OUString& rTxt, sal_Int32 nIdx, sal_Int32 nLen, - sal_Int32 nPartIdx, sal_Int32 nPartLen, - std::span<const sal_Int32> pKashidaPos, - std::vector<sal_Int32>* pKashidaPosDropped) const -{ - pKashidaPosDropped->clear(); - - // do layout - std::unique_ptr<SalLayout> pSalLayout = ImplLayout( rTxt, nIdx, nLen ); - if( !pSalLayout ) - return 0; - - auto nEnd = nIdx + nLen; - auto nPartEnd = nPartIdx + nPartLen; - sal_Int32 nDropped = 0; - for (auto nPos : pKashidaPos) - { - auto nNextPos = nPos + 1; - - // Skip combining marks to find the next character after this position. - while (nNextPos < nEnd - && u_getIntPropertyValue(rTxt[nNextPos], UCHAR_JOINING_TYPE) == U_JT_TRANSPARENT) - { - nNextPos++; - } - - // tdf#124116: We now apply OpenType features across different layouts. Positions past the - // end of the layout must be validated. - - // Currently, kashidas cannot be inserted if the grapheme cluster indicated by nPos is - // split across multiple layouts. Reject any such position. - if (nNextPos > nPartEnd) - { - pKashidaPosDropped->push_back(nPos); - ++nDropped; - } - - // Check the glyph flags from HarfBuzz in all other situations. - if (!pSalLayout->IsKashidaPosValid(nPos, nNextPos)) - { - pKashidaPosDropped->push_back(nPos); - ++nDropped; - } - } - return nDropped; -} - // tdf#163105: Get map of valid kashida positions for a single word void OutputDevice::GetWordKashidaPositions(const OUString& rText, std::vector<bool>* pOutMap) const