LCOV - code coverage report
Current view: top level - i18npool/source/breakiterator - breakiteratorImpl.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 221 295 74.9 %
Date: 2012-08-25 Functions: 29 36 80.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 342 666 51.4 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*
       3                 :            :  * This file is part of the LibreOffice project.
       4                 :            :  *
       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/.
       8                 :            :  *
       9                 :            :  * This file incorporates work covered by the following license notice:
      10                 :            :  *
      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 .
      18                 :            :  */
      19                 :            : 
      20                 :            : 
      21                 :            : #include <breakiteratorImpl.hxx>
      22                 :            : #include <unicode/uchar.h>
      23                 :            : #include <i18nutil/unicode.hxx>
      24                 :            : #include <rtl/ustrbuf.hxx>
      25                 :            : 
      26                 :            : using namespace ::com::sun::star::uno;
      27                 :            : using namespace ::com::sun::star::lang;
      28                 :            : using namespace ::rtl;
      29                 :            : 
      30                 :            : namespace com { namespace sun { namespace star { namespace i18n {
      31                 :            : 
      32         [ +  - ]:      26023 : BreakIteratorImpl::BreakIteratorImpl( const Reference < XMultiServiceFactory >& rxMSF ) : xMSF( rxMSF )
      33                 :            : {
      34                 :      26023 : }
      35                 :            : 
      36         [ +  - ]:       1997 : BreakIteratorImpl::BreakIteratorImpl()
      37                 :            : {
      38                 :       1997 : }
      39                 :            : 
      40                 :      27964 : BreakIteratorImpl::~BreakIteratorImpl()
      41                 :            : {
      42                 :            :         // Clear lookuptable
      43         [ +  + ]:      32017 :         for (size_t l = 0; l < lookupTable.size(); l++)
      44 [ +  - ][ +  - ]:       4053 :             delete lookupTable[l];
      45                 :      27964 :         lookupTable.clear();
      46         [ -  + ]:      53939 : }
      47                 :            : 
      48                 :            : #define LBI getLocaleSpecificBreakIterator(rLocale)
      49                 :            : 
      50                 :    3646773 : sal_Int32 SAL_CALL BreakIteratorImpl::nextCharacters( const OUString& Text, sal_Int32 nStartPos,
      51                 :            :         const Locale &rLocale, sal_Int16 nCharacterIteratorMode, sal_Int32 nCount, sal_Int32& nDone )
      52                 :            :         throw(RuntimeException)
      53                 :            : {
      54 [ -  + ][ #  # ]:    3646773 :         if (nCount < 0) throw RuntimeException();
      55                 :            : 
      56 [ +  - ][ +  - ]:    3646773 :         return LBI->nextCharacters( Text, nStartPos, rLocale, nCharacterIteratorMode, nCount, nDone);
      57                 :            : }
      58                 :            : 
      59                 :      69078 : sal_Int32 SAL_CALL BreakIteratorImpl::previousCharacters( const OUString& Text, sal_Int32 nStartPos,
      60                 :            :         const Locale& rLocale, sal_Int16 nCharacterIteratorMode, sal_Int32 nCount, sal_Int32& nDone )
      61                 :            :         throw(RuntimeException)
      62                 :            : {
      63 [ -  + ][ #  # ]:      69078 :         if (nCount < 0) throw RuntimeException();
      64                 :            : 
      65 [ +  - ][ +  - ]:      69078 :         return LBI->previousCharacters( Text, nStartPos, rLocale, nCharacterIteratorMode, nCount, nDone);
      66                 :            : }
      67                 :            : 
      68                 :            : #define isZWSP(c) (ch == 0x200B)
      69                 :            : 
      70                 :     431369 : static sal_Int32 skipSpace(const OUString& Text, sal_Int32 nPos, sal_Int32 len, sal_Int16 rWordType, sal_Bool bDirection)
      71                 :            : {
      72                 :     431369 :         sal_uInt32 ch=0;
      73                 :     431369 :         sal_Int32 pos=nPos;
      74   [ +  +  +  + ]:     431369 :         switch (rWordType) {
      75                 :            :             case WordType::ANYWORD_IGNOREWHITESPACES:
      76         [ +  + ]:       4337 :                 if (bDirection)
      77 [ +  + ][ +  - ]:       2678 :                     while (nPos < len && (u_isWhitespace(ch = Text.iterateCodePoints(&pos, 1)) || isZWSP(ch))) nPos=pos;
         [ +  - ][ +  + ]
         [ -  + ][ +  + ]
      78                 :            :                 else
      79 [ +  + ][ +  - ]:       2743 :                     while (nPos > 0 && (u_isWhitespace(ch = Text.iterateCodePoints(&pos, -1)) || isZWSP(ch))) nPos=pos;
         [ +  - ][ +  + ]
         [ -  + ][ +  + ]
      80                 :       4337 :             break;
      81                 :            :             case WordType::DICTIONARY_WORD:
      82         [ +  + ]:     271914 :                 if (bDirection)
      83 [ +  + ][ +  - ]:     274672 :                     while (nPos < len && (u_isWhitespace(ch = Text.iterateCodePoints(&pos, 1)) || isZWSP(ch) ||
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
                 [ +  + ]
      84 [ +  - ][ +  + ]:     138310 :                             ! (ch == 0x002E || u_isalnum(ch)))) nPos=pos;
      85                 :            :                 else
      86 [ +  + ][ +  - ]:     280787 :                     while (nPos > 0 && (u_isWhitespace(ch = Text.iterateCodePoints(&pos, -1)) || isZWSP(ch) ||
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
                 [ +  + ]
      87 [ +  - ][ +  + ]:     145235 :                             ! (ch == 0x002E || u_isalnum(ch)))) nPos=pos;
      88                 :     271914 :             break;
      89                 :            :             case WordType::WORD_COUNT:
      90         [ +  + ]:     138484 :                 if (bDirection)
      91 [ +  - ][ +  - ]:      69242 :                     while (nPos < len && (u_isUWhiteSpace(ch = Text.iterateCodePoints(&pos, 1)) || isZWSP(ch))) nPos=pos;
         [ +  - ][ +  - ]
         [ -  + ][ -  + ]
      92                 :            :                 else
      93 [ +  + ][ +  - ]:     137260 :                     while (nPos > 0 && (u_isUWhiteSpace(ch = Text.iterateCodePoints(&pos, -1)) || isZWSP(ch))) nPos=pos;
         [ +  - ][ +  + ]
         [ -  + ][ +  + ]
      94                 :     138484 :             break;
      95                 :            :         }
      96                 :     431369 :         return nPos;
      97                 :            : }
      98                 :            : 
      99                 :        866 : Boundary SAL_CALL BreakIteratorImpl::nextWord( const OUString& Text, sal_Int32 nStartPos,
     100                 :            :         const Locale& rLocale, sal_Int16 rWordType ) throw(RuntimeException)
     101                 :            : {
     102                 :        866 :         sal_Int32 len = Text.getLength();
     103 [ -  + ][ +  + ]:        866 :         if( nStartPos < 0 || len == 0 )
     104                 :          3 :             result.endPos = result.startPos = 0;
     105         [ +  + ]:        863 :         else if (nStartPos >= len)
     106                 :          6 :             result.endPos = result.startPos = len;
     107                 :            :         else {
     108 [ +  - ][ +  - ]:        857 :             result = LBI->nextWord(Text, nStartPos, rLocale, rWordType);
     109                 :            : 
     110                 :        857 :             nStartPos = skipSpace(Text, result.startPos, len, rWordType, sal_True);
     111                 :            : 
     112         [ +  + ]:        857 :             if ( nStartPos != result.startPos) {
     113         [ -  + ]:          2 :                 if( nStartPos >= len )
     114                 :          0 :                     result.startPos = result.endPos = len;
     115                 :            :                 else {
     116 [ +  - ][ +  - ]:          2 :                     result = LBI->getWordBoundary(Text, nStartPos, rLocale, rWordType, sal_True);
     117                 :            :                     // i88041: avoid startPos goes back to nStartPos when switching between Latin and CJK scripts
     118         [ -  + ]:          2 :                     if (result.startPos < nStartPos) result.startPos = nStartPos;
     119                 :            :                 }
     120                 :            :             }
     121                 :            :         }
     122                 :        866 :         return result;
     123                 :            : }
     124                 :            : 
     125                 :          6 : static inline sal_Bool SAL_CALL isCJK( const Locale& rLocale ) {
     126 [ +  - ][ +  - ]:          6 :         return rLocale.Language == "zh" || rLocale.Language == "ja" || rLocale.Language == "ko";
                 [ -  + ]
     127                 :            : }
     128                 :            : 
     129                 :         40 : Boundary SAL_CALL BreakIteratorImpl::previousWord( const OUString& Text, sal_Int32 nStartPos,
     130                 :            :         const Locale& rLocale, sal_Int16 rWordType) throw(RuntimeException)
     131                 :            : {
     132                 :         40 :         sal_Int32 len = Text.getLength();
     133 [ -  + ][ +  - ]:         40 :         if( nStartPos <= 0 || len == 0 ) {
     134                 :          0 :             result.endPos = result.startPos = 0;
     135                 :          0 :             return result;
     136         [ -  + ]:         40 :         } else if (nStartPos > len) {
     137                 :          0 :             result.endPos = result.startPos = len;
     138                 :          0 :             return result;
     139                 :            :         }
     140                 :            : 
     141         [ +  - ]:         40 :         sal_Int32 nPos = skipSpace(Text, nStartPos, len, rWordType, sal_False);
     142                 :            : 
     143                 :            :         // if some spaces are skiped, and the script type is Asian with no CJK rLocale, we have to return
     144                 :            :         // (nStartPos, -1) for caller to send correct rLocale for loading correct dictionary.
     145                 :         40 :         result.startPos = nPos;
     146 [ +  + ][ +  - ]:         40 :         if (nPos != nStartPos && nPos > 0 && !isCJK(rLocale) && getScriptClass(Text.iterateCodePoints(&nPos, -1)) == ScriptType::ASIAN) {
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ -  + ][ -  + ]
     147                 :          0 :             result.endPos = -1;
     148                 :          0 :             return result;
     149                 :            :         }
     150                 :            : 
     151 [ +  - ][ +  - ]:         40 :         return LBI->previousWord(Text, result.startPos, rLocale, rWordType);
                 [ +  - ]
     152                 :            : }
     153                 :            : 
     154                 :            : 
     155                 :     221914 : Boundary SAL_CALL BreakIteratorImpl::getWordBoundary( const OUString& Text, sal_Int32 nPos, const Locale& rLocale,
     156                 :            :         sal_Int16 rWordType, sal_Bool bDirection ) throw(RuntimeException)
     157                 :            : {
     158                 :     221914 :         sal_Int32 len = Text.getLength();
     159 [ +  + ][ +  - ]:     221914 :         if( nPos < 0 || len == 0 )
     160                 :       6708 :             result.endPos = result.startPos = 0;
     161         [ -  + ]:     215206 :         else if (nPos > len)
     162                 :          0 :             result.endPos = result.startPos = len;
     163                 :            :         else {
     164                 :            :             sal_Int32 next, prev;
     165                 :     215206 :             next = skipSpace(Text, nPos, len, rWordType, sal_True);
     166                 :     215206 :             prev = skipSpace(Text, nPos, len, rWordType, sal_False);
     167 [ +  + ][ +  + ]:     215206 :             if (prev == 0 && next == len) {
     168                 :        469 :                 result.endPos = result.startPos = nPos;
     169 [ +  + ][ -  + ]:     214737 :             } else if (prev == 0 && ! bDirection) {
     170                 :          0 :                 result.endPos = result.startPos = 0;
     171 [ +  + ][ +  + ]:     214737 :             } else if (next == len && bDirection) {
     172                 :       2106 :                 result.endPos = result.startPos = len;
     173                 :            :             } else {
     174         [ +  + ]:     212631 :                 if (next != prev) {
     175 [ +  + ][ +  - ]:     110106 :                     if (next == nPos && next != len)
     176                 :     108008 :                         bDirection = sal_True;
     177 [ +  + ][ +  + ]:       2098 :                     else if (prev == nPos && prev != 0)
     178                 :        790 :                         bDirection = sal_False;
     179                 :            :                     else
     180         [ +  + ]:     110106 :                         nPos = bDirection ? next : prev;
     181                 :            :                 }
     182 [ +  - ][ +  - ]:     212631 :                 result = LBI->getWordBoundary(Text, nPos, rLocale, rWordType, bDirection);
     183                 :            :             }
     184                 :            :         }
     185                 :     221914 :         return result;
     186                 :            : }
     187                 :            : 
     188                 :         36 : sal_Bool SAL_CALL BreakIteratorImpl::isBeginWord( const OUString& Text, sal_Int32 nPos,
     189                 :            :         const Locale& rLocale, sal_Int16 rWordType ) throw(RuntimeException)
     190                 :            : {
     191                 :         36 :         sal_Int32 len = Text.getLength();
     192                 :            : 
     193 [ +  + ][ +  - ]:         36 :         if (nPos < 0 || nPos >= len) return sal_False;
     194                 :            : 
     195                 :         30 :         sal_Int32 tmp = skipSpace(Text, nPos, len, rWordType, sal_True);
     196                 :            : 
     197         [ +  + ]:         30 :         if (tmp != nPos) return sal_False;
     198                 :            : 
     199                 :         22 :         result = getWordBoundary(Text, nPos, rLocale, rWordType, sal_True);
     200                 :            : 
     201                 :         36 :         return result.startPos == nPos;
     202                 :            : }
     203                 :            : 
     204                 :         50 : sal_Bool SAL_CALL BreakIteratorImpl::isEndWord( const OUString& Text, sal_Int32 nPos,
     205                 :            :         const Locale& rLocale, sal_Int16 rWordType ) throw(RuntimeException)
     206                 :            : {
     207                 :         50 :         sal_Int32 len = Text.getLength();
     208                 :            : 
     209 [ -  + ][ +  + ]:         50 :         if (nPos <= 0 || nPos > len) return sal_False;
     210                 :            : 
     211                 :         30 :         sal_Int32 tmp = skipSpace(Text, nPos, len, rWordType, sal_False);
     212                 :            : 
     213         [ +  + ]:         30 :         if (tmp != nPos) return sal_False;
     214                 :            : 
     215                 :         26 :         result = getWordBoundary(Text, nPos, rLocale, rWordType, sal_False);
     216                 :            : 
     217                 :         50 :         return result.endPos == nPos;
     218                 :            : }
     219                 :            : 
     220                 :         30 : sal_Int32 SAL_CALL BreakIteratorImpl::beginOfSentence( const OUString& Text, sal_Int32 nStartPos,
     221                 :            :         const Locale &rLocale ) throw(RuntimeException)
     222                 :            : {
     223 [ +  - ][ -  + ]:         30 :         if (nStartPos < 0 || nStartPos > Text.getLength())
                 [ -  + ]
     224                 :          0 :             return -1;
     225         [ -  + ]:         30 :         if (Text.isEmpty()) return 0;
     226 [ +  - ][ +  - ]:         30 :         return LBI->beginOfSentence(Text, nStartPos, rLocale);
     227                 :            : }
     228                 :            : 
     229                 :       3880 : sal_Int32 SAL_CALL BreakIteratorImpl::endOfSentence( const OUString& Text, sal_Int32 nStartPos,
     230                 :            :         const Locale &rLocale ) throw(RuntimeException)
     231                 :            : {
     232 [ +  - ][ -  + ]:       3880 :         if (nStartPos < 0 || nStartPos > Text.getLength())
                 [ -  + ]
     233                 :          0 :             return -1;
     234         [ -  + ]:       3880 :         if (Text.isEmpty()) return 0;
     235 [ +  - ][ +  - ]:       3880 :         return LBI->endOfSentence(Text, nStartPos, rLocale);
     236                 :            : }
     237                 :            : 
     238                 :     140403 : LineBreakResults SAL_CALL BreakIteratorImpl::getLineBreak( const OUString& Text, sal_Int32 nStartPos,
     239                 :            :         const Locale& rLocale, sal_Int32 nMinBreakPos, const LineBreakHyphenationOptions& hOptions,
     240                 :            :         const LineBreakUserOptions& bOptions ) throw(RuntimeException)
     241                 :            : {
     242 [ +  - ][ +  - ]:     140403 :         return LBI->getLineBreak(Text, nStartPos, rLocale, nMinBreakPos, hOptions, bOptions);
     243                 :            : }
     244                 :            : 
     245                 :    3159467 : sal_Int16 SAL_CALL BreakIteratorImpl::getScriptType( const OUString& Text, sal_Int32 nPos )
     246                 :            :         throw(RuntimeException)
     247                 :            : {
     248                 :    3159406 :         return (nPos < 0 || nPos >= Text.getLength()) ? ScriptType::WEAK :
     249   [ +  +  +  + ]:    6318873 :                             getScriptClass(Text.iterateCodePoints(&nPos, 0));
     250                 :            : }
     251                 :            : 
     252                 :            : 
     253                 :            : /** Increments/decrements position first, then obtains character.
     254                 :            :     @return current position, may be -1 or text length if string was consumed.
     255                 :            :  */
     256                 :    8010753 : static sal_Int32 SAL_CALL iterateCodePoints(const OUString& Text, sal_Int32 &nStartPos, sal_Int32 inc, sal_uInt32& ch) {
     257                 :    8010753 :         sal_Int32 nLen = Text.getLength();
     258 [ +  + ][ +  - ]:    8010753 :         if (nStartPos + inc < 0 || nStartPos + inc >= nLen) {
     259                 :     376064 :             ch = 0;
     260         [ +  - ]:     376064 :             nStartPos = nStartPos + inc < 0 ? -1 : nLen;
     261                 :            :         } else {
     262                 :    7634689 :             ch = Text.iterateCodePoints(&nStartPos, inc);
     263                 :            :             // Fix for #i80436#.
     264                 :            :             // erAck: 2009-06-30T21:52+0200  This logic looks somewhat
     265                 :            :             // suspicious as if it cures a symptom.. anyway, had to add
     266                 :            :             // nStartPos < Text.getLength() to silence the (correct) assertion
     267                 :            :             // in rtl_uString_iterateCodePoints() if Text was one character
     268                 :            :             // (codepoint) only, made up of a surrogate pair.
     269                 :            :             //if (inc > 0 && nStartPos < Text.getLength())
     270                 :            :             //    ch = Text.iterateCodePoints(&nStartPos, 0);
     271                 :            :             // With surrogates, nStartPos may actually point behind string
     272                 :            :             // now, even if inc is only +1
     273         [ +  + ]:    7634689 :             if (inc > 0)
     274         [ +  - ]:    7620076 :                 ch = (nStartPos < nLen ? Text.iterateCodePoints(&nStartPos, 0) : 0);
     275                 :            :         }
     276                 :    8010753 :         return nStartPos;
     277                 :            : }
     278                 :            : 
     279                 :            : 
     280                 :      13408 : sal_Int32 SAL_CALL BreakIteratorImpl::beginOfScript( const OUString& Text,
     281                 :            :         sal_Int32 nStartPos, sal_Int16 ScriptType ) throw(RuntimeException)
     282                 :            : {
     283 [ +  - ][ -  + ]:      13408 :         if (nStartPos < 0 || nStartPos >= Text.getLength())
                 [ -  + ]
     284                 :          0 :             return -1;
     285                 :            : 
     286 [ +  - ][ +  - ]:      13408 :         if(ScriptType != getScriptClass(Text.iterateCodePoints(&nStartPos, 0)))
                 [ -  + ]
     287                 :          0 :             return -1;
     288                 :            : 
     289         [ -  + ]:      13408 :         if (nStartPos == 0) return 0;
     290                 :      13408 :         sal_uInt32 ch=0;
     291 [ +  - ][ +  - ]:      14613 :         while (iterateCodePoints(Text, nStartPos, -1, ch) >= 0 && ScriptType == getScriptClass(ch)) {
         [ +  - ][ +  + ]
                 [ +  + ]
     292         [ +  + ]:       2582 :             if (nStartPos == 0) return 0;
     293                 :            :         }
     294                 :            : 
     295         [ +  - ]:      13408 :         return  iterateCodePoints(Text, nStartPos, 1, ch);
     296                 :            : }
     297                 :            : 
     298                 :     261988 : sal_Int32 SAL_CALL BreakIteratorImpl::endOfScript( const OUString& Text,
     299                 :            :         sal_Int32 nStartPos, sal_Int16 ScriptType ) throw(RuntimeException)
     300                 :            : {
     301 [ +  - ][ +  + ]:     261988 :         if (nStartPos < 0 || nStartPos >= Text.getLength())
                 [ +  + ]
     302                 :       1761 :             return -1;
     303                 :            : 
     304 [ +  - ][ +  - ]:     260227 :         if(ScriptType != getScriptClass(Text.iterateCodePoints(&nStartPos, 0)))
                 [ -  + ]
     305                 :          0 :             return -1;
     306                 :            : 
     307                 :     260227 :         sal_Int32 strLen = Text.getLength();
     308                 :     260227 :         sal_uInt32 ch=0;
     309 [ +  - ][ +  + ]:    6449525 :         while(iterateCodePoints(Text, nStartPos, 1, ch) < strLen ) {
     310         [ +  - ]:    6195388 :             sal_Int16 currentCharScriptType = getScriptClass(ch);
     311 [ +  + ][ +  + ]:    6195388 :             if(ScriptType != currentCharScriptType && currentCharScriptType != ScriptType::WEAK)
     312                 :       6090 :                 break;
     313                 :            :         }
     314                 :     261988 :         return  nStartPos;
     315                 :            : }
     316                 :            : 
     317                 :          0 : sal_Int32  SAL_CALL BreakIteratorImpl::previousScript( const OUString& Text,
     318                 :            :         sal_Int32 nStartPos, sal_Int16 ScriptType ) throw(RuntimeException)
     319                 :            : {
     320         [ #  # ]:          0 :         if (nStartPos < 0)
     321                 :          0 :             return -1;
     322         [ #  # ]:          0 :         if (nStartPos > Text.getLength())
     323                 :          0 :             nStartPos = Text.getLength();
     324                 :            : 
     325 [ #  # ][ #  # ]:          0 :         sal_Int16 numberOfChange = (ScriptType == getScriptClass(Text.iterateCodePoints(&nStartPos, 0))) ? 3 : 2;
                 [ #  # ]
     326                 :            : 
     327                 :          0 :         sal_uInt32 ch=0;
     328 [ #  # ][ #  # ]:          0 :         while (numberOfChange > 0 && iterateCodePoints(Text, nStartPos, -1, ch) >= 0) {
         [ #  # ][ #  # ]
     329 [ #  # ][ #  # ]:          0 :             if ((((numberOfChange % 2) == 0) ^ (ScriptType != getScriptClass(ch))))
     330                 :          0 :                 numberOfChange--;
     331         [ #  # ]:          0 :             else if (nStartPos == 0) {
     332         [ #  # ]:          0 :                 if (numberOfChange > 0)
     333                 :          0 :                     numberOfChange--;
     334         [ #  # ]:          0 :                 if (nStartPos > 0)
     335         [ #  # ]:          0 :                     Text.iterateCodePoints(&nStartPos, -1);
     336                 :            :                 else
     337                 :          0 :                     return -1;
     338                 :            :             }
     339                 :            :         }
     340 [ #  # ][ #  # ]:          0 :         return numberOfChange == 0 ? iterateCodePoints(Text, nStartPos, 1, ch) : -1;
     341                 :            : }
     342                 :            : 
     343                 :          0 : sal_Int32 SAL_CALL BreakIteratorImpl::nextScript( const OUString& Text, sal_Int32 nStartPos,
     344                 :            :         sal_Int16 ScriptType ) throw(RuntimeException)
     345                 :            : 
     346                 :            : {
     347         [ #  # ]:          0 :         if (nStartPos < 0)
     348                 :          0 :             nStartPos = 0;
     349                 :          0 :         sal_Int32 strLen = Text.getLength();
     350         [ #  # ]:          0 :         if (nStartPos > strLen)
     351                 :          0 :             return -1;
     352                 :            : 
     353 [ #  # ][ #  # ]:          0 :         sal_Int16 numberOfChange = (ScriptType == getScriptClass(Text.iterateCodePoints(&nStartPos, 0))) ? 2 : 1;
                 [ #  # ]
     354                 :            : 
     355                 :          0 :         sal_uInt32 ch=0;
     356 [ #  # ][ #  # ]:          0 :         while (numberOfChange > 0 && iterateCodePoints(Text, nStartPos, 1, ch) < strLen) {
         [ #  # ][ #  # ]
     357         [ #  # ]:          0 :             sal_Int16 currentCharScriptType = getScriptClass(ch);
     358 [ #  # ][ #  # ]:          0 :             if ((numberOfChange == 1) ? (ScriptType == currentCharScriptType) :
         [ #  # ][ #  # ]
     359                 :            :                     (ScriptType != currentCharScriptType && currentCharScriptType != ScriptType::WEAK))
     360                 :          0 :                 numberOfChange--;
     361                 :            :         }
     362         [ #  # ]:          0 :         return numberOfChange == 0 ? nStartPos : -1;
     363                 :            : }
     364                 :            : 
     365                 :          0 : sal_Int32 SAL_CALL BreakIteratorImpl::beginOfCharBlock( const OUString& Text, sal_Int32 nStartPos,
     366                 :            :         const Locale& /*rLocale*/, sal_Int16 CharType ) throw(RuntimeException)
     367                 :            : {
     368         [ #  # ]:          0 :         if (CharType == CharType::ANY_CHAR) return 0;
     369 [ #  # ][ #  # ]:          0 :         if (nStartPos < 0 || nStartPos >= Text.getLength()) return -1;
                 [ #  # ]
     370 [ #  # ][ #  # ]:          0 :         if (CharType != (sal_Int16)u_charType( Text.iterateCodePoints(&nStartPos, 0))) return -1;
                 [ #  # ]
     371                 :            : 
     372                 :          0 :         sal_Int32 nPos=nStartPos;
     373 [ #  # ][ #  # ]:          0 :         while(nStartPos > 0 && CharType == (sal_Int16)u_charType(Text.iterateCodePoints(&nPos, -1))) { nStartPos=nPos; }
         [ #  # ][ #  # ]
                 [ #  # ]
     374                 :          0 :         return nStartPos; // begin of char block is inclusive
     375                 :            : }
     376                 :            : 
     377                 :      52833 : sal_Int32 SAL_CALL BreakIteratorImpl::endOfCharBlock( const OUString& Text, sal_Int32 nStartPos,
     378                 :            :         const Locale& /*rLocale*/, sal_Int16 CharType ) throw(RuntimeException)
     379                 :            : {
     380                 :      52833 :         sal_Int32 strLen = Text.getLength();
     381                 :            : 
     382         [ -  + ]:      52833 :         if (CharType == CharType::ANY_CHAR) return strLen; // end of char block is exclusive
     383 [ +  - ][ +  + ]:      52833 :         if (nStartPos < 0 || nStartPos >= strLen) return -1;
     384 [ +  - ][ +  - ]:      52800 :         if (CharType != (sal_Int16)u_charType(Text.iterateCodePoints(&nStartPos, 0))) return -1;
                 [ +  + ]
     385                 :            : 
     386                 :      52791 :         sal_uInt32 ch=0;
     387 [ +  - ][ +  + ]:      53639 :         while(iterateCodePoints(Text, nStartPos, 1, ch) < strLen && CharType == (sal_Int16)u_charType(ch)) {}
         [ +  - ][ +  + ]
                 [ +  + ]
     388                 :      52833 :         return nStartPos; // end of char block is exclusive
     389                 :            : }
     390                 :            : 
     391                 :     164882 : sal_Int32 SAL_CALL BreakIteratorImpl::nextCharBlock( const OUString& Text, sal_Int32 nStartPos,
     392                 :            :         const Locale& /*rLocale*/, sal_Int16 CharType ) throw(RuntimeException)
     393                 :            : {
     394         [ -  + ]:     164882 :         if (CharType == CharType::ANY_CHAR) return -1;
     395 [ +  - ][ -  + ]:     164882 :         if (nStartPos < 0 || nStartPos >= Text.getLength()) return -1;
                 [ -  + ]
     396                 :            : 
     397 [ +  - ][ +  - ]:     164882 :         sal_Int16 numberOfChange = (CharType == (sal_Int16)u_charType(Text.iterateCodePoints(&nStartPos, 0))) ? 2 : 1;
                 [ -  + ]
     398                 :     164882 :         sal_Int32 strLen = Text.getLength();
     399                 :            : 
     400                 :     164882 :     sal_uInt32 ch=0;
     401 [ +  + ][ +  - ]:    1576684 :     while (numberOfChange > 0 && iterateCodePoints(Text, nStartPos, 1, ch) < strLen) {
         [ +  + ][ +  + ]
     402 [ +  - ][ +  + ]:    1411802 :         if ((CharType != (sal_Int16)u_charType(ch)) ^ (numberOfChange == 1))
     403                 :      95739 :             numberOfChange--;
     404                 :            :     }
     405         [ +  + ]:     164882 :     return numberOfChange == 0 ? nStartPos : -1;
     406                 :            : }
     407                 :            : 
     408                 :          0 : sal_Int32 SAL_CALL BreakIteratorImpl::previousCharBlock( const OUString& Text, sal_Int32 nStartPos,
     409                 :            :         const Locale& /*rLocale*/, sal_Int16 CharType ) throw(RuntimeException)
     410                 :            : {
     411         [ #  # ]:          0 :         if(CharType == CharType::ANY_CHAR) return -1;
     412 [ #  # ][ #  # ]:          0 :         if (nStartPos < 0 || nStartPos >= Text.getLength()) return -1;
                 [ #  # ]
     413                 :            : 
     414 [ #  # ][ #  # ]:          0 :         sal_Int16 numberOfChange = (CharType == (sal_Int16)u_charType(Text.iterateCodePoints(&nStartPos, 0))) ? 3 : 2;
                 [ #  # ]
     415                 :            : 
     416                 :          0 :         sal_uInt32 ch=0;
     417 [ #  # ][ #  # ]:          0 :         while (numberOfChange > 0 && iterateCodePoints(Text, nStartPos, -1, ch) >= 0) {
         [ #  # ][ #  # ]
     418 [ #  # ][ #  # ]:          0 :             if (((numberOfChange % 2) == 0) ^ (CharType != (sal_Int16)u_charType(ch)))
     419                 :          0 :                 numberOfChange--;
     420 [ #  # ][ #  # ]:          0 :             if (nStartPos == 0 && numberOfChange > 0) {
     421                 :          0 :                 numberOfChange--;
     422         [ #  # ]:          0 :                 if (numberOfChange == 0) return nStartPos;
     423                 :            :             }
     424                 :            :         }
     425 [ #  # ][ #  # ]:          0 :         return numberOfChange == 0 ? iterateCodePoints(Text, nStartPos, 1, ch) : -1;
     426                 :            : }
     427                 :            : 
     428                 :            : 
     429                 :            : 
     430                 :       7771 : sal_Int16 SAL_CALL BreakIteratorImpl::getWordType( const OUString& /*Text*/,
     431                 :            :         sal_Int32 /*nPos*/, const Locale& /*rLocale*/ ) throw(RuntimeException)
     432                 :            : {
     433                 :       7771 :         return 0;
     434                 :            : }
     435                 :            : 
     436                 :            : namespace
     437                 :            : {
     438                 :       1419 :     sal_Int16 getScriptClassByUAX24Script(sal_uInt32 currentChar)
     439                 :            :     {
     440                 :       1419 :         int32_t script = u_getIntPropertyValue(currentChar, UCHAR_SCRIPT);
     441                 :       1419 :         return unicode::getScriptClassFromUScriptCode(static_cast<UScriptCode>(script));
     442                 :            :     }
     443                 :            : 
     444                 :            :     struct UBlock2Script
     445                 :            :     {
     446                 :            :         UBlockCode from;
     447                 :            :         UBlockCode to;
     448                 :            :         sal_Int16 script;
     449                 :            :     };
     450                 :            : 
     451                 :            :     static UBlock2Script scriptList[] =
     452                 :            :     {
     453                 :            :         {UBLOCK_NO_BLOCK, UBLOCK_NO_BLOCK, ScriptType::WEAK},
     454                 :            :         {UBLOCK_BASIC_LATIN, UBLOCK_ARMENIAN, ScriptType::LATIN},
     455                 :            :         {UBLOCK_HEBREW, UBLOCK_MYANMAR, ScriptType::COMPLEX},
     456                 :            :         {UBLOCK_GEORGIAN, UBLOCK_GEORGIAN, ScriptType::LATIN},
     457                 :            :         {UBLOCK_HANGUL_JAMO, UBLOCK_HANGUL_JAMO, ScriptType::ASIAN},
     458                 :            :         {UBLOCK_ETHIOPIC, UBLOCK_ETHIOPIC, ScriptType::COMPLEX},
     459                 :            :         {UBLOCK_CHEROKEE, UBLOCK_RUNIC, ScriptType::LATIN},
     460                 :            :         {UBLOCK_KHMER, UBLOCK_MONGOLIAN, ScriptType::COMPLEX},
     461                 :            :         {UBLOCK_LATIN_EXTENDED_ADDITIONAL, UBLOCK_GREEK_EXTENDED, ScriptType::LATIN},
     462                 :            :         {UBLOCK_NUMBER_FORMS, UBLOCK_NUMBER_FORMS, ScriptType::WEAK},
     463                 :            :         {UBLOCK_CJK_RADICALS_SUPPLEMENT, UBLOCK_HANGUL_SYLLABLES, ScriptType::ASIAN},
     464                 :            :         {UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS, UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS, ScriptType::ASIAN},
     465                 :            :         {UBLOCK_ARABIC_PRESENTATION_FORMS_A, UBLOCK_ARABIC_PRESENTATION_FORMS_A, ScriptType::COMPLEX},
     466                 :            :         {UBLOCK_CJK_COMPATIBILITY_FORMS, UBLOCK_CJK_COMPATIBILITY_FORMS, ScriptType::ASIAN},
     467                 :            :         {UBLOCK_ARABIC_PRESENTATION_FORMS_B, UBLOCK_ARABIC_PRESENTATION_FORMS_B, ScriptType::COMPLEX},
     468                 :            :         {UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS, UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS, ScriptType::ASIAN},
     469                 :            :         {UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B, UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT, ScriptType::ASIAN},
     470                 :            :         {UBLOCK_CJK_STROKES, UBLOCK_CJK_STROKES, ScriptType::ASIAN},
     471                 :            :         {UBLOCK_LATIN_EXTENDED_C, UBLOCK_LATIN_EXTENDED_D, ScriptType::LATIN}
     472                 :            :     };
     473                 :            : 
     474                 :            :     #define scriptListCount SAL_N_ELEMENTS(scriptList)
     475                 :            : 
     476                 :            :     //always sets rScriptType
     477                 :            :     //
     478                 :            :     //returns true for characters historically explicitly assigned to
     479                 :            :     //latin/weak/asian
     480                 :            :     //
     481                 :            :     //returns false for characters that historically implicitly assigned to
     482                 :            :     //weak as unknown
     483                 :    8488463 :     bool getCompatibilityScriptClassByBlock(sal_uInt32 currentChar, sal_Int16 &rScriptType)
     484                 :            :     {
     485                 :    8488463 :         bool bKnown = true;
     486                 :            :         //handle specific characters always as weak:
     487                 :            :         //  0x01 - this breaks a word
     488                 :            :         //  0x02 - this can be inside a word
     489                 :            :         //  0x20 & 0xA0 - Bug 102975, declare western space and non-break space as WEAK char.
     490 [ +  + ][ +  + ]:    8488463 :         if( 0x01 == currentChar || 0x02 == currentChar || 0x20 == currentChar || 0xA0 == currentChar)
         [ +  + ][ +  + ]
     491                 :     558596 :             rScriptType = ScriptType::WEAK;
     492                 :            :         // workaround for Coptic
     493 [ +  + ][ -  + ]:    7929867 :         else if ( 0x2C80 <= currentChar && 0x2CE3 >= currentChar)
     494                 :          0 :             rScriptType = ScriptType::LATIN;
     495                 :            :         else
     496                 :            :         {
     497                 :    7929867 :             UBlockCode block=ublock_getCode(currentChar);
     498                 :    7929867 :             size_t i = 0;
     499         [ +  - ]:   15877173 :             while (i < scriptListCount)
     500                 :            :             {
     501         [ +  + ]:   15877173 :                 if (block <= scriptList[i].to)
     502                 :    7929867 :                     break;
     503                 :    7947306 :                 ++i;
     504                 :            :             }
     505 [ +  - ][ +  + ]:    7929867 :             if (i < scriptListCount && block >= scriptList[i].from)
     506                 :    7928448 :                 rScriptType = scriptList[i].script;
     507                 :            :             else
     508                 :            :             {
     509                 :       1419 :                 rScriptType = ScriptType::WEAK;
     510                 :       1419 :                 bKnown = false;
     511                 :            :             }
     512                 :            :         }
     513                 :    8488463 :         return bKnown;
     514                 :            :     }
     515                 :            : }
     516                 :            : 
     517                 :    9639175 : sal_Int16  BreakIteratorImpl::getScriptClass(sal_uInt32 currentChar)
     518                 :            : {
     519                 :            :     static sal_uInt32 lastChar = 0;
     520                 :            :     static sal_Int16 nRet = 0;
     521                 :            : 
     522         [ +  + ]:    9639175 :     if (currentChar != lastChar)
     523                 :            :     {
     524                 :    8488463 :         lastChar = currentChar;
     525                 :            : 
     526         [ +  + ]:    8488463 :         if (!getCompatibilityScriptClassByBlock(currentChar, nRet))
     527                 :       1419 :             nRet = getScriptClassByUAX24Script(currentChar);
     528                 :            :     }
     529                 :            : 
     530                 :    9639175 :     return nRet;
     531                 :            : }
     532                 :            : 
     533                 :    4418942 : static inline sal_Bool operator == (const Locale& l1, const Locale& l2) {
     534 [ +  + ][ +  + ]:    4418942 :         return l1.Language == l2.Language && l1.Country == l2.Country && l1.Variant == l2.Variant;
                 [ +  - ]
     535                 :            : }
     536                 :            : 
     537                 :       6102 : sal_Bool SAL_CALL BreakIteratorImpl::createLocaleSpecificBreakIterator(const OUString& aLocaleName) throw( RuntimeException )
     538                 :            : {
     539                 :            :         // to share service between same Language but different Country code, like zh_CN and zh_TW
     540         [ +  + ]:       6381 :         for (size_t l = 0; l < lookupTable.size(); l++) {
     541                 :        366 :             lookupTableItem *listItem = lookupTable[l];
     542         [ +  + ]:        366 :             if (aLocaleName == listItem->aLocale.Language) {
     543         [ +  - ]:         87 :                 xBI = listItem->xBI;
     544                 :         87 :                 return sal_True;
     545                 :            :             }
     546                 :            :         }
     547                 :            : 
     548         [ +  - ]:       6015 :         Reference < uno::XInterface > xI = xMSF->createInstance(
     549         [ +  - ]:       6015 :             OUString("com.sun.star.i18n.BreakIterator_") + aLocaleName);
     550                 :            : 
     551         [ +  + ]:       6015 :         if ( xI.is() ) {
     552 [ +  - ][ +  - ]:       1997 :             xI->queryInterface( getCppuType((const Reference< XBreakIterator>*)0) ) >>= xBI;
         [ +  - ][ +  - ]
     553         [ +  - ]:       1997 :             if (xBI.is()) {
     554 [ +  - ][ +  - ]:       1997 :                 lookupTable.push_back(new lookupTableItem(Locale(aLocaleName, aLocaleName, aLocaleName), xBI));
                 [ +  - ]
     555                 :       1997 :                 return sal_True;
     556                 :            :             }
     557                 :            :         }
     558                 :       6102 :         return sal_False;
     559                 :            : }
     560                 :            : 
     561                 :            : Reference < XBreakIterator > SAL_CALL
     562                 :    4073694 : BreakIteratorImpl::getLocaleSpecificBreakIterator(const Locale& rLocale) throw (RuntimeException)
     563                 :            : {
     564 [ +  + ][ +  + ]:    4073694 :         if (xBI.is() && rLocale == aLocale)
                 [ +  + ]
     565                 :    3933024 :             return xBI;
     566         [ +  - ]:     140670 :         else if (xMSF.is()) {
     567                 :     140670 :             aLocale = rLocale;
     568                 :            : 
     569         [ +  + ]:     349326 :             for (size_t i = 0; i < lookupTable.size(); i++) {
     570                 :     347242 :                 lookupTableItem *listItem = lookupTable[i];
     571         [ +  + ]:     347242 :                 if (rLocale == listItem->aLocale)
     572         [ +  - ]:     138586 :                     return xBI = listItem->xBI;
     573                 :            :             }
     574                 :            : 
     575                 :       2084 :             sal_Unicode under = (sal_Unicode)'_';
     576                 :            : 
     577                 :       2084 :             sal_Int32 l = rLocale.Language.getLength();
     578                 :       2084 :             sal_Int32 c = rLocale.Country.getLength();
     579                 :       2084 :             sal_Int32 v = rLocale.Variant.getLength();
     580                 :       2084 :             OUStringBuffer aBuf(l+c+v+3);
     581                 :            : 
     582 [ +  - ][ -  + ]:      12294 :             if ((l > 0 && c > 0 && v > 0 &&
         [ #  # ][ +  + ]
         [ +  - ][ +  - ]
         [ +  + ][ +  -  
          +  +  +  -  -  
              + ][ #  # ]
         [ +  + ][ +  + ]
         [ +  - ][ +  - ]
                 [ +  + ]
     583                 :            :                     // load service with name <base>_<lang>_<country>_<varian>
     584 [ #  # ][ #  # ]:          0 :                     createLocaleSpecificBreakIterator(aBuf.append(rLocale.Language).append(under).append(
     585 [ #  # ][ #  # ]:       2084 :                                     rLocale.Country).append(under).append(rLocale.Variant).makeStringAndClear())) ||
         [ #  # ][ #  # ]
         [ #  # ][ -  + ]
                 [ #  # ]
     586                 :            :                 (l > 0 && c > 0 &&
     587                 :            :                     // load service with name <base>_<lang>_<country>
     588 [ +  - ][ +  - ]:       2018 :                     createLocaleSpecificBreakIterator(aBuf.append(rLocale.Language).append(under).append(
     589 [ +  - ][ +  - ]:       4102 :                                     rLocale.Country).makeStringAndClear())) ||
         [ +  - ][ +  + ]
                 [ #  # ]
     590                 :       2018 :                 (l > 0 && c > 0 && rLocale.Language.compareToAscii("zh") == 0 &&
     591                 :          3 :                                     (rLocale.Country.compareToAscii("HK") == 0 ||
     592                 :          3 :                                     rLocale.Country.compareToAscii("MO") == 0) &&
     593                 :            :                     // if the country code is HK or MO, one more step to try TW.
     594 [ #  # ][ #  # ]:          0 :                     createLocaleSpecificBreakIterator(aBuf.append(rLocale.Language).append(under).appendAscii(
     595 [ #  # ][ #  # ]:       2084 :                                     "TW").makeStringAndClear())) ||
         [ #  # ][ -  + ]
                 [ #  # ]
     596                 :            :                 (l > 0 &&
     597                 :            :                     // load service with name <base>_<lang>
     598         [ +  - ]:       2018 :                     createLocaleSpecificBreakIterator(rLocale.Language)) ||
     599                 :            :                     // load default service with name <base>_Unicode
     600 [ +  - ][ +  + ]:       4150 :                     createLocaleSpecificBreakIterator(OUString("Unicode"))) {
                 [ +  + ]
           [ #  #  #  # ]
     601 [ +  - ][ +  - ]:       2084 :                 lookupTable.push_back( new lookupTableItem(aLocale, xBI) );
                 [ +  - ]
     602                 :       2084 :                 return xBI;
     603         [ -  + ]:     140670 :             }
     604                 :            :         }
     605         [ #  # ]:    4073694 :         throw RuntimeException();
     606                 :            : }
     607                 :            : 
     608                 :            : const sal_Char cBreakIterator[] = "com.sun.star.i18n.BreakIterator";
     609                 :            : 
     610                 :            : OUString SAL_CALL
     611                 :          0 : BreakIteratorImpl::getImplementationName(void) throw( RuntimeException )
     612                 :            : {
     613                 :          0 :         return OUString::createFromAscii(cBreakIterator);
     614                 :            : }
     615                 :            : 
     616                 :            : sal_Bool SAL_CALL
     617                 :          0 : BreakIteratorImpl::supportsService(const OUString& rServiceName) throw( RuntimeException )
     618                 :            : {
     619                 :          0 :         return !rServiceName.compareToAscii(cBreakIterator);
     620                 :            : }
     621                 :            : 
     622                 :            : Sequence< OUString > SAL_CALL
     623                 :          0 : BreakIteratorImpl::getSupportedServiceNames(void) throw( RuntimeException )
     624                 :            : {
     625                 :          0 :         Sequence< OUString > aRet(1);
     626         [ #  # ]:          0 :         aRet[0] = OUString::createFromAscii(cBreakIterator);
     627                 :          0 :         return aRet;
     628                 :            : }
     629                 :            : 
     630                 :            : } } } }
     631                 :            : 
     632                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10