summaryrefslogtreecommitdiff
path: root/i18nutil/source/utility
diff options
context:
space:
mode:
authorJonathan Clark <jonathan@libreoffice.org>2024-09-26 02:59:26 -0600
committerJonathan Clark <jonathan@libreoffice.org>2024-09-27 03:50:01 +0200
commitc3c29d31d77ff93aa50634cfd51c62d12dc0f6ec (patch)
tree0c938a2c80e3de61c8f6aa6133a187d96ba8fb2f /i18nutil/source/utility
parentd8f430e4bef414616fd80bbf4ea16d767991b5b9 (diff)
tdf#140767 Implemented Syriac justification
This change extends kashida justification to Syriac, using custom insertion rules. Change-Id: I7508d2c32e95abb12a098e989c7153828ba81c87 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173990 Tested-by: Jenkins Reviewed-by: Jonathan Clark <jonathan@libreoffice.org>
Diffstat (limited to 'i18nutil/source/utility')
-rw-r--r--i18nutil/source/utility/kashida.cxx88
1 files changed, 80 insertions, 8 deletions
diff --git a/i18nutil/source/utility/kashida.cxx b/i18nutil/source/utility/kashida.cxx
index 6a6c7adde690..a992e5c8e643 100644
--- a/i18nutil/source/utility/kashida.cxx
+++ b/i18nutil/source/utility/kashida.cxx
@@ -133,10 +133,9 @@ bool CanConnectToPrev(sal_Unicode cCh, sal_Unicode cPrevCh)
return bRet;
}
-}
std::optional<i18nutil::KashidaPosition>
-i18nutil::GetWordKashidaPosition(const OUString& rWord, const std::vector<bool>& pValidPositions)
+GetWordKashidaPositionArabic(const OUString& rWord, const std::vector<bool>& pValidPositions)
{
sal_Int32 nIdx = 0;
sal_Int32 nPrevIdx = 0;
@@ -148,9 +147,6 @@ i18nutil::GetWordKashidaPosition(const OUString& rWord, const std::vector<bool>&
sal_Int32 nWordLen = rWord.getLength();
- SAL_WARN_IF(!pValidPositions.empty() && pValidPositions.size() != static_cast<size_t>(nWordLen),
- "i18n", "Kashida valid position array wrong size");
-
// ignore trailing vowel chars
while (nWordLen && isTransparentChar(rWord[nWordLen - 1]))
{
@@ -298,8 +294,8 @@ i18nutil::GetWordKashidaPosition(const OUString& rWord, const std::vector<bool>&
}
}
- // 8. If valid position data exists, use the last legal position
- if (nPriorityLevel >= 7 && nIdx > 0 && !pValidPositions.empty())
+ // 8. Try any valid position
+ if (nPriorityLevel >= 7 && nIdx > 0)
{
fnTryInsertBefore(7);
}
@@ -317,10 +313,86 @@ i18nutil::GetWordKashidaPosition(const OUString& rWord, const std::vector<bool>&
if (-1 != nKashidaPos)
{
- return KashidaPosition{ nKashidaPos };
+ return i18nutil::KashidaPosition{ nKashidaPos };
}
return std::nullopt;
}
+std::optional<i18nutil::KashidaPosition>
+GetWordKashidaPositionSyriac(const OUString& rWord, const std::vector<bool>& pValidPositions)
+{
+ sal_Int32 nWordLen = rWord.getLength();
+
+ // Search for a user-inserted kashida
+ for (sal_Int32 i = nWordLen - 1; i >= 0; --i)
+ {
+ if (0x640 == rWord[i])
+ {
+ return i18nutil::KashidaPosition{ i };
+ }
+ }
+
+ // Always insert kashida from the outside-in:
+ // - First, work from the end of the word toward the midpoint
+ // - Then, work from the beginning of the word toward the midpoint
+
+ sal_Int32 nWordMidpoint = nWordLen / 2;
+
+ auto fnPositionValid = [&pValidPositions](sal_Int32 nIdx) {
+ // Exclusions:
+
+ // tdf#163105: Do not insert kashida if the position is invalid
+ if (!pValidPositions.empty() && !pValidPositions[nIdx])
+ {
+ return false;
+ }
+
+ return true;
+ };
+
+ // End to midpoint
+ for (sal_Int32 i = nWordLen - 2; i > nWordMidpoint; --i)
+ {
+ if (fnPositionValid(i))
+ {
+ return i18nutil::KashidaPosition{ i };
+ }
+ }
+
+ // Beginning to midpoint
+ for (sal_Int32 i = 0; i <= nWordMidpoint; ++i)
+ {
+ if (fnPositionValid(i))
+ {
+ return i18nutil::KashidaPosition{ i };
+ }
+ }
+
+ return std::nullopt;
+}
+}
+
+std::optional<i18nutil::KashidaPosition>
+i18nutil::GetWordKashidaPosition(const OUString& rWord, const std::vector<bool>& pValidPositions)
+{
+ sal_Int32 nWordLen = rWord.getLength();
+
+ SAL_WARN_IF(!pValidPositions.empty() && pValidPositions.size() != static_cast<size_t>(nWordLen),
+ "i18n", "Kashida valid position array wrong size");
+
+ for (sal_Int32 nIdx = 0; nIdx < nWordLen; ++nIdx)
+ {
+ auto cCh = rWord[nIdx];
+
+ if ((cCh >= 0x700 && cCh <= 0x74F) || (cCh >= 0x860 && cCh <= 0x86A))
+ {
+ // This word contains Syriac characters.
+ return GetWordKashidaPositionSyriac(rWord, pValidPositions);
+ }
+ }
+
+ return GetWordKashidaPositionArabic(rWord, pValidPositions);
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */