summaryrefslogtreecommitdiff
path: root/editeng
diff options
context:
space:
mode:
authorJonathan Clark <jonathan@libreoffice.org>2024-08-30 00:21:12 -0600
committerJonathan Clark <jonathan@libreoffice.org>2024-08-30 16:17:21 +0200
commit937023bca427f803a9e7085d5090d5d2b17623ed (patch)
tree99238d531da81f11bfef7fd7f45dfb546967e709 /editeng
parent6475adeb03962c6c1aa1696e4b96928b9a3286ef (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.hxx3
-rw-r--r--editeng/source/editeng/impedit3.cxx40
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();