diff options
author | Jonathan Clark <jonathan@libreoffice.org> | 2024-08-30 00:21:12 -0600 |
---|---|---|
committer | Jonathan Clark <jonathan@libreoffice.org> | 2024-08-30 16:17:21 +0200 |
commit | 937023bca427f803a9e7085d5090d5d2b17623ed (patch) | |
tree | 99238d531da81f11bfef7fd7f45dfb546967e709 /editeng | |
parent | 6475adeb03962c6c1aa1696e4b96928b9a3286ef (diff) |
tdf#151748 editeng: Improve kashida position validation
Previously, editeng did not validate whether kashida insertion positions
had enough room for at least a single kashida glyph. This caused kashida
glyphs to overlap other characters in some situations.
Editeng will now drop candidate kashida insertion positions from the
beginning of the line, until there is enough room to safely justify the
remaining text. This approximates Writer's behavior.
Change-Id: I804cae72503332bea8dc9e60cdfe08bd3429dc52
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172641
Reviewed-by: Jonathan Clark <jonathan@libreoffice.org>
Tested-by: Jenkins
Diffstat (limited to 'editeng')
-rw-r--r-- | editeng/source/editeng/impedit.hxx | 3 | ||||
-rw-r--r-- | editeng/source/editeng/impedit3.cxx | 40 |
2 files changed, 34 insertions, 9 deletions
diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx index 5ea71794912d..d62edc53419b 100644 --- a/editeng/source/editeng/impedit.hxx +++ b/editeng/source/editeng/impedit.hxx @@ -719,7 +719,8 @@ private: bool ImplHasText() const; - void ImpFindKashidas( ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, std::vector<sal_Int32>& rArray ); + void ImpFindKashidas(ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, + std::vector<sal_Int32>& rArray, sal_Int32 nRemainingSpace); void InsertContent(std::unique_ptr<ContentNode> pNode, sal_Int32 nPos); EditPaM SplitContent( sal_Int32 nNode, sal_Int32 nSepPos ); diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx index d8a89139cd59..3cd8ef12eb4d 100644 --- a/editeng/source/editeng/impedit3.cxx +++ b/editeng/source/editeng/impedit3.cxx @@ -2306,17 +2306,16 @@ void ImpEditEngine::ImpAdjustBlocks(ParaPortion& rParaPortion, EditLine& rLine, std::vector<sal_Int32> aPositions; // Kashidas ? - ImpFindKashidas( pNode, nFirstChar, nLastChar, aPositions ); + ImpFindKashidas(pNode, nFirstChar, nLastChar, aPositions, nRemainingSpace); auto nKashidas = aPositions.size(); sal_uInt16 nLastScript = i18n::ScriptType::LATIN; for ( sal_Int32 nChar = nFirstChar; nChar <= nLastChar; nChar++ ) { EditPaM aPaM( pNode, nChar+1 ); - LanguageType eLang = GetLanguage(aPaM).nLang; sal_uInt16 nScript = GetI18NScriptType(aPaM); // Arabic script is handled above, but if no Kashida positions are found, use blanks. - if (MsLangId::getPrimaryLanguage(eLang) == LANGUAGE_ARABIC_PRIMARY_ONLY && nKashidas) + if (nKashidas) continue; if ( pNode->GetChar(nChar) == ' ' ) @@ -2348,8 +2347,7 @@ void ImpEditEngine::ImpAdjustBlocks(ParaPortion& rParaPortion, EditLine& rLine, // If the last character is a blank, it is rejected! // The width must be distributed to the blockers in front... // But not if it is the only one. - if ( ( pNode->GetChar( nLastChar ) == ' ' ) && ( aPositions.size() > 1 ) && - ( MsLangId::getPrimaryLanguage( GetLanguage( EditPaM( pNode, nLastChar ) ).nLang ) != LANGUAGE_ARABIC_PRIMARY_ONLY ) ) + if ((pNode->GetChar(nLastChar) == ' ') && (aPositions.size() > 1) && (!nKashidas)) { aPositions.pop_back(); sal_Int32 nPortionStart, nPortion; @@ -2427,13 +2425,16 @@ void ImpEditEngine::ImpAdjustBlocks(ParaPortion& rParaPortion, EditLine& rLine, } // For Kashidas from sw/source/core/text/porlay.cxx -void ImpEditEngine::ImpFindKashidas( ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, std::vector<sal_Int32>& rArray ) +void ImpEditEngine::ImpFindKashidas(ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, + std::vector<sal_Int32>& rArray, sal_Int32 nRemainingSpace) { // Kashida glyph looks suspicious, skip Kashida justification if (GetRefDevice()->GetMinKashida() <= 0) return; 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 @@ -2442,6 +2443,7 @@ void ImpEditEngine::ImpFindKashidas( ContentNode* pNode, sal_Int32 nStart, sal_I if ( aWordSel.Min().GetIndex() < nStart ) aWordSel.Min().SetIndex( nStart ); + SvxFont aTmpFont(pNode->GetCharAttribs().GetDefFont()); while ( ( aWordSel.Min().GetNode() == pNode ) && ( aWordSel.Min().GetIndex() < nEnd ) ) { const sal_Int32 nSavPos = aWordSel.Max().GetIndex(); @@ -2599,13 +2601,35 @@ void ImpEditEngine::ImpFindKashidas( ContentNode* pNode, sal_Int32 nStart, sal_I ++nIdx; } // end of current word - if ( nKashidaPos>=0 ) - aKashidaArray.push_back( nKashidaPos ); + if (nKashidaPos >= 0) + { + SeekCursor(pNode, nKashidaPos + 1, aTmpFont); + aTmpFont.SetPhysFont(*GetRefDevice()); + + auto nMinKashidaWidth = GetRefDevice()->GetMinKashida(); + nTotalMinKashida += nMinKashidaWidth; + aMinKashidaArray.push_back(nMinKashidaWidth); + + aKashidaArray.push_back(nKashidaPos); + } aWordSel = WordRight( aWordSel.Max(), css::i18n::WordType::DICTIONARY_WORD ); 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. + 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()); + // Validate std::vector<sal_Int32> aDropped; auto nOldLayout = GetRefDevice()->GetLayoutMode(); |