tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / i18npool / source / transliteration / transliterationImpl.cxx
blob0b2f40683a76291d290aff90aa7338c04a2245e3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <transliterationImpl.hxx>
22 #include <servicename.hxx>
24 #include <com/sun/star/i18n/LocaleData2.hpp>
25 #include <com/sun/star/i18n/TransliterationType.hpp>
26 #include <com/sun/star/i18n/TransliterationModulesExtra.hpp>
28 #include <comphelper/sequence.hxx>
29 #include <cppuhelper/supportsservice.hxx>
30 #include <o3tl/string_view.hxx>
31 #include <rtl/ustring.hxx>
33 #include <algorithm>
34 #include <mutex>
35 #include <numeric>
37 using namespace com::sun::star::uno;
38 using namespace com::sun::star::i18n;
39 using namespace com::sun::star::lang;
42 namespace i18npool {
44 #define TmItem1( name ) \
45 {TransliterationModules_##name, TransliterationModulesNew_##name, #name}
47 #define TmItem2( name ) \
48 {TransliterationModules(0), TransliterationModulesNew_##name, #name}
50 namespace {
52 // Ignore Module list
53 struct TMList {
54 TransliterationModules tm;
55 TransliterationModulesNew tmn;
56 const char *implName;
61 TMList const TMlist[] = { // Modules ModulesNew
62 TmItem1 (IGNORE_CASE), // 0. (1<<8 256) (7)
63 TmItem1 (IGNORE_WIDTH), // 1. (1<<9 512) (8)
64 TmItem1 (IGNORE_KANA), // 2. (1<<10 1024) (9)
65 // No enum define for this trans. application has to use impl name to load it
66 // TmItem1 (IGNORE_CASE_SIMPLE), // (1<<11 1024) (66)
68 {TransliterationModules_IgnoreTraditionalKanji_ja_JP,
69 TransliterationModulesNew_IgnoreTraditionalKanji_ja_JP, "ignoreTraditionalKanji_ja_JP"},
70 // 3. (1<<12 4096) (10)
71 {TransliterationModules_IgnoreTraditionalKana_ja_JP,
72 TransliterationModulesNew_IgnoreTraditionalKana_ja_JP, "ignoreTraditionalKana_ja_JP"},
73 // 4. (1<<13 8192) (11)
74 {TransliterationModules_IgnoreMinusSign_ja_JP, TransliterationModulesNew_IgnoreMinusSign_ja_JP,
75 "ignoreMinusSign_ja_JP"}, // 5. (1<<13 16384) (12)
76 {TransliterationModules_IgnoreIterationMark_ja_JP,
77 TransliterationModulesNew_IgnoreIterationMark_ja_JP, "ignoreIterationMark_ja_JP"},
78 // 6. (1<<14 32768) (13)
79 {TransliterationModules_IgnoreSeparator_ja_JP, TransliterationModulesNew_IgnoreSeparator_ja_JP,
80 "ignoreSeparator_ja_JP"}, // 7. (1<<15 65536) (14)
81 {TransliterationModules_IgnoreSize_ja_JP, TransliterationModulesNew_IgnoreSize_ja_JP,
82 "ignoreSize_ja_JP"}, // 15. (1<<23 16777216) (22)
83 {TransliterationModules_IgnoreMiddleDot_ja_JP, TransliterationModulesNew_IgnoreMiddleDot_ja_JP,
84 "ignoreMiddleDot_ja_JP"}, // 17. (1<<25 67108864) (24)
85 {TransliterationModules_IgnoreSpace_ja_JP, TransliterationModulesNew_IgnoreSpace_ja_JP,
86 "ignoreSpace_ja_JP"}, // 18. (1<<26 134217728) (25)
87 {TransliterationModules_IgnoreZiZu_ja_JP, TransliterationModulesNew_IgnoreZiZu_ja_JP,
88 "ignoreZiZu_ja_JP"}, // 8. (1<<16 131072) (15)
89 {TransliterationModules_IgnoreBaFa_ja_JP, TransliterationModulesNew_IgnoreBaFa_ja_JP,
90 "ignoreBaFa_ja_JP"}, // 9. (1<<17 262144) (16)
91 {TransliterationModules_IgnoreTiJi_ja_JP, TransliterationModulesNew_IgnoreTiJi_ja_JP,
92 "ignoreTiJi_ja_JP"}, // 10. (1<<18 524288) (17)
93 {TransliterationModules_IgnoreHyuByu_ja_JP, TransliterationModulesNew_IgnoreHyuByu_ja_JP,
94 "ignoreHyuByu_ja_JP"}, // 11. (1<<19 1048576) (18)
95 {TransliterationModules_IgnoreSeZe_ja_JP, TransliterationModulesNew_IgnoreSeZe_ja_JP,
96 "ignoreSeZe_ja_JP"}, // 12. (1<<20 2097152) (19)
97 {TransliterationModules_IgnoreIandEfollowedByYa_ja_JP,
98 TransliterationModulesNew_IgnoreIandEfollowedByYa_ja_JP, "ignoreIandEfollowedByYa_ja_JP"},
99 // 13. (1<<21 4194304) (20)
100 {TransliterationModules_IgnoreKiKuFollowedBySa_ja_JP,
101 TransliterationModulesNew_IgnoreKiKuFollowedBySa_ja_JP, "ignoreKiKuFollowedBySa_ja_JP"},
102 // 14. (1<<22 8388608) (21)
103 {TransliterationModules_IgnoreProlongedSoundMark_ja_JP,
104 TransliterationModulesNew_IgnoreProlongedSoundMark_ja_JP, "ignoreProlongedSoundMark_ja_JP"},
105 // 16. (1<<24 33554432) (23)
107 TmItem1 (UPPERCASE_LOWERCASE), // 19. (1) (1)
108 TmItem1 (LOWERCASE_UPPERCASE), // 20. (2) (2)
109 TmItem1 (HALFWIDTH_FULLWIDTH), // 21. (3) (3)
110 TmItem1 (FULLWIDTH_HALFWIDTH), // 22. (4) (4)
111 TmItem1 (KATAKANA_HIRAGANA), // 23. (5) (5)
112 TmItem1 (HIRAGANA_KATAKANA), // 24. (6) (6)
114 {TransliterationModules_SmallToLarge_ja_JP, TransliterationModulesNew_SmallToLarge_ja_JP,
115 "smallToLarge_ja_JP"}, // 25. (1<<27 268435456) (26)
116 {TransliterationModules_LargeToSmall_ja_JP, TransliterationModulesNew_LargeToSmall_ja_JP,
117 "largeToSmall_ja_JP"}, // 26. (1<<28 536870912) (27)
118 TmItem2 (NumToTextLower_zh_CN), // 27. () (28)
119 TmItem2 (NumToTextUpper_zh_CN), // 28. () (29)
120 TmItem2 (NumToTextLower_zh_TW), // 29. () (30)
121 TmItem2 (NumToTextUpper_zh_TW), // 30. () (31)
122 TmItem2 (NumToTextFormalHangul_ko), // 31. () (32)
123 TmItem2 (NumToTextFormalLower_ko), // 32. () (33)
124 TmItem2 (NumToTextFormalUpper_ko), // 33. () (34)
125 TmItem2 (NumToTextInformalHangul_ko), // 34. () (35)
126 TmItem2 (NumToTextInformalLower_ko), // 35. () (36)
127 TmItem2 (NumToTextInformalUpper_ko), // 36. () (37)
128 TmItem2 (NumToCharLower_zh_CN), // 37. () (38)
129 TmItem2 (NumToCharUpper_zh_CN), // 38. () (39)
130 TmItem2 (NumToCharLower_zh_TW), // 39. () (40)
131 TmItem2 (NumToCharUpper_zh_TW), // 40. () (41)
132 TmItem2 (NumToCharHangul_ko), // 41. () (42)
133 TmItem2 (NumToCharLower_ko), // 42. () (43)
134 TmItem2 (NumToCharUpper_ko), // 43. () (44)
135 TmItem2 (NumToCharFullwidth), // 44. () (45)
136 TmItem2 (NumToCharKanjiShort_ja_JP), // 45. () (46)
137 TmItem2 (TextToNumLower_zh_CN), // 46. () (47)
138 TmItem2 (TextToNumUpper_zh_CN), // 47. () (48)
139 TmItem2 (TextToNumLower_zh_TW), // 48. () (49)
140 TmItem2 (TextToNumUpper_zh_TW), // 49. () (50)
141 TmItem2 (TextToNumFormalHangul_ko), // 50. () (51)
142 TmItem2 (TextToNumFormalLower_ko), // 51. () (52)
143 TmItem2 (TextToNumFormalUpper_ko), // 52. () (53)
144 TmItem2 (TextToNumInformalHangul_ko), // 53. () (54)
145 TmItem2 (TextToNumInformalLower_ko), // 54. () (55)
146 TmItem2 (TextToNumInformalUpper_ko), // 55. () (56)
148 TmItem2 (CharToNumLower_zh_CN), // 56. () (59)
149 TmItem2 (CharToNumUpper_zh_CN), // 57. () (60)
150 TmItem2 (CharToNumLower_zh_TW), // 58. () (61)
151 TmItem2 (CharToNumUpper_zh_TW), // 59. () (62)
152 TmItem2 (CharToNumHangul_ko), // 60. () (63)
153 TmItem2 (CharToNumLower_ko), // 61. () (64)
154 TmItem2 (CharToNumUpper_ko), // 62. () (65)
156 // no enum defined for these trans. application has to use impl name to load them
157 // TmItem2 (NumToCharArabic_Indic), // () (67)
158 // TmItem2 (NumToCharEstern_Arabic_Indic),// () (68)
159 // TmItem2 (NumToCharIndic), // () (69)
160 // TmItem2 (NumToCharThai), // () (70)
161 {TransliterationModules(0), TransliterationModulesNew(0), nullptr}
164 // Constructor/Destructor
165 TransliterationImpl::TransliterationImpl(const Reference <XComponentContext>& xContext) : mxContext(xContext)
167 numCascade = 0;
168 caseignoreOnly = true;
170 mxLocaledata.set(LocaleData2::create(xContext));
173 TransliterationImpl::~TransliterationImpl()
175 mxLocaledata.clear();
176 clear();
180 // Methods
181 OUString SAL_CALL
182 TransliterationImpl::getName()
184 if (numCascade == 1 && bodyCascade[0].is())
185 return bodyCascade[0]->getName();
186 if (numCascade < 1)
187 return ( u"Not Loaded"_ustr);
188 throw RuntimeException();
191 sal_Int16 SAL_CALL
192 TransliterationImpl::getType()
194 if (numCascade > 1)
195 return (TransliterationType::CASCADE|TransliterationType::IGNORE);
196 if (numCascade > 0 && bodyCascade[0].is())
197 return bodyCascade[0]->getType();
198 throw RuntimeException();
201 static TransliterationModules operator&(TransliterationModules lhs, TransliterationModules rhs) {
202 return TransliterationModules(sal_Int32(lhs) & sal_Int32(rhs));
204 static TransliterationModules operator|(TransliterationModules lhs, TransliterationModules rhs) {
205 return TransliterationModules(sal_Int32(lhs) | sal_Int32(rhs));
208 void SAL_CALL
209 TransliterationImpl::loadModule( TransliterationModules modType, const Locale& rLocale )
211 clear();
212 if (bool(modType & TransliterationModules_IGNORE_MASK) &&
213 bool(modType & TransliterationModules_NON_IGNORE_MASK))
215 throw RuntimeException();
216 } else if (bool(modType & TransliterationModules_IGNORE_MASK)) {
217 #define TransliterationModules_IGNORE_CASE_MASK (TransliterationModules_IGNORE_CASE | \
218 TransliterationModules_IGNORE_WIDTH | \
219 TransliterationModules_IGNORE_KANA)
220 TransliterationModules mask = ((modType & TransliterationModules_IGNORE_CASE_MASK) == modType) ?
221 TransliterationModules_IGNORE_CASE_MASK : TransliterationModules_IGNORE_MASK;
222 for (sal_Int16 i = 0; bool(TMlist[i].tm & mask); i++) {
223 if (bool(modType & TMlist[i].tm))
224 if (loadModuleByName(OUString::createFromAscii(TMlist[i].implName),
225 bodyCascade[numCascade], rLocale))
226 numCascade++;
228 // additional transliterations from TransliterationModulesExtra (we cannot extend TransliterationModules)
229 if (bool(modType & TransliterationModules(TransliterationModulesExtra::IGNORE_DIACRITICS_CTL)))
231 if (loadModuleByName(u"ignoreDiacritics_CTL", bodyCascade[numCascade], rLocale))
232 numCascade++;
234 if (bool(modType & TransliterationModules(TransliterationModulesExtra::IGNORE_KASHIDA_CTL)))
235 if (loadModuleByName(u"ignoreKashida_CTL", bodyCascade[numCascade], rLocale))
236 numCascade++;
238 } else if (bool(modType & TransliterationModules_NON_IGNORE_MASK)) {
239 for (sal_Int16 i = 0; bool(TMlist[i].tm); i++) {
240 if (TMlist[i].tm == modType) {
241 if (loadModuleByName(OUString::createFromAscii(TMlist[i].implName), bodyCascade[numCascade], rLocale))
242 numCascade++;
243 break;
249 void SAL_CALL
250 TransliterationImpl::loadModuleNew( const Sequence < TransliterationModulesNew > & modType, const Locale& rLocale )
252 clear();
253 TransliterationModules mask = TransliterationModules_END_OF_MODULE;
254 sal_Int32 count = modType.getLength();
255 if (count > maxCascade)
256 throw RuntimeException(); // could not handle more than maxCascade
257 for (sal_Int32 i = 0; i < count; i++) {
258 for (sal_Int16 j = 0; bool(TMlist[j].tmn); j++) {
259 if (TMlist[j].tmn == modType[i]) {
260 if (mask == TransliterationModules_END_OF_MODULE)
261 mask = bool(TMlist[i].tm) && bool(TMlist[i].tm & TransliterationModules_IGNORE_MASK) ?
262 TransliterationModules_IGNORE_MASK : TransliterationModules_NON_IGNORE_MASK;
263 else if (mask == TransliterationModules_IGNORE_MASK &&
264 (TMlist[i].tm&TransliterationModules_IGNORE_MASK) == TransliterationModules_END_OF_MODULE)
265 throw RuntimeException(); // could not mess up ignore trans. with non_ignore trans.
266 if (loadModuleByName(OUString::createFromAscii(TMlist[j].implName), bodyCascade[numCascade], rLocale))
267 numCascade++;
268 break;
274 void SAL_CALL
275 TransliterationImpl::loadModuleByImplName(const OUString& implName, const Locale& rLocale)
277 clear();
278 if (loadModuleByName(implName, bodyCascade[numCascade], rLocale))
279 numCascade++;
283 void SAL_CALL
284 TransliterationImpl::loadModulesByImplNames(const Sequence< OUString >& implNameList, const Locale& rLocale )
286 if (implNameList.getLength() > maxCascade || implNameList.getLength() <= 0)
287 throw RuntimeException();
289 clear();
290 for (const auto& rName : implNameList)
291 if (loadModuleByName(rName, bodyCascade[numCascade], rLocale))
292 numCascade++;
296 Sequence<OUString> SAL_CALL
297 TransliterationImpl::getAvailableModules( const Locale& rLocale, sal_Int16 sType )
299 const Sequence<OUString> translist = mxLocaledata->getTransliterations(rLocale);
300 std::vector<OUString> r;
301 r.reserve(translist.getLength());
302 Reference<XExtendedTransliteration> body;
303 for (const auto& rTrans : translist)
305 if (loadModuleByName(rTrans, body, rLocale)) {
306 if (body->getType() & sType)
307 r.push_back(rTrans);
308 body.clear();
311 return comphelper::containerToSequence(r);
315 OUString SAL_CALL
316 TransliterationImpl::transliterate( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
317 Sequence< sal_Int32 >& offset )
319 if (numCascade == 0)
320 return inStr;
322 if (numCascade == 1)
324 if ( startPos == 0 && nCount == inStr.getLength() )
325 return bodyCascade[0]->transliterate( inStr, 0, nCount, offset);
326 else
328 OUString tmpStr = inStr.copy(startPos, nCount);
329 tmpStr = bodyCascade[0]->transliterate(tmpStr, 0, nCount, offset);
330 if ( startPos )
332 for (sal_Int32 & j : asNonConstRange(offset))
333 j += startPos;
335 return tmpStr;
338 else
340 OUString tmpStr = inStr.copy(startPos, nCount);
342 auto [begin, end] = asNonConstRange(offset);
343 std::iota(begin, end, startPos);
345 Sequence<sal_Int32> from(nCount);
346 Sequence<sal_Int32> to = offset;
347 for (sal_Int32 i = 0; i < numCascade; i++) {
348 tmpStr = bodyCascade[i]->transliterate(tmpStr, 0, nCount, from);
350 nCount = tmpStr.getLength();
352 assert(from.getLength() == nCount);
353 from.swap(to);
354 for (sal_Int32& ix : asNonConstRange(to))
355 ix = from[ix];
357 offset = std::move(to);
358 return tmpStr;
363 OUString SAL_CALL
364 TransliterationImpl::folding( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
365 Sequence< sal_Int32 >& offset )
367 if (numCascade == 0)
368 return inStr;
370 if (offset.getLength() != nCount)
371 offset.realloc(nCount);
372 if (numCascade == 1)
374 if ( startPos == 0 && nCount == inStr.getLength() )
375 return bodyCascade[0]->folding( inStr, 0, nCount, offset);
376 else
378 OUString tmpStr = inStr.copy(startPos, nCount);
379 tmpStr = bodyCascade[0]->folding(tmpStr, 0, nCount, offset);
380 if ( startPos )
382 for (sal_Int32 & j : asNonConstRange(offset))
383 j += startPos;
385 return tmpStr;
388 else
390 OUString tmpStr = inStr.copy(startPos, nCount);
392 auto [begin, end] = asNonConstRange(offset);
393 std::iota(begin, end, startPos);
395 Sequence<sal_Int32> from;
396 Sequence<sal_Int32> to = offset;
398 for (sal_Int32 i = 0; i < numCascade; i++) {
399 tmpStr = bodyCascade[i]->folding(tmpStr, 0, nCount, from);
401 nCount = tmpStr.getLength();
403 assert(from.getLength() == nCount);
404 from.swap(to);
405 for (sal_Int32& ix : asNonConstRange(to))
406 ix = from[ix];
408 offset = std::move(to);
409 return tmpStr;
413 OUString SAL_CALL
414 TransliterationImpl::transliterateString2String( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount )
416 if (numCascade == 0)
417 return inStr;
418 else if (numCascade == 1)
419 return bodyCascade[0]->transliterateString2String( inStr, startPos, nCount);
420 else {
421 OUString tmpStr = bodyCascade[0]->transliterateString2String(inStr, startPos, nCount);
423 for (sal_Int32 i = 1; i < numCascade; i++)
424 tmpStr = bodyCascade[i]->transliterateString2String(tmpStr, 0, tmpStr.getLength());
425 return tmpStr;
429 OUString SAL_CALL
430 TransliterationImpl::transliterateChar2String( sal_Unicode inChar )
432 if (numCascade == 0)
433 return OUString(&inChar, 1);
434 else if (numCascade == 1)
435 return bodyCascade[0]->transliterateChar2String( inChar);
436 else {
437 OUString tmpStr = bodyCascade[0]->transliterateChar2String(inChar);
439 for (sal_Int32 i = 1; i < numCascade; i++)
440 tmpStr = bodyCascade[i]->transliterateString2String(tmpStr, 0, tmpStr.getLength());
441 return tmpStr;
445 sal_Unicode SAL_CALL
446 TransliterationImpl::transliterateChar2Char( sal_Unicode inChar )
448 sal_Unicode tmpChar = inChar;
449 for (sal_Int32 i = 0; i < numCascade; i++)
450 tmpChar = bodyCascade[i]->transliterateChar2Char(tmpChar);
451 return tmpChar;
455 sal_Bool SAL_CALL
456 TransliterationImpl::equals(
457 const OUString& str1, sal_Int32 pos1, sal_Int32 nCount1, sal_Int32& nMatch1,
458 const OUString& str2, sal_Int32 pos2, sal_Int32 nCount2, sal_Int32& nMatch2)
460 // since this is an API function make it user fail safe
461 if ( nCount1 < 0 ) {
462 pos1 += nCount1;
463 nCount1 = -nCount1;
465 if ( nCount2 < 0 ) {
466 pos2 += nCount2;
467 nCount2 = -nCount2;
469 if ( !nCount1 || !nCount2 ||
470 pos1 >= str1.getLength() || pos2 >= str2.getLength() ||
471 pos1 < 0 || pos2 < 0 ) {
472 nMatch1 = nMatch2 = 0;
473 // two empty strings return true, else false
474 return !nCount1 && !nCount2 && pos1 == str1.getLength() && pos2 == str2.getLength();
476 if ( pos1 + nCount1 > str1.getLength() )
477 nCount1 = str1.getLength() - pos1;
478 if ( pos2 + nCount2 > str2.getLength() )
479 nCount2 = str2.getLength() - pos2;
481 if (caseignoreOnly && caseignore.is())
482 return caseignore->equals(str1, pos1, nCount1, nMatch1, str2, pos2, nCount2, nMatch2);
484 Sequence<sal_Int32> offset1, offset2;
486 OUString tmpStr1 = folding(str1, pos1, nCount1, offset1);
487 OUString tmpStr2 = folding(str2, pos2, nCount2, offset2);
488 // Length of offset1 and offset2 may still be 0 if there was no folding
489 // necessary!
491 const sal_Unicode *p1 = tmpStr1.getStr();
492 const sal_Unicode *p2 = tmpStr2.getStr();
493 sal_Int32 i, nLen = ::std::min( tmpStr1.getLength(), tmpStr2.getLength());
494 for (i = 0; i < nLen; ++i, ++p1, ++p2 ) {
495 if (*p1 != *p2) {
496 // return number of matched code points so far
497 nMatch1 = (i < offset1.getLength()) ? offset1.getConstArray()[i] : i;
498 nMatch2 = (i < offset2.getLength()) ? offset2.getConstArray()[i] : i;
499 return false;
502 // i==nLen
503 if ( tmpStr1.getLength() != tmpStr2.getLength() ) {
504 // return number of matched code points so far
505 nMatch1 = (i <= offset1.getLength()) ? offset1.getConstArray()[i-1] + 1 : i;
506 nMatch2 = (i <= offset2.getLength()) ? offset2.getConstArray()[i-1] + 1 : i;
507 return false;
508 } else {
509 nMatch1 = nCount1;
510 nMatch2 = nCount2;
511 return true;
515 Sequence< OUString >
516 TransliterationImpl::getRange(const Sequence< OUString > &inStrs,
517 const sal_Int32 length, sal_Int16 _numCascade)
519 if (_numCascade >= numCascade || ! bodyCascade[_numCascade].is())
520 return inStrs;
522 sal_Int32 j_tmp = 0;
523 constexpr sal_Int32 nMaxOutput = 2;
524 const sal_Int32 nMaxOutputLength = nMaxOutput*length;
525 std::vector<OUString> ostr;
526 ostr.reserve(nMaxOutputLength);
527 for (sal_Int32 j = 0; j < length; j+=2) {
528 const Sequence< OUString > temp = bodyCascade[_numCascade]->transliterateRange(inStrs[j], inStrs[j+1]);
530 for (const auto& rStr : temp) {
531 if ( j_tmp++ >= nMaxOutputLength ) throw RuntimeException();
532 ostr.push_back(rStr);
536 return getRange(comphelper::containerToSequence(ostr), j_tmp, ++_numCascade);
540 Sequence< OUString > SAL_CALL
541 TransliterationImpl::transliterateRange( const OUString& str1, const OUString& str2 )
543 if (numCascade == 1)
544 return bodyCascade[0]->transliterateRange(str1, str2);
546 Sequence< OUString > ostr{ str1, str2 };
548 return getRange(ostr, 2, 0);
552 sal_Int32 SAL_CALL
553 TransliterationImpl::compareSubstring(
554 const OUString& str1, sal_Int32 off1, sal_Int32 len1,
555 const OUString& str2, sal_Int32 off2, sal_Int32 len2)
557 if (caseignoreOnly && caseignore.is())
558 return caseignore->compareSubstring(str1, off1, len1, str2, off2, len2);
560 Sequence <sal_Int32> offset;
562 OUString in_str1 = transliterate(str1, off1, len1, offset);
563 OUString in_str2 = transliterate(str2, off2, len2, offset);
564 const sal_Unicode* unistr1 = in_str1.getStr();
565 const sal_Unicode* unistr2 = in_str2.getStr();
566 sal_Int32 strlen1 = in_str1.getLength();
567 sal_Int32 strlen2 = in_str2.getLength();
569 while (strlen1 && strlen2) {
570 if (*unistr1 != *unistr2)
571 return *unistr1 > *unistr2 ? 1 : -1;
573 unistr1++; unistr2++; strlen1--; strlen2--;
575 return strlen1 == strlen2 ? 0 : (strlen1 > strlen2 ? 1 : -1);
579 sal_Int32 SAL_CALL
580 TransliterationImpl::compareString(const OUString& str1, const OUString& str2 )
582 if (caseignoreOnly && caseignore.is())
583 return caseignore->compareString(str1, str2);
584 else
585 return compareSubstring(str1, 0, str1.getLength(), str2, 0, str2.getLength());
589 void
590 TransliterationImpl::clear()
592 for (sal_Int32 i = 0; i < numCascade; i++)
593 if (bodyCascade[i].is())
594 bodyCascade[i].clear();
595 numCascade = 0;
596 caseignore.clear();
597 caseignoreOnly = true;
600 namespace
602 /** structure to cache the last transliteration body used. */
603 struct TransBody
605 OUString Name;
606 css::uno::Reference< css::i18n::XExtendedTransliteration > Body;
610 void TransliterationImpl::loadBody( OUString const &implName, Reference<XExtendedTransliteration>& body )
612 assert(!implName.isEmpty());
613 static std::mutex transBodyMutex;
614 std::unique_lock guard(transBodyMutex);
615 static TransBody lastTransBody;
616 if (implName != lastTransBody.Name)
618 lastTransBody.Body.set(
619 mxContext->getServiceManager()->createInstanceWithContext(implName, mxContext), UNO_QUERY_THROW);
620 lastTransBody.Name = implName;
622 body = lastTransBody.Body;
625 bool
626 TransliterationImpl::loadModuleByName( std::u16string_view implName,
627 Reference<XExtendedTransliteration>& body, const Locale& rLocale)
629 OUString cname = OUString::Concat(TRLT_IMPLNAME_PREFIX) + implName;
630 loadBody(cname, body);
631 if (body.is()) {
632 body->loadModule(TransliterationModules(0), rLocale); // toUpper/toLoad need rLocale
634 // if the module is ignore case/kana/width, load caseignore for equals/compareString mothed
635 for (sal_Int16 i = 0; i < 3; i++) {
636 if (o3tl::equalsAscii(implName, TMlist[i].implName)) {
637 if (i == 0) // current module is caseignore
638 body->loadModule(TMlist[0].tm, rLocale); // caseignore need to setup module name
639 if (! caseignore.is()) {
640 OUString bname = TRLT_IMPLNAME_PREFIX +
641 OUString::createFromAscii(TMlist[0].implName);
642 loadBody(bname, caseignore);
644 if (caseignore.is())
645 caseignore->loadModule(TMlist[i].tm, rLocale);
646 return true;
649 caseignoreOnly = false; // has other module than just ignore case/kana/width
651 return body.is();
654 OUString SAL_CALL
655 TransliterationImpl::getImplementationName()
657 return u"com.sun.star.i18n.Transliteration"_ustr;
660 sal_Bool SAL_CALL
661 TransliterationImpl::supportsService(const OUString& rServiceName)
663 return cppu::supportsService(this, rServiceName);
666 Sequence< OUString > SAL_CALL
667 TransliterationImpl::getSupportedServiceNames()
669 return { u"com.sun.star.i18n.Transliteration"_ustr };
674 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
675 com_sun_star_i18n_Transliteration_get_implementation(
676 css::uno::XComponentContext *context,
677 css::uno::Sequence<css::uno::Any> const &)
679 return cppu::acquire(new i18npool::TransliterationImpl(context));
682 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */