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>
25 #include <cppuhelper/factory.hxx>
26 #include <com/sun/star/beans/XPropertySet.hpp>
27 #include <com/sun/star/uno/XComponentContext.hpp>
28 #include <com/sun/star/linguistic2/XLinguProperties.hpp>
29 #include <com/sun/star/linguistic2/XLinguServiceEventBroadcaster.hpp>
30 #include <rtl/ustrbuf.hxx>
31 #include <i18nlangtag/lang.h>
32 #include <unotools/localedatawrapper.hxx>
33 #include <tools/debug.hxx>
34 #include <svl/lngmisc.hxx>
35 #include <comphelper/processfactory.hxx>
36 #include <comphelper/sequence.hxx>
37 #include <osl/mutex.hxx>
39 #include "hyphdsp.hxx"
40 #include <linguistic/hyphdta.hxx>
41 #include <linguistic/misc.hxx>
42 #include "lngsvcmgr.hxx"
45 using namespace com::sun::star
;
46 using namespace com::sun::star::beans
;
47 using namespace com::sun::star::lang
;
48 using namespace com::sun::star::uno
;
49 using namespace com::sun::star::linguistic2
;
50 using namespace linguistic
;
53 HyphenatorDispatcher::HyphenatorDispatcher( LngSvcMgr
&rLngSvcMgr
) :
59 HyphenatorDispatcher::~HyphenatorDispatcher()
65 void HyphenatorDispatcher::ClearSvcList()
67 // release memory for each table entry
68 HyphSvcByLangMap_t().swap(aSvcMap
);
72 Reference
<XHyphenatedWord
> HyphenatorDispatcher::buildHyphWord(
73 const OUString
& rOrigWord
,
74 const Reference
<XDictionaryEntry
> &xEntry
,
75 LanguageType nLang
, sal_Int16 nMaxLeading
)
77 MutexGuard
aGuard( GetLinguMutex() );
79 Reference
< XHyphenatedWord
> xRes
;
83 OUString
aText( xEntry
->getDictionaryWord() );
84 sal_Int32 nTextLen
= aText
.getLength();
86 // trailing '=' means "hyphenation should not be possible"
87 if (nTextLen
> 0 && aText
[ nTextLen
- 1 ] != '=' && aText
[ nTextLen
- 1 ] != '[')
89 sal_Int16 nHyphenationPos
= -1;
90 sal_Int16 nOrigHyphPos
= -1;
92 OUStringBuffer
aTmp( nTextLen
);
95 sal_Int32 nHyphIdx
= -1;
96 sal_Int32 nLeading
= 0;
97 for (sal_Int32 i
= 0; i
< nTextLen
; i
++)
99 sal_Unicode cTmp
= aText
[i
];
100 if (cTmp
== '[' || cTmp
== ']')
102 if (cTmp
!= '=' && !bSkip2
&& cTmp
!= ']')
111 if (!bSkip
&& nHyphIdx
>= 0)
113 if (nLeading
<= nMaxLeading
) {
114 nHyphenationPos
= static_cast<sal_Int16
>(nHyphIdx
);
118 bSkip
= true; //! multiple '=' should count as one only
122 if (nHyphenationPos
> 0)
124 #if OSL_DEBUG_LEVEL > 0
126 if (aTmp
.toString() != rOrigWord
)
128 // both words should only differ by a having a trailing '.'
129 // character or not...
130 OUString aShorter
, aLonger
;
131 if (aTmp
.getLength() <= rOrigWord
.getLength())
133 aShorter
= aTmp
.toString();
138 aShorter
= rOrigWord
;
139 aLonger
= aTmp
.toString();
141 sal_Int32 nS
= aShorter
.getLength();
142 sal_Int32 nL
= aLonger
.getLength();
143 if (nS
> 0 && nL
> 0)
145 assert( ((nS
+ 1 == nL
) && aLonger
[nL
-1] == '.') && "HyphenatorDispatcher::buildHyphWord: unexpected difference between words!" );
150 sal_Int32 nHyphenPos
= -1;
151 if (aText
[ nOrigHyphPos
] == '[') // alternative hyphenation
154 sal_Unicode c
= aText
[ nOrigHyphPos
+ 1 ];
155 sal_Int32 endhyphpat
= aText
.indexOf( ']', nOrigHyphPos
);
156 if ('0' <= c
&& c
<= '9')
163 OUStringBuffer
aTmp2 ( aTmp
.copy(0, std::max (nHyphenationPos
+ 1 - split
, 0) ) );
164 aTmp2
.append( aText
.subView( nOrigHyphPos
+ 1, endhyphpat
- nOrigHyphPos
- 1) );
165 nHyphenPos
= aTmp2
.getLength();
166 aTmp2
.append( aTmp
.copy( nHyphenationPos
+ 1 ) );
167 //! take care of #i22591#
168 if (rOrigWord
[ rOrigWord
.getLength() - 1 ] == '.')
170 aText
= aTmp2
.makeStringAndClear();
173 if (nHyphenPos
== -1)
176 xRes
= new HyphenatedWord( rOrigWord
, nLang
, nHyphenationPos
,
177 aText
, (nHyphenPos
> -1) ? nHyphenPos
- 1 : nHyphenationPos
);
186 Reference
< XPossibleHyphens
> HyphenatorDispatcher::buildPossHyphens(
187 const Reference
< XDictionaryEntry
> &xEntry
, LanguageType nLanguage
)
189 MutexGuard
aGuard( GetLinguMutex() );
191 Reference
<XPossibleHyphens
> xRes
;
195 // text with hyphenation info
196 OUString
aText( xEntry
->getDictionaryWord() );
197 sal_Int32 nTextLen
= aText
.getLength();
199 // trailing '=' means "hyphenation should not be possible"
200 if (nTextLen
> 0 && aText
[ nTextLen
- 1 ] != '=' && aText
[ nTextLen
- 1 ] != '[')
202 // sequence to hold hyphenation positions
203 Sequence
< sal_Int16
> aHyphPos( nTextLen
);
204 sal_Int16
*pPos
= aHyphPos
.getArray();
205 sal_Int32 nHyphCount
= 0;
207 OUStringBuffer
aTmp( nTextLen
);
210 sal_Int32 nHyphIdx
= -1;
211 for (sal_Int32 i
= 0; i
< nTextLen
; i
++)
213 sal_Unicode cTmp
= aText
[i
];
214 if (cTmp
== '[' || cTmp
== ']')
216 if (cTmp
!= '=' && !bSkip2
&& cTmp
!= ']')
224 if (!bSkip
&& nHyphIdx
>= 0)
225 pPos
[ nHyphCount
++ ] = static_cast<sal_Int16
>(nHyphIdx
);
226 bSkip
= true; //! multiple '=' should count as one only
230 // ignore (multiple) trailing '='
231 if (bSkip
&& nHyphIdx
>= 0)
235 DBG_ASSERT( nHyphCount
>= 0, "lng : invalid hyphenation count");
239 aHyphPos
.realloc( nHyphCount
);
240 xRes
= new PossibleHyphens( aTmp
.makeStringAndClear(), nLanguage
,
250 Sequence
< Locale
> SAL_CALL
HyphenatorDispatcher::getLocales()
252 MutexGuard
aGuard( GetLinguMutex() );
254 std::vector
<Locale
> aLocales
;
255 aLocales
.reserve(aSvcMap
.size());
257 std::transform(aSvcMap
.begin(), aSvcMap
.end(), std::back_inserter(aLocales
),
258 [](HyphSvcByLangMap_t::const_reference elem
) { return LanguageTag::convertToLocale(elem
.first
); });
260 return comphelper::containerToSequence(aLocales
);
264 sal_Bool SAL_CALL
HyphenatorDispatcher::hasLocale(const Locale
& rLocale
)
266 MutexGuard
aGuard( GetLinguMutex() );
267 HyphSvcByLangMap_t::const_iterator
aIt( aSvcMap
.find( LinguLocaleToLanguage( rLocale
) ) );
268 return aIt
!= aSvcMap
.end();
272 Reference
< XHyphenatedWord
> SAL_CALL
273 HyphenatorDispatcher::hyphenate(
274 const OUString
& rWord
, const Locale
& rLocale
, sal_Int16 nMaxLeading
,
275 const css::uno::Sequence
< ::css::beans::PropertyValue
>& rProperties
)
277 MutexGuard
aGuard( GetLinguMutex() );
279 Reference
< XHyphenatedWord
> xRes
;
281 sal_Int32 nWordLen
= rWord
.getLength();
282 LanguageType nLanguage
= LinguLocaleToLanguage( rLocale
);
283 if (LinguIsUnspecified(nLanguage
) || !nWordLen
||
284 nMaxLeading
== 0 || nMaxLeading
== nWordLen
)
287 // search for entry with that language
288 HyphSvcByLangMap_t::iterator
aIt( aSvcMap
.find( nLanguage
) );
289 LangSvcEntries_Hyph
*pEntry
= aIt
!= aSvcMap
.end() ? aIt
->second
.get() : nullptr;
291 bool bWordModified
= false;
292 if (!pEntry
|| (nMaxLeading
< 0 || nMaxLeading
> nWordLen
))
298 OUString
aChkWord( rWord
);
300 // replace typographical apostroph by ascii apostroph
301 OUString
aSingleQuote( GetLocaleDataWrapper( nLanguage
).getQuotationMarkEnd() );
302 DBG_ASSERT( 1 == aSingleQuote
.getLength(), "unexpected length of quotation mark" );
303 if (!aSingleQuote
.isEmpty())
304 aChkWord
= aChkWord
.replace( aSingleQuote
[0], '\'' );
306 bWordModified
|= RemoveHyphens( aChkWord
);
307 if (IsIgnoreControlChars( rProperties
, GetPropSet() ))
308 bWordModified
|= RemoveControlChars( aChkWord
);
309 sal_Int16 nChkMaxLeading
= static_cast<sal_Int16
>(GetPosInWordToCheck( rWord
, nMaxLeading
));
311 // check for results from (positive) dictionaries which have precedence!
312 Reference
< XDictionaryEntry
> xEntry
;
314 if (GetDicList().is() && IsUseDicList( rProperties
, GetPropSet() ))
316 xEntry
= GetDicList()->queryDictionaryEntry( aChkWord
, rLocale
,
322 //! because queryDictionaryEntry (in the end DictionaryNeo::getEntry)
323 //! does not distinguish between "XYZ" and "XYZ." in order to avoid
324 //! to require them as different entry we have to supply the
325 //! original word here as well so it can be used in th result
326 //! otherwise a strange effect may occur (see #i22591#)
327 xRes
= buildHyphWord( rWord
, xEntry
, nLanguage
, nChkMaxLeading
);
331 sal_Int32 nLen
= pEntry
->aSvcImplNames
.hasElements() ? 1 : 0;
332 DBG_ASSERT( pEntry
->nLastTriedSvcIndex
< nLen
,
333 "lng : index out of range");
336 Reference
< XHyphenator
> xHyph
;
337 if (pEntry
->aSvcRefs
.hasElements())
338 xHyph
= pEntry
->aSvcRefs
[0];
340 // try already instantiated service
341 if (i
<= pEntry
->nLastTriedSvcIndex
)
343 if (xHyph
.is() && xHyph
->hasLocale( rLocale
))
344 xRes
= xHyph
->hyphenate( aChkWord
, rLocale
, nChkMaxLeading
,
348 else if (pEntry
->nLastTriedSvcIndex
< nLen
- 1)
349 // instantiate services and try it
351 Reference
< XHyphenator
> *pRef
= pEntry
->aSvcRefs
.getArray();
353 Reference
< XComponentContext
> xContext(
354 comphelper::getProcessComponentContext() );
356 // build service initialization argument
357 Sequence
< Any
> aArgs(2);
358 aArgs
.getArray()[0] <<= GetPropSet();
360 // create specific service via it's implementation name
363 xHyph
= Reference
< XHyphenator
>(
364 xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
365 pEntry
->aSvcImplNames
[0], aArgs
, xContext
),
368 catch (uno::Exception
&)
370 SAL_WARN( "linguistic", "createInstanceWithArguments failed" );
374 Reference
< XLinguServiceEventBroadcaster
>
375 xBroadcaster( xHyph
, UNO_QUERY
);
376 if (xBroadcaster
.is())
377 rMgr
.AddLngSvcEvtBroadcaster( xBroadcaster
);
379 if (xHyph
.is() && xHyph
->hasLocale( rLocale
))
380 xRes
= xHyph
->hyphenate( aChkWord
, rLocale
, nChkMaxLeading
,
383 pEntry
->nLastTriedSvcIndex
= static_cast<sal_Int16
>(i
);
386 // if language is not supported by the services
387 // remove it from the list.
388 if (xHyph
.is() && !xHyph
->hasLocale( rLocale
))
389 aSvcMap
.erase( nLanguage
);
391 } // if (xEntry.is())
394 if (bWordModified
&& xRes
.is())
395 xRes
= RebuildHyphensAndControlChars( rWord
, xRes
);
397 if (xRes
.is() && xRes
->getWord() != rWord
)
399 xRes
= new HyphenatedWord( rWord
, nLanguage
, xRes
->getHyphenationPos(),
400 xRes
->getHyphenatedWord(),
401 xRes
->getHyphenPos() );
408 Reference
< XHyphenatedWord
> SAL_CALL
409 HyphenatorDispatcher::queryAlternativeSpelling(
410 const OUString
& rWord
, const Locale
& rLocale
, sal_Int16 nIndex
,
411 const css::uno::Sequence
< ::css::beans::PropertyValue
>& rProperties
)
413 MutexGuard
aGuard( GetLinguMutex() );
415 Reference
< XHyphenatedWord
> xRes
;
417 sal_Int32 nWordLen
= rWord
.getLength();
418 LanguageType nLanguage
= LinguLocaleToLanguage( rLocale
);
419 if (LinguIsUnspecified(nLanguage
) || !nWordLen
)
422 // search for entry with that language
423 HyphSvcByLangMap_t::iterator
aIt( aSvcMap
.find( nLanguage
) );
424 LangSvcEntries_Hyph
*pEntry
= aIt
!= aSvcMap
.end() ? aIt
->second
.get() : nullptr;
426 bool bWordModified
= false;
427 if (!pEntry
|| 0 > nIndex
|| nIndex
> nWordLen
- 2)
433 OUString
aChkWord( rWord
);
435 // replace typographical apostroph by ascii apostroph
436 OUString
aSingleQuote( GetLocaleDataWrapper( nLanguage
).getQuotationMarkEnd() );
437 DBG_ASSERT( 1 == aSingleQuote
.getLength(), "unexpected length of quotation mark" );
438 if (!aSingleQuote
.isEmpty())
439 aChkWord
= aChkWord
.replace( aSingleQuote
[0], '\'' );
441 bWordModified
|= RemoveHyphens( aChkWord
);
442 if (IsIgnoreControlChars( rProperties
, GetPropSet() ))
443 bWordModified
|= RemoveControlChars( aChkWord
);
444 sal_Int16 nChkIndex
= static_cast<sal_Int16
>(GetPosInWordToCheck( rWord
, nIndex
));
446 // check for results from (positive) dictionaries which have precedence!
447 Reference
< XDictionaryEntry
> xEntry
;
449 if (GetDicList().is() && IsUseDicList( rProperties
, GetPropSet() ))
451 xEntry
= GetDicList()->queryDictionaryEntry( aChkWord
, rLocale
,
457 xRes
= buildHyphWord(aChkWord
, xEntry
, nLanguage
, nIndex
+ 1);
458 if (xRes
.is() && xRes
->isAlternativeSpelling() && xRes
->getHyphenationPos() == nIndex
)
463 sal_Int32 nLen
= pEntry
->aSvcImplNames
.hasElements() ? 1 : 0;
464 DBG_ASSERT( pEntry
->nLastTriedSvcIndex
< nLen
,
465 "lng : index out of range");
468 Reference
< XHyphenator
> xHyph
;
469 if (pEntry
->aSvcRefs
.hasElements())
470 xHyph
= pEntry
->aSvcRefs
[0];
472 // try already instantiated service
473 if (i
<= pEntry
->nLastTriedSvcIndex
)
475 if (xHyph
.is() && xHyph
->hasLocale( rLocale
))
476 xRes
= xHyph
->queryAlternativeSpelling( aChkWord
, rLocale
,
477 nChkIndex
, rProperties
);
480 else if (pEntry
->nLastTriedSvcIndex
< nLen
- 1)
481 // instantiate services and try it
483 Reference
< XHyphenator
> *pRef
= pEntry
->aSvcRefs
.getArray();
485 Reference
< XComponentContext
> xContext(
486 comphelper::getProcessComponentContext() );
488 // build service initialization argument
489 Sequence
< Any
> aArgs(2);
490 aArgs
.getArray()[0] <<= GetPropSet();
492 // create specific service via it's implementation name
495 xHyph
= Reference
< XHyphenator
>(
496 xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
497 pEntry
->aSvcImplNames
[0], aArgs
, xContext
), UNO_QUERY
);
499 catch (uno::Exception
&)
501 SAL_WARN( "linguistic", "createInstanceWithArguments failed" );
505 Reference
< XLinguServiceEventBroadcaster
>
506 xBroadcaster( xHyph
, UNO_QUERY
);
507 if (xBroadcaster
.is())
508 rMgr
.AddLngSvcEvtBroadcaster( xBroadcaster
);
510 if (xHyph
.is() && xHyph
->hasLocale( rLocale
))
511 xRes
= xHyph
->queryAlternativeSpelling( aChkWord
, rLocale
,
512 nChkIndex
, rProperties
);
514 pEntry
->nLastTriedSvcIndex
= static_cast<sal_Int16
>(i
);
517 // if language is not supported by the services
518 // remove it from the list.
519 if (xHyph
.is() && !xHyph
->hasLocale( rLocale
))
520 aSvcMap
.erase( nLanguage
);
522 } // if (xEntry.is())
525 if (bWordModified
&& xRes
.is())
526 xRes
= RebuildHyphensAndControlChars( rWord
, xRes
);
528 if (xRes
.is() && xRes
->getWord() != rWord
)
530 xRes
= new HyphenatedWord( rWord
, nLanguage
, xRes
->getHyphenationPos(),
531 xRes
->getHyphenatedWord(),
532 xRes
->getHyphenPos() );
539 Reference
< XPossibleHyphens
> SAL_CALL
540 HyphenatorDispatcher::createPossibleHyphens(
541 const OUString
& rWord
, const Locale
& rLocale
,
542 const css::uno::Sequence
< ::css::beans::PropertyValue
>& rProperties
)
544 MutexGuard
aGuard( GetLinguMutex() );
546 Reference
< XPossibleHyphens
> xRes
;
548 LanguageType nLanguage
= LinguLocaleToLanguage( rLocale
);
549 if (LinguIsUnspecified(nLanguage
) || rWord
.isEmpty())
552 // search for entry with that language
553 HyphSvcByLangMap_t::iterator
aIt( aSvcMap
.find( nLanguage
) );
554 LangSvcEntries_Hyph
*pEntry
= aIt
!= aSvcMap
.end() ? aIt
->second
.get() : nullptr;
558 OUString
aChkWord( rWord
);
560 // replace typographical apostroph by ascii apostroph
561 OUString
aSingleQuote( GetLocaleDataWrapper( nLanguage
).getQuotationMarkEnd() );
562 DBG_ASSERT( 1 == aSingleQuote
.getLength(), "unexpected length of quotation mark" );
563 if (!aSingleQuote
.isEmpty())
564 aChkWord
= aChkWord
.replace( aSingleQuote
[0], '\'' );
566 RemoveHyphens( aChkWord
);
567 if (IsIgnoreControlChars( rProperties
, GetPropSet() ))
568 RemoveControlChars( aChkWord
);
570 // check for results from (positive) dictionaries which have precedence!
571 Reference
< XDictionaryEntry
> xEntry
;
573 if (GetDicList().is() && IsUseDicList( rProperties
, GetPropSet() ))
575 xEntry
= GetDicList()->queryDictionaryEntry( aChkWord
, rLocale
,
581 xRes
= buildPossHyphens( xEntry
, nLanguage
);
585 sal_Int32 nLen
= pEntry
->aSvcImplNames
.hasElements() ? 1 : 0;
586 DBG_ASSERT( pEntry
->nLastTriedSvcIndex
< nLen
,
587 "lng : index out of range");
590 Reference
< XHyphenator
> xHyph
;
591 if (pEntry
->aSvcRefs
.hasElements())
592 xHyph
= pEntry
->aSvcRefs
[0];
594 // try already instantiated service
595 if (i
<= pEntry
->nLastTriedSvcIndex
)
597 if (xHyph
.is() && xHyph
->hasLocale( rLocale
))
598 xRes
= xHyph
->createPossibleHyphens( aChkWord
, rLocale
,
602 else if (pEntry
->nLastTriedSvcIndex
< nLen
- 1)
603 // instantiate services and try it
605 Reference
< XHyphenator
> *pRef
= pEntry
->aSvcRefs
.getArray();
607 Reference
< XComponentContext
> xContext(
608 comphelper::getProcessComponentContext() );
610 // build service initialization argument
611 Sequence
< Any
> aArgs(2);
612 aArgs
.getArray()[0] <<= GetPropSet();
614 // create specific service via it's implementation name
617 xHyph
.set( xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(
618 pEntry
->aSvcImplNames
[0], aArgs
, xContext
),
621 catch (uno::Exception
&)
623 SAL_WARN( "linguistic", "createWithArguments failed" );
627 Reference
< XLinguServiceEventBroadcaster
>
628 xBroadcaster( xHyph
, UNO_QUERY
);
629 if (xBroadcaster
.is())
630 rMgr
.AddLngSvcEvtBroadcaster( xBroadcaster
);
632 if (xHyph
.is() && xHyph
->hasLocale( rLocale
))
633 xRes
= xHyph
->createPossibleHyphens( aChkWord
, rLocale
, rProperties
);
635 pEntry
->nLastTriedSvcIndex
= static_cast<sal_Int16
>(i
);
638 // if language is not supported by the services
639 // remove it from the list.
640 if (xHyph
.is() && !xHyph
->hasLocale( rLocale
))
641 aSvcMap
.erase( nLanguage
);
643 } // if (xEntry.is())
646 if (xRes
.is() && xRes
->getWord() != rWord
)
648 xRes
= new PossibleHyphens( rWord
, nLanguage
,
649 xRes
->getPossibleHyphens(),
650 xRes
->getHyphenationPositions() );
657 void HyphenatorDispatcher::SetServiceList( const Locale
&rLocale
,
658 const Sequence
< OUString
> &rSvcImplNames
)
660 MutexGuard
aGuard( GetLinguMutex() );
662 LanguageType nLanguage
= LinguLocaleToLanguage( rLocale
);
664 if (!rSvcImplNames
.hasElements())
666 aSvcMap
.erase( nLanguage
);
670 LangSvcEntries_Hyph
*pEntry
= aSvcMap
[ nLanguage
].get();
674 pEntry
->aSvcImplNames
= rSvcImplNames
;
675 pEntry
->aSvcImplNames
.realloc(1);
676 pEntry
->aSvcRefs
= Sequence
< Reference
< XHyphenator
> > ( 1 );
680 auto pTmpEntry
= std::make_shared
<LangSvcEntries_Hyph
>( rSvcImplNames
[0] );
681 pTmpEntry
->aSvcRefs
= Sequence
< Reference
< XHyphenator
> >( 1 );
682 aSvcMap
[ nLanguage
] = pTmpEntry
;
689 HyphenatorDispatcher::GetServiceList( const Locale
&rLocale
) const
691 MutexGuard
aGuard( GetLinguMutex() );
693 Sequence
< OUString
> aRes
;
695 // search for entry with that language and use data from that
696 LanguageType nLanguage
= LinguLocaleToLanguage( rLocale
);
697 const HyphSvcByLangMap_t::const_iterator
aIt( aSvcMap
.find( nLanguage
) );
698 const LangSvcEntries_Hyph
*pEntry
= aIt
!= aSvcMap
.end() ? aIt
->second
.get() : nullptr;
701 aRes
= pEntry
->aSvcImplNames
;
702 if (aRes
.hasElements())
710 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */