1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
24 #if OSL_DEBUG_LEVEL > 0
28 #include <cppuhelper/factory.hxx>
29 #include <com/sun/star/beans/XPropertySet.hpp>
30 #include <com/sun/star/uno/XComponentContext.hpp>
31 #include <com/sun/star/linguistic2/XLinguProperties.hpp>
32 #include <com/sun/star/linguistic2/XLinguServiceEventBroadcaster.hpp>
33 #include <rtl/ustrbuf.hxx>
34 #include <i18nlangtag/lang.h>
35 #include <unotools/localedatawrapper.hxx>
36 #include <tools/debug.hxx>
37 #include <svl/lngmisc.hxx>
38 #include <comphelper/processfactory.hxx>
39 #include <comphelper/sequence.hxx>
40 #include <osl/mutex.hxx>
42 #include "hyphdsp.hxx"
43 #include <linguistic/hyphdta.hxx>
44 #include <linguistic/misc.hxx>
45 #include "lngsvcmgr.hxx"
48 using namespace com::sun::star
;
49 using namespace com::sun::star::beans
;
50 using namespace com::sun::star::lang
;
51 using namespace com::sun::star::uno
;
52 using namespace com::sun::star::linguistic2
;
53 using namespace linguistic
;
56 HyphenatorDispatcher::HyphenatorDispatcher( LngSvcMgr
&rLngSvcMgr
) :
62 HyphenatorDispatcher::~HyphenatorDispatcher()
68 void HyphenatorDispatcher::ClearSvcList()
70 // release memory for each table entry
71 HyphSvcByLangMap_t().swap(aSvcMap
);
75 Reference
<XHyphenatedWord
> HyphenatorDispatcher::buildHyphWord(
76 const OUString
& rOrigWord
,
77 const Reference
<XDictionaryEntry
> &xEntry
,
78 LanguageType nLang
, sal_Int16 nMaxLeading
)
80 MutexGuard
aGuard( GetLinguMutex() );
82 Reference
< XHyphenatedWord
> xRes
;
86 OUString
aText( xEntry
->getDictionaryWord() );
87 sal_Int32 nTextLen
= aText
.getLength();
89 // trailing '=' means "hyphenation should not be possible"
90 if (nTextLen
> 0 && aText
[ nTextLen
- 1 ] != '=' && aText
[ nTextLen
- 1 ] != '[')
92 sal_Int16 nHyphenationPos
= -1;
93 sal_Int16 nOrigHyphPos
= -1;
95 OUStringBuffer
aTmp( nTextLen
);
98 sal_Int32 nHyphIdx
= -1;
99 sal_Int32 nLeading
= 0;
100 for (sal_Int32 i
= 0; i
< nTextLen
; i
++)
102 sal_Unicode cTmp
= aText
[i
];
103 if (cTmp
== '[' || cTmp
== ']')
105 if (cTmp
!= '=' && !bSkip2
&& cTmp
!= ']')
114 if (!bSkip
&& nHyphIdx
>= 0)
116 if (nLeading
<= nMaxLeading
) {
117 nHyphenationPos
= static_cast<sal_Int16
>(nHyphIdx
);
121 bSkip
= true; //! multiple '=' should count as one only
125 if (nHyphenationPos
> 0)
127 #if OSL_DEBUG_LEVEL > 0
129 if (std::u16string_view(aTmp
) != rOrigWord
)
131 // both words should only differ by a having a trailing '.'
132 // character or not...
133 std::u16string_view
aShorter(aTmp
), aLonger(rOrigWord
);
134 if (aTmp
.getLength() > rOrigWord
.getLength())
135 std::swap(aShorter
, aLonger
);
136 sal_Int32 nS
= aShorter
.size();
137 sal_Int32 nL
= aLonger
.size();
138 if (nS
> 0 && nL
> 0)
140 assert( ((nS
+ 1 == nL
) && aLonger
[nL
-1] == '.') && "HyphenatorDispatcher::buildHyphWord: unexpected difference between words!" );
145 sal_Int32 nHyphenPos
= -1;
146 if (aText
[ nOrigHyphPos
] == '[') // alternative hyphenation
149 sal_Unicode c
= aText
[ nOrigHyphPos
+ 1 ];
150 sal_Int32 endhyphpat
= aText
.indexOf( ']', nOrigHyphPos
);
151 if ('0' <= c
&& c
<= '9')
158 OUStringBuffer
aTmp2 ( aTmp
.copy(0, std::max (nHyphenationPos
+ 1 - split
, 0) ) );
159 aTmp2
.append( aText
.subView( nOrigHyphPos
+ 1, endhyphpat
- nOrigHyphPos
- 1) );
160 nHyphenPos
= aTmp2
.getLength();
161 aTmp2
.append( aTmp
.subView( nHyphenationPos
+ 1 ) );
162 //! take care of #i22591#
163 if (rOrigWord
[ rOrigWord
.getLength() - 1 ] == '.')
165 aText
= aTmp2
.makeStringAndClear();
168 if (nHyphenPos
== -1)
171 xRes
= new HyphenatedWord( rOrigWord
, nLang
, nHyphenationPos
,
172 aText
, (nHyphenPos
> -1) ? nHyphenPos
- 1 : nHyphenationPos
);
181 Reference
< XPossibleHyphens
> HyphenatorDispatcher::buildPossHyphens(
182 const Reference
< XDictionaryEntry
> &xEntry
, LanguageType nLanguage
)
184 MutexGuard
aGuard( GetLinguMutex() );
186 Reference
<XPossibleHyphens
> xRes
;
190 // text with hyphenation info
191 OUString
aText( xEntry
->getDictionaryWord() );
192 sal_Int32 nTextLen
= aText
.getLength();
194 // trailing '=' means "hyphenation should not be possible"
195 if (nTextLen
> 0 && aText
[ nTextLen
- 1 ] != '=' && aText
[ nTextLen
- 1 ] != '[')
197 // sequence to hold hyphenation positions
198 Sequence
< sal_Int16
> aHyphPos( nTextLen
);
199 sal_Int16
*pPos
= aHyphPos
.getArray();
200 sal_Int32 nHyphCount
= 0;
202 OUStringBuffer
aTmp( nTextLen
);
205 sal_Int32 nHyphIdx
= -1;
206 for (sal_Int32 i
= 0; i
< nTextLen
; i
++)
208 sal_Unicode cTmp
= aText
[i
];
209 if (cTmp
== '[' || cTmp
== ']')
211 if (cTmp
!= '=' && !bSkip2
&& cTmp
!= ']')
219 if (!bSkip
&& nHyphIdx
>= 0)
220 pPos
[ nHyphCount
++ ] = static_cast<sal_Int16
>(nHyphIdx
);
221 bSkip
= true; //! multiple '=' should count as one only
225 // ignore (multiple) trailing '='
226 if (bSkip
&& nHyphIdx
>= 0)
230 DBG_ASSERT( nHyphCount
>= 0, "lng : invalid hyphenation count");
234 aHyphPos
.realloc( nHyphCount
);
235 xRes
= new PossibleHyphens( aTmp
.makeStringAndClear(), nLanguage
,
245 Sequence
< Locale
> SAL_CALL
HyphenatorDispatcher::getLocales()
247 MutexGuard
aGuard( GetLinguMutex() );
249 std::vector
<Locale
> aLocales
;
250 aLocales
.reserve(aSvcMap
.size());
252 std::transform(aSvcMap
.begin(), aSvcMap
.end(), std::back_inserter(aLocales
),
253 [](HyphSvcByLangMap_t::const_reference elem
) { return LanguageTag::convertToLocale(elem
.first
); });
255 return comphelper::containerToSequence(aLocales
);
259 sal_Bool SAL_CALL
HyphenatorDispatcher::hasLocale(const Locale
& rLocale
)
261 MutexGuard
aGuard( GetLinguMutex() );
262 HyphSvcByLangMap_t::const_iterator
aIt( aSvcMap
.find( LinguLocaleToLanguage( rLocale
) ) );
263 return aIt
!= aSvcMap
.end();
267 Reference
< XHyphenatedWord
> SAL_CALL
268 HyphenatorDispatcher::hyphenate(
269 const OUString
& rWord
, const Locale
& rLocale
, sal_Int16 nMaxLeading
,
270 const css::uno::Sequence
< ::css::beans::PropertyValue
>& rProperties
)
272 MutexGuard
aGuard( GetLinguMutex() );
274 Reference
< XHyphenatedWord
> xRes
;
276 sal_Int32 nWordLen
= rWord
.getLength();
277 LanguageType nLanguage
= LinguLocaleToLanguage( rLocale
);
278 if (LinguIsUnspecified(nLanguage
) || !nWordLen
||
279 nMaxLeading
== 0 || nMaxLeading
== nWordLen
)
282 // search for entry with that language
283 HyphSvcByLangMap_t::iterator
aIt( aSvcMap
.find( nLanguage
) );
284 LangSvcEntries_Hyph
*pEntry
= aIt
!= aSvcMap
.end() ? aIt
->second
.get() : nullptr;
286 bool bWordModified
= false;
287 if (!pEntry
|| (nMaxLeading
< 0 || nMaxLeading
> nWordLen
))
293 OUString
aChkWord( rWord
);
295 // replace typographical apostroph by ascii apostroph
296 OUString
aSingleQuote( GetLocaleDataWrapper( nLanguage
).getQuotationMarkEnd() );
297 DBG_ASSERT( 1 == aSingleQuote
.getLength(), "unexpected length of quotation mark" );
298 if (!aSingleQuote
.isEmpty())
299 aChkWord
= aChkWord
.replace( aSingleQuote
[0], '\'' );
301 bWordModified
|= RemoveHyphens( aChkWord
);
302 if (IsIgnoreControlChars( rProperties
, GetPropSet() ))
303 bWordModified
|= RemoveControlChars( aChkWord
);
304 sal_Int16 nChkMaxLeading
= static_cast<sal_Int16
>(GetPosInWordToCheck( rWord
, nMaxLeading
));
306 // check for results from (positive) dictionaries which have precedence!
307 Reference
< XDictionaryEntry
> xEntry
;
309 if (GetDicList().is() && IsUseDicList( rProperties
, GetPropSet() ))
311 xEntry
= GetDicList()->queryDictionaryEntry( aChkWord
, rLocale
,
317 //! because queryDictionaryEntry (in the end DictionaryNeo::getEntry)
318 //! does not distinguish between "XYZ" and "XYZ." in order to avoid
319 //! to require them as different entry we have to supply the
320 //! original word here as well so it can be used in th result
321 //! otherwise a strange effect may occur (see #i22591#)
322 xRes
= buildHyphWord( rWord
, xEntry
, nLanguage
, nChkMaxLeading
);
326 sal_Int32 nLen
= pEntry
->aSvcImplNames
.hasElements() ? 1 : 0;
327 DBG_ASSERT( pEntry
->nLastTriedSvcIndex
< nLen
,
328 "lng : index out of range");
331 Reference
< XHyphenator
> xHyph
;
332 if (pEntry
->aSvcRefs
.hasElements())
333 xHyph
= pEntry
->aSvcRefs
[0];
335 // try already instantiated service
336 if (i
<= pEntry
->nLastTriedSvcIndex
)
338 if (xHyph
.is() && xHyph
->hasLocale( rLocale
))
339 xRes
= xHyph
->hyphenate( aChkWord
, rLocale
, nChkMaxLeading
,
343 else if (pEntry
->nLastTriedSvcIndex
< nLen
- 1)
344 // instantiate services and try it
346 Reference
< XHyphenator
> *pRef
= pEntry
->aSvcRefs
.getArray();
348 Reference
< XComponentContext
> xContext(
349 comphelper::getProcessComponentContext() );
351 // build service initialization argument
352 Sequence
< Any
> aArgs(2);
353 aArgs
.getArray()[0] <<= GetPropSet();
355 // create specific service via it's implementation name
358 xHyph
= Reference
< XHyphenator
>(
359 xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
360 pEntry
->aSvcImplNames
[0], aArgs
, xContext
),
363 catch (uno::Exception
&)
365 SAL_WARN( "linguistic", "createInstanceWithArguments failed" );
369 Reference
< XLinguServiceEventBroadcaster
>
370 xBroadcaster( xHyph
, UNO_QUERY
);
371 if (xBroadcaster
.is())
372 rMgr
.AddLngSvcEvtBroadcaster( xBroadcaster
);
374 if (xHyph
.is() && xHyph
->hasLocale( rLocale
))
375 xRes
= xHyph
->hyphenate( aChkWord
, rLocale
, nChkMaxLeading
,
378 pEntry
->nLastTriedSvcIndex
= static_cast<sal_Int16
>(i
);
381 // if language is not supported by the services
382 // remove it from the list.
383 if (xHyph
.is() && !xHyph
->hasLocale( rLocale
))
384 aSvcMap
.erase( nLanguage
);
386 } // if (xEntry.is())
389 if (bWordModified
&& xRes
.is())
390 xRes
= RebuildHyphensAndControlChars( rWord
, xRes
);
392 if (xRes
.is() && xRes
->getWord() != rWord
)
394 xRes
= new HyphenatedWord( rWord
, nLanguage
, xRes
->getHyphenationPos(),
395 xRes
->getHyphenatedWord(),
396 xRes
->getHyphenPos() );
403 Reference
< XHyphenatedWord
> SAL_CALL
404 HyphenatorDispatcher::queryAlternativeSpelling(
405 const OUString
& rWord
, const Locale
& rLocale
, sal_Int16 nIndex
,
406 const css::uno::Sequence
< ::css::beans::PropertyValue
>& rProperties
)
408 MutexGuard
aGuard( GetLinguMutex() );
410 Reference
< XHyphenatedWord
> xRes
;
412 sal_Int32 nWordLen
= rWord
.getLength();
413 LanguageType nLanguage
= LinguLocaleToLanguage( rLocale
);
414 if (LinguIsUnspecified(nLanguage
) || !nWordLen
)
417 // search for entry with that language
418 HyphSvcByLangMap_t::iterator
aIt( aSvcMap
.find( nLanguage
) );
419 LangSvcEntries_Hyph
*pEntry
= aIt
!= aSvcMap
.end() ? aIt
->second
.get() : nullptr;
421 bool bWordModified
= false;
422 if (!pEntry
|| 0 > nIndex
|| nIndex
> nWordLen
- 2)
428 OUString
aChkWord( rWord
);
430 // replace typographical apostroph by ascii apostroph
431 OUString
aSingleQuote( GetLocaleDataWrapper( nLanguage
).getQuotationMarkEnd() );
432 DBG_ASSERT( 1 == aSingleQuote
.getLength(), "unexpected length of quotation mark" );
433 if (!aSingleQuote
.isEmpty())
434 aChkWord
= aChkWord
.replace( aSingleQuote
[0], '\'' );
436 bWordModified
|= RemoveHyphens( aChkWord
);
437 if (IsIgnoreControlChars( rProperties
, GetPropSet() ))
438 bWordModified
|= RemoveControlChars( aChkWord
);
439 sal_Int16 nChkIndex
= static_cast<sal_Int16
>(GetPosInWordToCheck( rWord
, nIndex
));
441 // check for results from (positive) dictionaries which have precedence!
442 Reference
< XDictionaryEntry
> xEntry
;
444 if (GetDicList().is() && IsUseDicList( rProperties
, GetPropSet() ))
446 xEntry
= GetDicList()->queryDictionaryEntry( aChkWord
, rLocale
,
452 xRes
= buildHyphWord(aChkWord
, xEntry
, nLanguage
, nIndex
+ 1);
453 if (xRes
.is() && xRes
->isAlternativeSpelling() && xRes
->getHyphenationPos() == nIndex
)
458 sal_Int32 nLen
= pEntry
->aSvcImplNames
.hasElements() ? 1 : 0;
459 DBG_ASSERT( pEntry
->nLastTriedSvcIndex
< nLen
,
460 "lng : index out of range");
463 Reference
< XHyphenator
> xHyph
;
464 if (pEntry
->aSvcRefs
.hasElements())
465 xHyph
= pEntry
->aSvcRefs
[0];
467 // try already instantiated service
468 if (i
<= pEntry
->nLastTriedSvcIndex
)
470 if (xHyph
.is() && xHyph
->hasLocale( rLocale
))
471 xRes
= xHyph
->queryAlternativeSpelling( aChkWord
, rLocale
,
472 nChkIndex
, rProperties
);
475 else if (pEntry
->nLastTriedSvcIndex
< nLen
- 1)
476 // instantiate services and try it
478 Reference
< XHyphenator
> *pRef
= pEntry
->aSvcRefs
.getArray();
480 Reference
< XComponentContext
> xContext(
481 comphelper::getProcessComponentContext() );
483 // build service initialization argument
484 Sequence
< Any
> aArgs(2);
485 aArgs
.getArray()[0] <<= GetPropSet();
487 // create specific service via it's implementation name
490 xHyph
= Reference
< XHyphenator
>(
491 xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
492 pEntry
->aSvcImplNames
[0], aArgs
, xContext
), UNO_QUERY
);
494 catch (uno::Exception
&)
496 SAL_WARN( "linguistic", "createInstanceWithArguments failed" );
500 Reference
< XLinguServiceEventBroadcaster
>
501 xBroadcaster( xHyph
, UNO_QUERY
);
502 if (xBroadcaster
.is())
503 rMgr
.AddLngSvcEvtBroadcaster( xBroadcaster
);
505 if (xHyph
.is() && xHyph
->hasLocale( rLocale
))
506 xRes
= xHyph
->queryAlternativeSpelling( aChkWord
, rLocale
,
507 nChkIndex
, rProperties
);
509 pEntry
->nLastTriedSvcIndex
= static_cast<sal_Int16
>(i
);
512 // if language is not supported by the services
513 // remove it from the list.
514 if (xHyph
.is() && !xHyph
->hasLocale( rLocale
))
515 aSvcMap
.erase( nLanguage
);
517 } // if (xEntry.is())
520 if (bWordModified
&& xRes
.is())
521 xRes
= RebuildHyphensAndControlChars( rWord
, xRes
);
523 if (xRes
.is() && xRes
->getWord() != rWord
)
525 xRes
= new HyphenatedWord( rWord
, nLanguage
, xRes
->getHyphenationPos(),
526 xRes
->getHyphenatedWord(),
527 xRes
->getHyphenPos() );
534 Reference
< XPossibleHyphens
> SAL_CALL
535 HyphenatorDispatcher::createPossibleHyphens(
536 const OUString
& rWord
, const Locale
& rLocale
,
537 const css::uno::Sequence
< ::css::beans::PropertyValue
>& rProperties
)
539 MutexGuard
aGuard( GetLinguMutex() );
541 Reference
< XPossibleHyphens
> xRes
;
543 LanguageType nLanguage
= LinguLocaleToLanguage( rLocale
);
544 if (LinguIsUnspecified(nLanguage
) || rWord
.isEmpty())
547 // search for entry with that language
548 HyphSvcByLangMap_t::iterator
aIt( aSvcMap
.find( nLanguage
) );
549 LangSvcEntries_Hyph
*pEntry
= aIt
!= aSvcMap
.end() ? aIt
->second
.get() : nullptr;
553 OUString
aChkWord( rWord
);
555 // replace typographical apostroph by ascii apostroph
556 OUString
aSingleQuote( GetLocaleDataWrapper( nLanguage
).getQuotationMarkEnd() );
557 DBG_ASSERT( 1 == aSingleQuote
.getLength(), "unexpected length of quotation mark" );
558 if (!aSingleQuote
.isEmpty())
559 aChkWord
= aChkWord
.replace( aSingleQuote
[0], '\'' );
561 RemoveHyphens( aChkWord
);
562 if (IsIgnoreControlChars( rProperties
, GetPropSet() ))
563 RemoveControlChars( aChkWord
);
565 // check for results from (positive) dictionaries which have precedence!
566 Reference
< XDictionaryEntry
> xEntry
;
568 if (GetDicList().is() && IsUseDicList( rProperties
, GetPropSet() ))
570 xEntry
= GetDicList()->queryDictionaryEntry( aChkWord
, rLocale
,
576 xRes
= buildPossHyphens( xEntry
, nLanguage
);
580 sal_Int32 nLen
= pEntry
->aSvcImplNames
.hasElements() ? 1 : 0;
581 DBG_ASSERT( pEntry
->nLastTriedSvcIndex
< nLen
,
582 "lng : index out of range");
585 Reference
< XHyphenator
> xHyph
;
586 if (pEntry
->aSvcRefs
.hasElements())
587 xHyph
= pEntry
->aSvcRefs
[0];
589 // try already instantiated service
590 if (i
<= pEntry
->nLastTriedSvcIndex
)
592 if (xHyph
.is() && xHyph
->hasLocale( rLocale
))
593 xRes
= xHyph
->createPossibleHyphens( aChkWord
, rLocale
,
597 else if (pEntry
->nLastTriedSvcIndex
< nLen
- 1)
598 // instantiate services and try it
600 Reference
< XHyphenator
> *pRef
= pEntry
->aSvcRefs
.getArray();
602 Reference
< XComponentContext
> xContext(
603 comphelper::getProcessComponentContext() );
605 // build service initialization argument
606 Sequence
< Any
> aArgs(2);
607 aArgs
.getArray()[0] <<= GetPropSet();
609 // create specific service via it's implementation name
612 xHyph
.set( xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
613 pEntry
->aSvcImplNames
[0], aArgs
, xContext
),
616 catch (uno::Exception
&)
618 SAL_WARN( "linguistic", "createWithArguments failed" );
622 Reference
< XLinguServiceEventBroadcaster
>
623 xBroadcaster( xHyph
, UNO_QUERY
);
624 if (xBroadcaster
.is())
625 rMgr
.AddLngSvcEvtBroadcaster( xBroadcaster
);
627 if (xHyph
.is() && xHyph
->hasLocale( rLocale
))
628 xRes
= xHyph
->createPossibleHyphens( aChkWord
, rLocale
, rProperties
);
630 pEntry
->nLastTriedSvcIndex
= static_cast<sal_Int16
>(i
);
633 // if language is not supported by the services
634 // remove it from the list.
635 if (xHyph
.is() && !xHyph
->hasLocale( rLocale
))
636 aSvcMap
.erase( nLanguage
);
638 } // if (xEntry.is())
641 if (xRes
.is() && xRes
->getWord() != rWord
)
643 xRes
= new PossibleHyphens( rWord
, nLanguage
,
644 xRes
->getPossibleHyphens(),
645 xRes
->getHyphenationPositions() );
652 void HyphenatorDispatcher::SetServiceList( const Locale
&rLocale
,
653 const Sequence
< OUString
> &rSvcImplNames
)
655 MutexGuard
aGuard( GetLinguMutex() );
657 LanguageType nLanguage
= LinguLocaleToLanguage( rLocale
);
659 if (!rSvcImplNames
.hasElements())
661 aSvcMap
.erase( nLanguage
);
665 LangSvcEntries_Hyph
*pEntry
= aSvcMap
[ nLanguage
].get();
669 pEntry
->aSvcImplNames
= rSvcImplNames
;
670 pEntry
->aSvcImplNames
.realloc(1);
671 pEntry
->aSvcRefs
= Sequence
< Reference
< XHyphenator
> > ( 1 );
675 auto pTmpEntry
= std::make_shared
<LangSvcEntries_Hyph
>( rSvcImplNames
[0] );
676 pTmpEntry
->aSvcRefs
= Sequence
< Reference
< XHyphenator
> >( 1 );
677 aSvcMap
[ nLanguage
] = pTmpEntry
;
684 HyphenatorDispatcher::GetServiceList( const Locale
&rLocale
) const
686 MutexGuard
aGuard( GetLinguMutex() );
688 Sequence
< OUString
> aRes
;
690 // search for entry with that language and use data from that
691 LanguageType nLanguage
= LinguLocaleToLanguage( rLocale
);
692 const HyphSvcByLangMap_t::const_iterator
aIt( aSvcMap
.find( nLanguage
) );
693 const LangSvcEntries_Hyph
*pEntry
= aIt
!= aSvcMap
.end() ? aIt
->second
.get() : nullptr;
696 aRes
= pEntry
->aSvcImplNames
;
697 if (aRes
.hasElements())
705 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */