LCOV - code coverage report
Current view: top level - vcl/source/gdi - sallayout.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 668 980 68.2 %
Date: 2012-08-25 Functions: 49 62 79.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 466 994 46.9 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*************************************************************************
       3                 :            :  *
       4                 :            :  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       5                 :            :  *
       6                 :            :  * Copyright 2000, 2010 Oracle and/or its affiliates.
       7                 :            :  *
       8                 :            :  * OpenOffice.org - a multi-platform office productivity suite
       9                 :            :  *
      10                 :            :  * This file is part of OpenOffice.org.
      11                 :            :  *
      12                 :            :  * OpenOffice.org is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU Lesser General Public License version 3
      14                 :            :  * only, as published by the Free Software Foundation.
      15                 :            :  *
      16                 :            :  * OpenOffice.org is distributed in the hope that it will be useful,
      17                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19                 :            :  * GNU Lesser General Public License version 3 for more details
      20                 :            :  * (a copy is included in the LICENSE file that accompanied this code).
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU Lesser General Public License
      23                 :            :  * version 3 along with OpenOffice.org.  If not, see
      24                 :            :  * <http://www.openoffice.org/license.html>
      25                 :            :  * for a copy of the LGPLv3 License.
      26                 :            :  *
      27                 :            :  ************************************************************************/
      28                 :            : 
      29                 :            : 
      30                 :            : #include <cstdio>
      31                 :            : 
      32                 :            : #define _USE_MATH_DEFINES
      33                 :            : #include <math.h>
      34                 :            : #include <sal/alloca.h>
      35                 :            : 
      36                 :            : #include <salgdi.hxx>
      37                 :            : #include <sallayout.hxx>
      38                 :            : #include <basegfx/polygon/b2dpolypolygon.hxx>
      39                 :            : #include <basegfx/matrix/b2dhommatrix.hxx>
      40                 :            : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      41                 :            : 
      42                 :            : #include <i18npool/lang.h>
      43                 :            : 
      44                 :            : #include <tools/debug.hxx>
      45                 :            : 
      46                 :            : #include <limits.h>
      47                 :            : 
      48                 :            : #if defined _MSC_VER
      49                 :            : #pragma warning(push, 1)
      50                 :            : #endif
      51                 :            : #include <unicode/ubidi.h>
      52                 :            : #include <unicode/uchar.h>
      53                 :            : #if defined _MSC_VER
      54                 :            : #pragma warning(pop)
      55                 :            : #endif
      56                 :            : 
      57                 :            : #include <algorithm>
      58                 :            : 
      59                 :            : #ifdef DEBUG
      60                 :            : //#define MULTI_SL_DEBUG
      61                 :            : #endif
      62                 :            : 
      63                 :            : #ifdef MULTI_SL_DEBUG
      64                 :            : #include <string>
      65                 :            : FILE * mslLogFile = NULL;
      66                 :            : FILE * mslLog()
      67                 :            : {
      68                 :            : #ifdef MSC
      69                 :            :     std::string logFileName(getenv("TEMP"));
      70                 :            :     logFileName.append("\\msllayout.log");
      71                 :            :     if (mslLogFile == NULL) mslLogFile = fopen(logFileName.c_str(),"w");
      72                 :            :     else fflush(mslLogFile);
      73                 :            :     return mslLogFile;
      74                 :            : #else
      75                 :            :     return stdout;
      76                 :            : #endif
      77                 :            : }
      78                 :            : #endif
      79                 :            : // =======================================================================
      80                 :            : 
      81                 :            : // TODO: ask the glyph directly, for now we need this method because of #i99367#
      82                 :            : // true if a codepoint doesn't influence the logical text width
      83                 :       5156 : bool IsDiacritic( sal_UCS4 nChar )
      84                 :            : {
      85                 :            :     // shortcut abvious non-diacritics
      86         [ -  + ]:       5156 :     if( nChar < 0x0300 )
      87                 :          0 :         return false;
      88         [ -  + ]:       5156 :      if( nChar >= 0x2100 )
      89                 :          0 :         return false;
      90                 :            : 
      91                 :            :     // TODO: #i105058# use icu uchar.h's character classification instead of the handcrafted table
      92                 :            :     struct DiaRange { sal_UCS4 mnMin, mnEnd;};
      93                 :            :     static const DiaRange aRanges[] = {
      94                 :            :         {0x0300, 0x0370},
      95                 :            :         {0x0590, 0x05BE}, {0x05BF, 0x05C0}, {0x05C1, 0x05C3}, {0x05C4, 0x05C6}, {0x05C7, 0x05C8},
      96                 :            :         {0x0610, 0x061B}, {0x064B, 0x0660}, {0x0670, 0x0671}, {0x06D6, 0x06DD}, {0x06DF, 0x06E5}, {0x06E7, 0x06E9}, {0x06EA,0x06EF},
      97                 :            :         {0x0730, 0x074D}, {0x07A6, 0x07B1}, {0x07EB, 0x07F4},
      98                 :            :         {0x1DC0, 0x1E00},
      99                 :            :         {0x205F, 0x2070}, {0x20D0, 0x2100},
     100                 :            :         {0xFB1E, 0xFB1F}
     101                 :            :     };
     102                 :            : 
     103                 :            :     // TODO: almost anything is faster than an O(n) search
     104                 :            :     static const int nCount = SAL_N_ELEMENTS(aRanges);
     105                 :       5156 :     const DiaRange* pRange = &aRanges[0];
     106         [ +  + ]:      76536 :     for( int i = nCount; --i >= 0; ++pRange )
     107 [ +  + ][ +  + ]:      73615 :         if( (pRange->mnMin <= nChar) && (nChar < pRange->mnEnd) )
     108                 :       2235 :             return true;
     109                 :            : 
     110                 :       5156 :     return false;
     111                 :            : }
     112                 :            : 
     113                 :            : // =======================================================================
     114                 :            : 
     115                 :          0 : int GetVerticalFlags( sal_UCS4 nChar )
     116                 :            : {
     117 [ #  # ][ #  # ]:          0 :     if( (nChar >= 0x1100 && nChar <= 0x11f9)    // Hangul Jamo
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     118                 :            :      || (nChar == 0x2030 || nChar == 0x2031)    // per mille sign
     119                 :            :      || (nChar >= 0x3000 && nChar <= 0xfaff)    // unified CJK
     120                 :            :      || (nChar >= 0xfe20 && nChar <= 0xfe6f)    // CJK compatibility
     121                 :            :      || (nChar >= 0xff00 && nChar <= 0xfffd) )  // other CJK
     122                 :            :     {
     123                 :            :         /* #i52932# remember:
     124                 :            :          nChar == 0x2010 || nChar == 0x2015
     125                 :            :          nChar == 0x2016 || nChar == 0x2026
     126                 :            :          are GF_NONE also, but already handled in the outer if condition
     127                 :            :         */
     128 [ #  # ][ #  # ]:          0 :         if((nChar >= 0x3008 && nChar <= 0x301C && nChar != 0x3012)
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     129                 :            :         || (nChar == 0xFF3B || nChar == 0xFF3D)
     130                 :            :         || (nChar >= 0xFF5B && nChar <= 0xFF9F) // halfwidth forms
     131                 :            :         || (nChar == 0xFFE3) )
     132                 :          0 :             return GF_NONE; // not rotated
     133         [ #  # ]:          0 :         else if( nChar == 0x30fc )
     134                 :          0 :             return GF_ROTR; // right
     135                 :          0 :         return GF_ROTL;     // left
     136                 :            :     }
     137 [ #  # ][ #  # ]:          0 :     else if( (nChar >= 0x20000) && (nChar <= 0x3FFFF) ) // all SIP/TIP ideographs
     138                 :          0 :         return GF_ROTL; // left
     139                 :            : 
     140                 :          0 :     return GF_NONE; // not rotated as default
     141                 :            : }
     142                 :            : 
     143                 :            : // -----------------------------------------------------------------------
     144                 :            : 
     145                 :          0 : sal_UCS4 GetVerticalChar( sal_UCS4 )
     146                 :            : {
     147                 :          0 :     return 0; // #i14788# input method is responsible vertical char changes
     148                 :            : }
     149                 :            : 
     150                 :            : // -----------------------------------------------------------------------
     151                 :            : 
     152                 :         24 : VCL_DLLPUBLIC sal_UCS4 GetMirroredChar( sal_UCS4 nChar )
     153                 :            : {
     154                 :         24 :     nChar = u_charMirror( nChar );
     155                 :         24 :     return nChar;
     156                 :            : }
     157                 :            : 
     158                 :            : // -----------------------------------------------------------------------
     159                 :            : 
     160                 :   10657779 : sal_UCS4 GetLocalizedChar( sal_UCS4 nChar, LanguageType eLang )
     161                 :            : {
     162                 :            :     // currently only conversion from ASCII digits is interesting
     163 [ +  - ][ -  + ]:   10657779 :     if( (nChar < '0') || ('9' < nChar) )
     164                 :          0 :         return nChar;
     165                 :            : 
     166                 :            :     int nOffset;
     167                 :            :     // eLang & LANGUAGE_MASK_PRIMARY catches language independent of region.
     168                 :            :     // CAVEAT! To some like Mongolian MS assigned the same primary language
     169                 :            :     // although the script type is different!
     170   [ +  -  -  -  :   10657779 :     switch( eLang & LANGUAGE_MASK_PRIMARY )
          -  -  -  -  -  
          -  -  -  -  -  
             -  -  -  - ]
     171                 :            :     {
     172                 :            :         default:
     173                 :   10657779 :             nOffset = 0;
     174                 :   10657779 :             break;
     175                 :            :         case LANGUAGE_ARABIC_SAUDI_ARABIA  & LANGUAGE_MASK_PRIMARY:
     176                 :          0 :             nOffset = 0x0660 - '0';  // arabic-indic digits
     177                 :          0 :             break;
     178                 :            :         case LANGUAGE_FARSI         & LANGUAGE_MASK_PRIMARY:
     179                 :            :         case LANGUAGE_URDU          & LANGUAGE_MASK_PRIMARY:
     180                 :            :         case LANGUAGE_PUNJABI       & LANGUAGE_MASK_PRIMARY: //???
     181                 :            :         case LANGUAGE_SINDHI        & LANGUAGE_MASK_PRIMARY:
     182                 :          0 :             nOffset = 0x06F0 - '0';  // eastern arabic-indic digits
     183                 :          0 :             break;
     184                 :            :         case LANGUAGE_BENGALI       & LANGUAGE_MASK_PRIMARY:
     185                 :          0 :             nOffset = 0x09E6 - '0';  // bengali
     186                 :          0 :             break;
     187                 :            :         case LANGUAGE_HINDI         & LANGUAGE_MASK_PRIMARY:
     188                 :          0 :             nOffset = 0x0966 - '0';  // devanagari
     189                 :          0 :             break;
     190                 :            :         case LANGUAGE_AMHARIC_ETHIOPIA & LANGUAGE_MASK_PRIMARY:
     191                 :            :         case LANGUAGE_TIGRIGNA_ETHIOPIA & LANGUAGE_MASK_PRIMARY:
     192                 :            :         // TODO case:
     193                 :          0 :             nOffset = 0x1369 - '0';  // ethiopic
     194                 :          0 :             break;
     195                 :            :         case LANGUAGE_GUJARATI      & LANGUAGE_MASK_PRIMARY:
     196                 :          0 :             nOffset = 0x0AE6 - '0';  // gujarati
     197                 :          0 :             break;
     198                 :            : #ifdef LANGUAGE_GURMUKHI // TODO case:
     199                 :            :         case LANGUAGE_GURMUKHI      & LANGUAGE_MASK_PRIMARY:
     200                 :            :             nOffset = 0x0A66 - '0';  // gurmukhi
     201                 :            :             break;
     202                 :            : #endif
     203                 :            :         case LANGUAGE_KANNADA       & LANGUAGE_MASK_PRIMARY:
     204                 :          0 :             nOffset = 0x0CE6 - '0';  // kannada
     205                 :          0 :             break;
     206                 :            :         case LANGUAGE_KHMER         & LANGUAGE_MASK_PRIMARY:
     207                 :          0 :             nOffset = 0x17E0 - '0';  // khmer
     208                 :          0 :             break;
     209                 :            :         case LANGUAGE_LAO           & LANGUAGE_MASK_PRIMARY:
     210                 :          0 :             nOffset = 0x0ED0 - '0';  // lao
     211                 :          0 :             break;
     212                 :            :         case LANGUAGE_MALAYALAM     & LANGUAGE_MASK_PRIMARY:
     213                 :          0 :             nOffset = 0x0D66 - '0';  // malayalam
     214                 :          0 :             break;
     215                 :            :         case LANGUAGE_MONGOLIAN     & LANGUAGE_MASK_PRIMARY:
     216         [ #  # ]:          0 :             if (eLang == LANGUAGE_MONGOLIAN_MONGOLIAN)
     217                 :          0 :                 nOffset = 0x1810 - '0';   // mongolian
     218                 :            :             else
     219                 :          0 :                 nOffset = 0;              // mongolian cyrillic
     220                 :          0 :             break;
     221                 :            :         case LANGUAGE_BURMESE       & LANGUAGE_MASK_PRIMARY:
     222                 :          0 :             nOffset = 0x1040 - '0';  // myanmar
     223                 :          0 :             break;
     224                 :            :         case LANGUAGE_ORIYA         & LANGUAGE_MASK_PRIMARY:
     225                 :          0 :             nOffset = 0x0B66 - '0';  // oriya
     226                 :          0 :             break;
     227                 :            :         case LANGUAGE_TAMIL         & LANGUAGE_MASK_PRIMARY:
     228                 :          0 :             nOffset = 0x0BE7 - '0';  // tamil
     229                 :          0 :             break;
     230                 :            :         case LANGUAGE_TELUGU        & LANGUAGE_MASK_PRIMARY:
     231                 :          0 :             nOffset = 0x0C66 - '0';  // telugu
     232                 :          0 :             break;
     233                 :            :         case LANGUAGE_THAI          & LANGUAGE_MASK_PRIMARY:
     234                 :          0 :             nOffset = 0x0E50 - '0';  // thai
     235                 :          0 :             break;
     236                 :            :         case LANGUAGE_TIBETAN       & LANGUAGE_MASK_PRIMARY:
     237                 :          0 :             nOffset = 0x0F20 - '0';  // tibetan
     238                 :          0 :             break;
     239                 :            :     }
     240                 :            : 
     241                 :   10657779 :     nChar += nOffset;
     242                 :   10657779 :     return nChar;
     243                 :            : }
     244                 :            : 
     245                 :            : // -----------------------------------------------------------------------
     246                 :            : 
     247                 :   22389785 : inline bool IsControlChar( sal_UCS4 cChar )
     248                 :            : {
     249                 :            :     // C0 control characters
     250 [ +  - ][ +  + ]:   22389785 :     if( (0x0001 <= cChar) && (cChar <= 0x001F) )
     251                 :        544 :         return true;
     252                 :            :     // formatting characters
     253 [ +  + ][ -  + ]:   22389241 :     if( (0x200E <= cChar) && (cChar <= 0x200F) )
     254                 :          0 :         return true;
     255 [ +  + ][ -  + ]:   22389241 :     if( (0x2028 <= cChar) && (cChar <= 0x202E) )
     256                 :          0 :         return true;
     257                 :            :     // deprecated formatting characters
     258 [ +  + ][ -  + ]:   22389241 :     if( (0x206A <= cChar) && (cChar <= 0x206F) )
     259                 :          0 :         return true;
     260         [ -  + ]:   22389241 :     if( (0x2060 == cChar) )
     261                 :          0 :         return true;
     262                 :            :     // byte order markers and invalid unicode
     263 [ +  - ][ +  - ]:   22389241 :     if( (cChar == 0xFEFF) || (cChar == 0xFFFE) || (cChar == 0xFFFF) )
                 [ -  + ]
     264                 :          0 :         return true;
     265                 :   22389785 :     return false;
     266                 :            : }
     267                 :            : 
     268                 :            : // =======================================================================
     269                 :            : 
     270                 :      19308 : bool ImplLayoutRuns::AddPos( int nCharPos, bool bRTL )
     271                 :            : {
     272                 :            :     // check if charpos could extend current run
     273                 :      19308 :     int nIndex = maRuns.size();
     274         [ +  + ]:      19308 :     if( nIndex >= 2 )
     275                 :            :     {
     276                 :        594 :         int nRunPos0 = maRuns[ nIndex-2 ];
     277                 :        594 :         int nRunPos1 = maRuns[ nIndex-1 ];
     278 [ +  - ][ +  - ]:        594 :         if( ((nCharPos + bRTL) == nRunPos1)
     279                 :            :     &&  ((nRunPos0 > nRunPos1) == bRTL) )
     280                 :            :         {
     281                 :            :             // extend current run by new charpos
     282                 :        594 :             maRuns[ nIndex-1 ] = nCharPos + !bRTL;
     283                 :        594 :             return false;
     284                 :            :         }
     285                 :            :         // ignore new charpos when it is in current run
     286 [ #  # ][ #  # ]:          0 :         if( (nRunPos0 <= nCharPos) && (nCharPos < nRunPos1) )
     287                 :          0 :             return false;
     288 [ #  # ][ #  # ]:          0 :         if( (nRunPos1 <= nCharPos) && (nCharPos < nRunPos0) )
     289                 :          0 :             return false;
     290                 :            :     }
     291                 :            : 
     292                 :            :     // else append a new run consisting of the new charpos
     293 [ -  + ][ +  - ]:      18714 :     maRuns.push_back( nCharPos + (bRTL ? 1 : 0) );
     294 [ -  + ][ +  - ]:      18714 :     maRuns.push_back( nCharPos + (bRTL ? 0 : 1) );
     295                 :      19308 :     return true;
     296                 :            : }
     297                 :            : 
     298                 :            : // -----------------------------------------------------------------------
     299                 :            : 
     300                 :     981732 : bool ImplLayoutRuns::AddRun( int nCharPos0, int nCharPos1, bool bRTL )
     301                 :            : {
     302         [ +  + ]:     981732 :     if( nCharPos0 == nCharPos1 )
     303                 :        613 :         return false;
     304                 :            : 
     305                 :            :     // swap if needed
     306         [ +  + ]:     981119 :     if( bRTL == (nCharPos0 < nCharPos1) )
     307                 :            :     {
     308                 :        232 :         int nTemp = nCharPos0;
     309                 :        232 :         nCharPos0 = nCharPos1;
     310                 :        232 :         nCharPos1 = nTemp;
     311                 :            :     }
     312                 :            : 
     313                 :            :     // append new run
     314                 :     981119 :     maRuns.push_back( nCharPos0 );
     315                 :     981119 :     maRuns.push_back( nCharPos1 );
     316                 :     981732 :     return true;
     317                 :            : }
     318                 :            : 
     319                 :            : // -----------------------------------------------------------------------
     320                 :            : 
     321                 :      19308 : bool ImplLayoutRuns::PosIsInRun( int nCharPos ) const
     322                 :            : {
     323         [ -  + ]:      19308 :     if( mnRunIndex >= (int)maRuns.size() )
     324                 :          0 :         return false;
     325                 :            : 
     326                 :      19308 :     int nMinCharPos = maRuns[ mnRunIndex+0 ];
     327                 :      19308 :     int nEndCharPos = maRuns[ mnRunIndex+1 ];
     328         [ -  + ]:      19308 :     if( nMinCharPos > nEndCharPos ) // reversed in RTL case
     329                 :            :     {
     330                 :          0 :         int nTemp = nMinCharPos;
     331                 :          0 :         nMinCharPos = nEndCharPos;
     332                 :          0 :         nEndCharPos = nTemp;
     333                 :            :     }
     334                 :            : 
     335         [ -  + ]:      19308 :     if( nCharPos < nMinCharPos )
     336                 :          0 :         return false;
     337         [ -  + ]:      19308 :     if( nCharPos >= nEndCharPos )
     338                 :          0 :         return false;
     339                 :      19308 :     return true;
     340                 :            : }
     341                 :            : 
     342                 :      28368 : bool ImplLayoutRuns::PosIsInAnyRun( int nCharPos ) const
     343                 :            : {
     344                 :      28368 :     bool bRet = false;
     345                 :      28368 :     int nRunIndex = mnRunIndex;
     346                 :            : 
     347                 :      28368 :     ImplLayoutRuns *pThis = const_cast<ImplLayoutRuns*>(this);
     348                 :            : 
     349                 :      28368 :     pThis->ResetPos();
     350                 :            : 
     351         [ +  + ]:      28368 :     for (size_t i = 0; i < maRuns.size(); i+=2)
     352                 :            :     {
     353         [ +  - ]:       9357 :         if( (bRet = PosIsInRun( nCharPos )) == true )
     354                 :       9357 :             break;
     355                 :          0 :         pThis->NextRun();
     356                 :            :     }
     357                 :            : 
     358                 :      28368 :     pThis->mnRunIndex = nRunIndex;
     359                 :      28368 :     return bRet;
     360                 :            : }
     361                 :            : 
     362                 :            : 
     363                 :            : // -----------------------------------------------------------------------
     364                 :            : 
     365                 :    1680867 : bool ImplLayoutRuns::GetNextPos( int* nCharPos, bool* bRightToLeft )
     366                 :            : {
     367                 :            :     // negative nCharPos => reset to first run
     368         [ +  + ]:    1680867 :     if( *nCharPos < 0 )
     369                 :      83735 :         mnRunIndex = 0;
     370                 :            : 
     371                 :            :     // return false when all runs completed
     372         [ +  + ]:    1680867 :     if( mnRunIndex >= (int)maRuns.size() )
     373                 :         32 :         return false;
     374                 :            : 
     375                 :    1680835 :     int nRunPos0 = maRuns[ mnRunIndex+0 ];
     376                 :    1680835 :     int nRunPos1 = maRuns[ mnRunIndex+1 ];
     377                 :    1680835 :     *bRightToLeft = (nRunPos0 > nRunPos1);
     378                 :            : 
     379         [ +  + ]:    1680835 :     if( *nCharPos < 0 )
     380                 :            :     {
     381                 :            :         // get first valid nCharPos in run
     382                 :      83703 :         *nCharPos = nRunPos0;
     383                 :            :     }
     384                 :            :     else
     385                 :            :     {
     386                 :            :         // advance to next nCharPos for LTR case
     387         [ +  + ]:    1597132 :         if( !*bRightToLeft )
     388                 :    1597108 :             ++(*nCharPos);
     389                 :            : 
     390                 :            :         // advance to next run if current run is completed
     391         [ +  + ]:    1597132 :         if( *nCharPos == nRunPos1 )
     392                 :            :         {
     393         [ +  - ]:      83703 :             if( (mnRunIndex += 2) >= (int)maRuns.size() )
     394                 :      83703 :                 return false;
     395                 :          0 :             nRunPos0 = maRuns[ mnRunIndex+0 ];
     396                 :          0 :             nRunPos1 = maRuns[ mnRunIndex+1 ];
     397                 :          0 :             *bRightToLeft = (nRunPos0 > nRunPos1);
     398                 :          0 :             *nCharPos = nRunPos0;
     399                 :            :         }
     400                 :            :     }
     401                 :            : 
     402                 :            :     // advance to next nCharPos for RTL case
     403         [ +  + ]:    1597132 :     if( *bRightToLeft )
     404                 :         24 :         --(*nCharPos);
     405                 :            : 
     406                 :    1680867 :     return true;
     407                 :            : }
     408                 :            : 
     409                 :            : // -----------------------------------------------------------------------
     410                 :            : 
     411                 :    2001478 : bool ImplLayoutRuns::GetRun( int* nMinRunPos, int* nEndRunPos, bool* bRightToLeft ) const
     412                 :            : {
     413         [ +  + ]:    2001478 :     if( mnRunIndex >= (int)maRuns.size() )
     414                 :     996070 :         return false;
     415                 :            : 
     416                 :    1005408 :     int nRunPos0 = maRuns[ mnRunIndex+0 ];
     417                 :    1005408 :     int nRunPos1 = maRuns[ mnRunIndex+1 ];
     418                 :    1005408 :     *bRightToLeft = (nRunPos1 < nRunPos0) ;
     419         [ +  + ]:    1005408 :     if( !*bRightToLeft )
     420                 :            :     {
     421                 :    1005184 :         *nMinRunPos = nRunPos0;
     422                 :    1005184 :         *nEndRunPos = nRunPos1;
     423                 :            :     }
     424                 :            :     else
     425                 :            :     {
     426                 :        224 :         *nMinRunPos = nRunPos1;
     427                 :        224 :         *nEndRunPos = nRunPos0;
     428                 :            :     }
     429                 :    2001478 :     return true;
     430                 :            : }
     431                 :            : 
     432                 :            : // =======================================================================
     433                 :            : 
     434                 :     981170 : ImplLayoutArgs::ImplLayoutArgs( const xub_Unicode* pStr, int nLen,
     435                 :            :     int nMinCharPos, int nEndCharPos, int nFlags )
     436                 :            : :
     437                 :            :     mnFlags( nFlags ),
     438                 :            :     mnLength( nLen ),
     439                 :            :     mnMinCharPos( nMinCharPos ),
     440                 :            :     mnEndCharPos( nEndCharPos ),
     441                 :            :     mpStr( pStr ),
     442                 :            :     mpDXArray( NULL ),
     443                 :            :     mnLayoutWidth( 0 ),
     444         [ +  - ]:     981170 :     mnOrientation( 0 )
     445                 :            : {
     446         [ +  + ]:     981170 :     if( mnFlags & SAL_LAYOUT_BIDI_STRONG )
     447                 :            :     {
     448                 :            :         // handle strong BiDi mode
     449                 :            : 
     450                 :            :         // do not bother to BiDi analyze strong LTR/RTL
     451                 :            :         // TODO: can we assume these strings do not have unicode control chars?
     452                 :            :         //       if not remove the control characters from the runs
     453                 :     977608 :         bool bRTL = ((mnFlags & SAL_LAYOUT_BIDI_RTL) != 0);
     454         [ +  - ]:     977608 :         AddRun( mnMinCharPos, mnEndCharPos, bRTL );
     455                 :            :     }
     456                 :            :     else
     457                 :            :     {
     458                 :            :         // handle weak BiDi mode
     459                 :            : 
     460                 :       3562 :         UBiDiLevel nLevel = UBIDI_DEFAULT_LTR;
     461         [ +  - ]:       3562 :         if( mnFlags & SAL_LAYOUT_BIDI_RTL )
     462                 :       3562 :             nLevel = UBIDI_DEFAULT_RTL;
     463                 :            : 
     464                 :            :         // prepare substring for BiDi analysis
     465                 :            :         // TODO: reuse allocated pParaBidi
     466                 :       3562 :         UErrorCode rcI18n = U_ZERO_ERROR;
     467         [ +  - ]:       3562 :         UBiDi* pParaBidi = ubidi_openSized( mnLength, 0, &rcI18n );
     468         [ +  - ]:       3562 :         if( !pParaBidi )
     469                 :     981170 :             return;
     470         [ +  - ]:       3562 :         ubidi_setPara( pParaBidi, reinterpret_cast<const UChar *>(mpStr), mnLength, nLevel, NULL, &rcI18n );    // UChar != sal_Unicode in MinGW
     471                 :            : 
     472                 :       3562 :         UBiDi* pLineBidi = pParaBidi;
     473                 :       3562 :         int nSubLength = mnEndCharPos - mnMinCharPos;
     474         [ +  + ]:       3562 :         if( nSubLength != mnLength )
     475                 :            :         {
     476         [ +  - ]:       1466 :             pLineBidi = ubidi_openSized( nSubLength, 0, &rcI18n );
     477         [ +  - ]:       1466 :             ubidi_setLine( pParaBidi, mnMinCharPos, mnEndCharPos, pLineBidi, &rcI18n );
     478                 :            :         }
     479                 :            : 
     480                 :            :         // run BiDi algorithm
     481         [ +  - ]:       3562 :         const int nRunCount = ubidi_countRuns( pLineBidi, &rcI18n );
     482                 :            :         //maRuns.resize( 2 * nRunCount );
     483         [ +  + ]:       7142 :         for( int i = 0; i < nRunCount; ++i )
     484                 :            :         {
     485                 :            :             int32_t nMinPos, nLength;
     486         [ +  - ]:       3580 :             const UBiDiDirection nDir = ubidi_getVisualRun( pLineBidi, i, &nMinPos, &nLength );
     487                 :       3580 :             const int nPos0 = nMinPos + mnMinCharPos;
     488                 :       3580 :             const int nPos1 = nPos0 + nLength;
     489                 :            : 
     490                 :       3580 :             const bool bRTL = (nDir == UBIDI_RTL);
     491         [ +  - ]:       3580 :             AddRun( nPos0, nPos1, bRTL );
     492                 :            :         }
     493                 :            : 
     494                 :            :         // cleanup BiDi engine
     495         [ +  + ]:       3562 :         if( pLineBidi != pParaBidi )
     496         [ +  - ]:       1466 :             ubidi_close( pLineBidi );
     497         [ +  - ]:       3562 :         ubidi_close( pParaBidi );
     498                 :            :     }
     499                 :            : 
     500                 :            :     // prepare calls to GetNextPos/GetNextRun
     501                 :     981170 :     maRuns.ResetPos();
     502                 :            : }
     503                 :            : 
     504                 :            : // -----------------------------------------------------------------------
     505                 :            : 
     506                 :            : // add a run after splitting it up to get rid of control chars
     507                 :     981188 : void ImplLayoutArgs::AddRun( int nCharPos0, int nCharPos1, bool bRTL )
     508                 :            : {
     509                 :            :     DBG_ASSERT( nCharPos0 <= nCharPos1, "ImplLayoutArgs::AddRun() nCharPos0>=nCharPos1" );
     510                 :            : 
     511                 :            :     // remove control characters from runs by splitting them up
     512         [ +  + ]:     981188 :     if( !bRTL )
     513                 :            :     {
     514         [ +  + ]:   23370151 :         for( int i = nCharPos0; i < nCharPos1; ++i )
     515         [ +  + ]:   22389235 :             if( IsControlChar( mpStr[i] ) )
     516                 :            :             {
     517                 :            :                 // add run until control char
     518                 :        428 :                 maRuns.AddRun( nCharPos0, i, bRTL );
     519                 :        428 :                 nCharPos0 = i + 1;
     520                 :            :             }
     521                 :            :     }
     522                 :            :     else
     523                 :            :     {
     524         [ +  + ]:        822 :         for( int i = nCharPos1; --i >= nCharPos0; )
     525         [ +  + ]:        550 :             if( IsControlChar( mpStr[i] ) )
     526                 :            :             {
     527                 :            :                 // add run until control char
     528                 :        116 :                 maRuns.AddRun( i+1, nCharPos1, bRTL );
     529                 :        116 :                 nCharPos1 = i;
     530                 :            :             }
     531                 :            :     }
     532                 :            : 
     533                 :            :     // add remainder of run
     534                 :     981188 :     maRuns.AddRun( nCharPos0, nCharPos1, bRTL );
     535                 :     981188 : }
     536                 :            : 
     537                 :            : // -----------------------------------------------------------------------
     538                 :            : 
     539                 :      18714 : bool ImplLayoutArgs::PrepareFallback()
     540                 :            : {
     541                 :            :     // short circuit if no fallback is needed
     542         [ +  + ]:      18714 :     if( maReruns.IsEmpty() )
     543                 :            :     {
     544                 :       9357 :         maRuns.Clear();
     545                 :       9357 :         return false;
     546                 :            :     }
     547                 :            : 
     548                 :            :     // convert the fallback requests to layout requests
     549                 :            :     bool bRTL;
     550                 :            :     int nMin, nEnd;
     551                 :            : 
     552                 :            :     // get the individual fallback requests
     553                 :            :     typedef std::vector<int> IntVector;
     554         [ +  - ]:       9357 :     IntVector aPosVector;
     555         [ +  - ]:       9357 :     aPosVector.reserve( mnLength );
     556                 :       9357 :     maReruns.ResetPos();
     557 [ +  - ][ +  + ]:      18714 :     for(; maReruns.GetRun( &nMin, &nEnd, &bRTL ); maReruns.NextRun() )
     558         [ +  + ]:      19011 :         for( int i = nMin; i < nEnd; ++i )
     559         [ +  - ]:       9654 :             aPosVector.push_back( i );
     560                 :       9357 :     maReruns.Clear();
     561                 :            : 
     562                 :            :     // sort the individual fallback requests
     563         [ +  - ]:       9357 :     std::sort( aPosVector.begin(), aPosVector.end() );
     564                 :            : 
     565                 :            :     // adjust fallback runs to have the same order and limits of the original runs
     566         [ +  - ]:       9357 :     ImplLayoutRuns aNewRuns;
     567                 :       9357 :     maRuns.ResetPos();
     568 [ +  - ][ +  + ]:      18714 :     for(; maRuns.GetRun( &nMin, &nEnd, &bRTL ); maRuns.NextRun() )
     569                 :            :     {
     570         [ +  - ]:       9357 :         if( !bRTL) {
     571 [ +  - ][ +  - ]:       9357 :             IntVector::const_iterator it = std::lower_bound( aPosVector.begin(), aPosVector.end(), nMin );
     572 [ +  - ][ +  - ]:      19011 :             for(; (it != aPosVector.end()) && (*it < nEnd); ++it )
         [ +  + ][ +  - ]
         [ +  - ][ +  - ]
         [ +  + ][ #  # ]
     573 [ +  - ][ +  - ]:       9654 :                 aNewRuns.AddPos( *it, bRTL );
     574                 :            :         } else {
     575 [ #  # ][ #  # ]:          0 :             IntVector::const_iterator it = std::upper_bound( aPosVector.begin(), aPosVector.end(), nEnd );
     576 [ #  # ][ #  # ]:          0 :             while( (it != aPosVector.begin()) && (*--it >= nMin) )
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     577 [ #  # ][ #  # ]:          0 :                 aNewRuns.AddPos( *it, bRTL );
     578                 :            :         }
     579                 :            :     }
     580                 :            : 
     581         [ +  - ]:       9357 :     maRuns = aNewRuns;  // TODO: use vector<>::swap()
     582                 :       9357 :     maRuns.ResetPos();
     583                 :      18714 :     return true;
     584                 :            : }
     585                 :            : 
     586                 :            : // -----------------------------------------------------------------------
     587                 :            : 
     588                 :    1954693 : bool ImplLayoutArgs::GetNextRun( int* nMinRunPos, int* nEndRunPos, bool* bRTL )
     589                 :            : {
     590                 :    1954693 :     bool bValid = maRuns.GetRun( nMinRunPos, nEndRunPos, bRTL );
     591                 :    1954693 :     maRuns.NextRun();
     592                 :    1954693 :     return bValid;
     593                 :            : }
     594                 :            : 
     595                 :            : // =======================================================================
     596                 :            : 
     597                 :    1003172 : SalLayout::SalLayout()
     598                 :            : :   mnMinCharPos( -1 ),
     599                 :            :     mnEndCharPos( -1 ),
     600                 :            :     mnLayoutFlags( 0 ),
     601                 :            :     mnUnitsPerPixel( 1 ),
     602                 :            :     mnOrientation( 0 ),
     603                 :            :     mnRefCount( 1 ),
     604                 :    1003172 :     maDrawOffset( 0, 0 )
     605                 :    1003172 : {}
     606                 :            : 
     607                 :            : // -----------------------------------------------------------------------
     608                 :            : 
     609                 :    1003172 : SalLayout::~SalLayout()
     610         [ -  + ]:    1003172 : {}
     611                 :            : 
     612                 :            : // -----------------------------------------------------------------------
     613                 :            : 
     614                 :    1009766 : void SalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
     615                 :            : {
     616                 :    1009766 :     mnMinCharPos  = rArgs.mnMinCharPos;
     617                 :    1009766 :     mnEndCharPos  = rArgs.mnEndCharPos;
     618                 :    1009766 :     mnLayoutFlags = rArgs.mnFlags;
     619                 :    1009766 :     mnOrientation = rArgs.mnOrientation;
     620                 :    1009766 : }
     621                 :            : 
     622                 :            : // -----------------------------------------------------------------------
     623                 :            : 
     624                 :    1003172 : void SalLayout::Release() const
     625                 :            : {
     626                 :            :     // TODO: protect when multiple threads can access this
     627         [ -  + ]:    1003172 :     if( --mnRefCount > 0 )
     628                 :    1003172 :         return;
     629                 :            :     // const_cast because some compilers violate ANSI C++ spec
     630         [ +  - ]:    1003172 :     delete const_cast<SalLayout*>(this);
     631                 :            : }
     632                 :            : 
     633                 :            : // -----------------------------------------------------------------------
     634                 :            : 
     635                 :    2486867 : Point SalLayout::GetDrawPosition( const Point& rRelative ) const
     636                 :            : {
     637                 :    2486867 :     Point aPos = maDrawBase;
     638                 :    2486867 :     Point aOfs = rRelative + maDrawOffset;
     639                 :            : 
     640         [ +  + ]:    2486867 :     if( mnOrientation == 0 )
     641                 :    2276321 :         aPos += aOfs;
     642                 :            :     else
     643                 :            :     {
     644                 :            :         // cache trigonometric results
     645                 :            :         static int nOldOrientation = 0;
     646                 :            :         static double fCos = 1.0, fSin = 0.0;
     647         [ +  + ]:     210546 :         if( nOldOrientation != mnOrientation )
     648                 :            :         {
     649                 :        278 :             nOldOrientation = mnOrientation;
     650                 :        278 :             double fRad = mnOrientation * (M_PI / 1800.0);
     651                 :        278 :             fCos = cos( fRad );
     652                 :        278 :             fSin = sin( fRad );
     653                 :            :         }
     654                 :            : 
     655                 :     210546 :         double fX = aOfs.X();
     656                 :     210546 :         double fY = aOfs.Y();
     657                 :     210546 :         long nX = static_cast<long>( +fCos * fX + fSin * fY );
     658                 :     210546 :         long nY = static_cast<long>( +fCos * fY - fSin * fX );
     659                 :    2486867 :         aPos += Point( nX, nY );
     660                 :            :     }
     661                 :            : 
     662                 :    2486867 :     return aPos;
     663                 :            : }
     664                 :            : 
     665                 :            : // -----------------------------------------------------------------------
     666                 :            : 
     667                 :            : // returns asian kerning values in quarter of character width units
     668                 :            : // to enable automatic halfwidth substitution for fullwidth punctuation
     669                 :            : // return value is negative for l, positive for r, zero for neutral
     670                 :            : 
     671                 :            : // If the range doesn't match in 0x3000 and 0x30FB, please change
     672                 :            : // also ImplCalcKerning.
     673                 :            : 
     674                 :          0 : int SalLayout::CalcAsianKerning( sal_UCS4 c, bool bLeft, bool /*TODO:? bVertical*/ )
     675                 :            : {
     676                 :            :     // http://www.asahi-net.or.jp/~sd5a-ucd/freetexts/jis/x4051/1995/appendix.html
     677                 :            :     static signed char nTable[0x30] =
     678                 :            :     {
     679                 :            :          0, -2, -2,  0,   0,  0,  0,  0,  +2, -2, +2, -2,  +2, -2, +2, -2,
     680                 :            :         +2, -2,  0,  0,  +2, -2, +2, -2,   0,  0,  0,  0,   0, +2, -2, -2,
     681                 :            :          0,  0,  0,  0,   0,  0,  0,  0,   0,  0, -2, -2,  +2, +2, -2, -2
     682                 :            :     };
     683                 :            : 
     684                 :          0 :     int nResult = 0;
     685 [ #  # ][ #  # ]:          0 :     if( (c >= 0x3000) && (c < 0x3030) )
     686                 :          0 :         nResult = nTable[ c - 0x3000 ];
     687   [ #  #  #  # ]:          0 :     else switch( c )
     688                 :            :     {
     689                 :            :         case 0x30FB:
     690         [ #  # ]:          0 :             nResult = bLeft ? -1 : +1;      // 25% left/right/top/bottom
     691                 :          0 :             break;
     692                 :            :         case 0x2019: case 0x201D:
     693                 :            :         case 0xFF01: case 0xFF09: case 0xFF0C:
     694                 :            :         case 0xFF1A: case 0xFF1B:
     695                 :          0 :             nResult = -2;
     696                 :          0 :             break;
     697                 :            :         case 0x2018: case 0x201C:
     698                 :            :         case 0xFF08:
     699                 :          0 :             nResult = +2;
     700                 :          0 :             break;
     701                 :            :         default:
     702                 :          0 :             break;
     703                 :            :     }
     704                 :            : 
     705                 :          0 :     return nResult;
     706                 :            : }
     707                 :            : 
     708                 :            : // -----------------------------------------------------------------------
     709                 :            : 
     710                 :       1338 : bool SalLayout::GetOutline( SalGraphics& rSalGraphics,
     711                 :            :     ::basegfx::B2DPolyPolygonVector& rVector ) const
     712                 :            : {
     713                 :       1338 :     bool bAllOk = true;
     714                 :       1338 :     bool bOneOk = false;
     715                 :            : 
     716                 :       1338 :     Point aPos;
     717         [ +  - ]:       1338 :     ::basegfx::B2DPolyPolygon aGlyphOutline;
     718                 :       3739 :     for( int nStart = 0;;)
     719                 :            :     {
     720                 :            :         sal_GlyphId nLGlyph;
     721 [ +  - ][ +  + ]:       3739 :         if( !GetNextGlyphs( 1, &nLGlyph, aPos, nStart ) )
     722                 :            :             break;
     723                 :            : 
     724                 :            :         // get outline of individual glyph, ignoring "empty" glyphs
     725         [ +  - ]:       2401 :         bool bSuccess = rSalGraphics.GetGlyphOutline( nLGlyph, aGlyphOutline );
     726                 :       2401 :         bAllOk &= bSuccess;
     727                 :       2401 :         bOneOk |= bSuccess;
     728                 :            :         // only add non-empty outlines
     729 [ +  + ][ +  - ]:       2401 :         if( bSuccess && (aGlyphOutline.count() > 0) )
         [ +  + ][ +  + ]
     730                 :            :         {
     731 [ +  + ][ -  + ]:       2225 :             if( aPos.X() || aPos.Y() )
                 [ +  + ]
     732                 :            :             {
     733 [ +  - ][ +  - ]:       1163 :                 aGlyphOutline.transform(basegfx::tools::createTranslateB2DHomMatrix(aPos.X(), aPos.Y()));
                 [ +  - ]
     734                 :            :             }
     735                 :            : 
     736                 :            :             // insert outline at correct position
     737         [ +  - ]:       2225 :             rVector.push_back( aGlyphOutline );
     738                 :            :         }
     739                 :            :     }
     740                 :            : 
     741 [ +  + ][ +  + ]:       1338 :     return (bAllOk && bOneOk);
                 [ +  - ]
     742                 :            : }
     743                 :            : 
     744                 :            : // -----------------------------------------------------------------------
     745                 :            : 
     746                 :     127528 : bool SalLayout::GetBoundRect( SalGraphics& rSalGraphics, Rectangle& rRect ) const
     747                 :            : {
     748                 :     127528 :     bool bRet = false;
     749                 :     127528 :     rRect.SetEmpty();
     750                 :            : 
     751                 :     127528 :     Point aPos;
     752         [ +  - ]:     127528 :     Rectangle aRectangle;
     753                 :     401770 :     for( int nStart = 0;;)
     754                 :            :     {
     755                 :            :         sal_GlyphId nLGlyph;
     756 [ +  - ][ +  + ]:     401770 :         if( !GetNextGlyphs( 1, &nLGlyph, aPos, nStart ) )
     757                 :            :             break;
     758                 :            : 
     759                 :            :         // get bounding rectangle of individual glyph
     760 [ +  - ][ +  - ]:     274242 :         if( rSalGraphics.GetGlyphBoundRect( nLGlyph, aRectangle ) )
     761                 :            :         {
     762                 :            :             // merge rectangle
     763         [ +  - ]:     274242 :             aRectangle += aPos;
     764 [ +  - ][ +  + ]:     274242 :             if (rRect.IsEmpty())
     765                 :     125074 :                 rRect = aRectangle;
     766                 :            :             else
     767         [ +  - ]:     149168 :                 rRect.Union(aRectangle);
     768                 :     274242 :             bRet = true;
     769                 :            :         }
     770                 :            :     }
     771                 :            : 
     772                 :     127528 :     return bRet;
     773                 :            : }
     774                 :            : 
     775                 :            : // -----------------------------------------------------------------------
     776                 :            : 
     777                 :     109886 : bool SalLayout::IsSpacingGlyph( sal_GlyphId nGlyph ) const
     778                 :            : {
     779                 :     109886 :     bool bRet = false;
     780         [ -  + ]:     109886 :     if( nGlyph & GF_ISCHAR )
     781                 :            :     {
     782                 :          0 :         long nChar = nGlyph & GF_IDXMASK;
     783                 :            :         bRet = (nChar <= 0x0020)                    // blank
     784                 :            :             //|| (nChar == 0x00A0)                  // non breaking space
     785                 :            :             || (nChar >= 0x2000 && nChar <= 0x200F) // whitespace
     786 [ #  # ][ #  # ]:          0 :             || (nChar == 0x3000);                   // ideographic space
         [ #  # ][ #  # ]
     787                 :            :     }
     788                 :            :     else
     789                 :     109886 :         bRet = ((nGlyph & GF_IDXMASK) == 3);
     790                 :     109886 :     return bRet;
     791                 :            : }
     792                 :            : 
     793                 :            : // -----------------------------------------------------------------------
     794                 :            : 
     795                 :          0 : const PhysicalFontFace* SalLayout::GetFallbackFontData( sal_GlyphId /*nGlyphId*/ ) const
     796                 :            : {
     797                 :          0 :     return NULL;
     798                 :            : }
     799                 :            : 
     800                 :            : // =======================================================================
     801                 :            : 
     802         [ +  - ]:     993815 : GenericSalLayout::GenericSalLayout()
     803                 :     993815 : {}
     804                 :            : 
     805                 :            : // -----------------------------------------------------------------------
     806                 :            : 
     807                 :     993815 : GenericSalLayout::~GenericSalLayout()
     808         [ -  + ]:     993815 : {}
     809                 :            : 
     810                 :            : // -----------------------------------------------------------------------
     811                 :            : 
     812                 :   22395212 : void GenericSalLayout::AppendGlyph( const GlyphItem& rGlyphItem )
     813                 :            : {
     814                 :   22395212 :     m_GlyphItems.push_back(rGlyphItem);
     815                 :   22395212 : }
     816                 :            : 
     817                 :            : // -----------------------------------------------------------------------
     818                 :            : 
     819                 :     324463 : bool GenericSalLayout::GetCharWidths( sal_Int32* pCharWidths ) const
     820                 :            : {
     821                 :            :     // initialize character extents buffer
     822                 :     324463 :     int nCharCount = mnEndCharPos - mnMinCharPos;
     823         [ +  + ]:   15029882 :     for( int n = 0; n < nCharCount; ++n )
     824                 :   14705419 :         pCharWidths[n] = 0;
     825                 :            : 
     826                 :            :     // determine cluster extents
     827 [ +  - ][ +  + ]:   15029086 :     for( GlyphVector::const_iterator pG = m_GlyphItems.begin(), end = m_GlyphItems.end(); pG != end ; ++pG)
     828                 :            :     {
     829                 :            :         // use cluster start to get char index
     830         [ -  + ]:   14704623 :         if( !pG->IsClusterStart() )
     831                 :          0 :             continue;
     832                 :            : 
     833                 :   14704623 :         int n = pG->mnCharPos;
     834         [ -  + ]:   14704623 :         if( n >= mnEndCharPos )
     835                 :          0 :             continue;
     836                 :   14704623 :         n -= mnMinCharPos;
     837         [ -  + ]:   14704623 :         if( n < 0 )
     838                 :          0 :             continue;
     839                 :            : 
     840                 :            :         // left glyph in cluster defines default extent
     841                 :   14704623 :         long nXPosMin = pG->maLinearPos.X();
     842                 :   14704623 :         long nXPosMax = nXPosMin + pG->mnNewWidth;
     843                 :            : 
     844                 :            :         // calculate right x-position for this glyph cluster
     845                 :            :         // break if no more glyphs in layout
     846                 :            :         // break at next glyph cluster start
     847 [ +  - ][ +  - ]:   14704623 :         while( (pG+1 != end) && !pG[1].IsClusterStart() )
         [ +  + ][ -  + ]
         [ +  + ][ +  - ]
         [ +  - ][ -  +  
          #  #  #  #  #  
                      # ]
     848                 :            :         {
     849                 :            :             // advance to next glyph in cluster
     850                 :          0 :             ++pG;
     851                 :            : 
     852         [ #  # ]:          0 :             if( pG->IsDiacritic() )
     853                 :          0 :                 continue; // ignore diacritics
     854                 :            :             // get leftmost x-extent of this glyph
     855                 :          0 :             long nXPos = pG->maLinearPos.X();
     856         [ #  # ]:          0 :             if( nXPosMin > nXPos )
     857                 :          0 :                 nXPosMin = nXPos;
     858                 :            : 
     859                 :            :             // get rightmost x-extent of this glyph
     860                 :          0 :             nXPos += pG->mnNewWidth;
     861         [ #  # ]:          0 :             if( nXPosMax < nXPos )
     862                 :          0 :                 nXPosMax = nXPos;
     863                 :            :         }
     864                 :            : 
     865                 :            :         // when the current cluster overlaps with the next one assume
     866                 :            :         // rightmost cluster edge is the leftmost edge of next cluster
     867                 :            :         // for clusters that do not have x-sorted glyphs
     868                 :            :         // TODO: avoid recalculation of left bound in next cluster iteration
     869 [ +  - ][ +  + ]:   14704623 :         for( GlyphVector::const_iterator pN = pG; ++pN != end; )
     870                 :            :         {
     871         [ +  - ]:   14380478 :             if( pN->IsClusterStart() )
     872                 :   14380478 :                 break;
     873         [ #  # ]:          0 :             if( pN->IsDiacritic() )
     874                 :          0 :                 continue;   // ignore diacritics
     875         [ #  # ]:          0 :             if( nXPosMax > pN->maLinearPos.X() )
     876                 :          0 :                 nXPosMax = pN->maLinearPos.X();
     877                 :            :         }
     878         [ -  + ]:   14704623 :         if( nXPosMax < nXPosMin )
     879                 :          0 :             nXPosMin = nXPosMax = 0;
     880                 :            : 
     881                 :            :         // character width is sum of glyph cluster widths
     882                 :   14704623 :         pCharWidths[n] += nXPosMax - nXPosMin;
     883                 :            :     }
     884                 :            : 
     885                 :            :     // TODO: distribute the cluster width proportionally to the characters
     886                 :            :     // clusters (e.g. ligatures) correspond to more than one char index,
     887                 :            :     // so some character widths are still uninitialized. This is solved
     888                 :            :     // by setting the first charwidth of the cluster to the cluster width
     889                 :            : 
     890                 :     324463 :     return true;
     891                 :            : }
     892                 :            : 
     893                 :            : // -----------------------------------------------------------------------
     894                 :            : 
     895                 :     631249 : long GenericSalLayout::FillDXArray( sal_Int32* pCharWidths ) const
     896                 :            : {
     897         [ +  + ]:     631249 :     if( pCharWidths )
     898         [ -  + ]:     268106 :         if( !GetCharWidths( pCharWidths ) )
     899                 :          0 :             return 0;
     900                 :            : 
     901                 :     631249 :     long nWidth = GetTextWidth();
     902                 :     631249 :     return nWidth;
     903                 :            : }
     904                 :            : 
     905                 :            : // -----------------------------------------------------------------------
     906                 :            : 
     907                 :            : // the text width is the maximum logical extent of all glyphs
     908                 :     678080 : long GenericSalLayout::GetTextWidth() const
     909                 :            : {
     910         [ +  + ]:     678080 :     if( m_GlyphItems.empty() )
     911                 :       6459 :         return 0;
     912                 :            : 
     913                 :            :     // initialize the extent
     914                 :     671621 :     long nMinPos = 0;
     915                 :     671621 :     long nMaxPos = 0;
     916                 :            : 
     917 [ +  - ][ +  + ]:   10268541 :     for( GlyphVector::const_iterator pG = m_GlyphItems.begin(), end = m_GlyphItems.end(); pG != end ; ++pG )
     918                 :            :     {
     919                 :            :         // update the text extent with the glyph extent
     920                 :    9596920 :         long nXPos = pG->maLinearPos.X();
     921         [ -  + ]:    9596920 :         if( nMinPos > nXPos )
     922                 :          0 :             nMinPos = nXPos;
     923                 :    9596920 :         nXPos += pG->mnNewWidth;
     924         [ +  + ]:    9596920 :         if( nMaxPos < nXPos )
     925                 :    9595211 :             nMaxPos = nXPos;
     926                 :            :     }
     927                 :            : 
     928                 :     671621 :     long nWidth = nMaxPos - nMinPos;
     929                 :     678080 :     return nWidth;
     930                 :            : }
     931                 :            : 
     932                 :            : // -----------------------------------------------------------------------
     933                 :            : 
     934                 :     999779 : void GenericSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
     935                 :            : {
     936                 :     999779 :     SalLayout::AdjustLayout( rArgs );
     937                 :            : 
     938         [ +  + ]:     999779 :     if( rArgs.mpDXArray )
     939                 :      48457 :         ApplyDXArray( rArgs );
     940         [ +  + ]:     951322 :     else if( rArgs.mnLayoutWidth )
     941                 :       3041 :         Justify( rArgs.mnLayoutWidth );
     942                 :     999779 : }
     943                 :            : 
     944                 :            : // -----------------------------------------------------------------------
     945                 :            : 
     946                 :      48457 : void GenericSalLayout::ApplyDXArray( ImplLayoutArgs& rArgs )
     947                 :            : {
     948         [ +  - ]:      48457 :     if( m_GlyphItems.empty())
     949                 :            :         return;
     950                 :            : 
     951                 :            :     // determine cluster boundaries and x base offset
     952                 :      48457 :     const int nCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
     953                 :      48457 :     int* pLogCluster = (int*)alloca( nCharCount * sizeof(int) );
     954                 :            :     size_t i;
     955                 :            :     int n,p;
     956                 :      48457 :     long nBasePointX = -1;
     957         [ +  + ]:      48457 :     if( mnLayoutFlags & SAL_LAYOUT_FOR_FALLBACK )
     958                 :        108 :         nBasePointX = 0;
     959         [ +  + ]:    1594514 :     for(p = 0; p < nCharCount; ++p )
     960                 :    1546057 :         pLogCluster[ p ] = -1;
     961                 :            : 
     962         [ +  + ]:    1594436 :     for( i = 0; i < m_GlyphItems.size(); ++i)
     963                 :            :     {
     964                 :    1545979 :         n = m_GlyphItems[i].mnCharPos - rArgs.mnMinCharPos;
     965 [ -  + ][ +  - ]:    1545979 :         if( (n < 0) || (nCharCount <= n) )
     966                 :          0 :             continue;
     967         [ +  - ]:    1545979 :         if( pLogCluster[ n ] < 0 )
     968                 :    1545979 :             pLogCluster[ n ] = i;
     969         [ +  + ]:    1545979 :         if( nBasePointX < 0 )
     970                 :      48349 :             nBasePointX = m_GlyphItems[i].maLinearPos.X();
     971                 :            :     }
     972                 :            :     // retarget unresolved pLogCluster[n] to a glyph inside the cluster
     973                 :            :     // TODO: better do it while the deleted-glyph markers are still there
     974         [ +  - ]:      48457 :     for( n = 0; n < nCharCount; ++n )
     975         [ +  - ]:      48457 :         if( (p = pLogCluster[0]) >= 0 )
     976                 :      48457 :             break;
     977         [ +  - ]:      48457 :     if( n >= nCharCount )
     978                 :            :         return;
     979         [ +  + ]:    1594514 :     for( n = 0; n < nCharCount; ++n )
     980                 :            :     {
     981         [ +  + ]:    1546057 :         if( pLogCluster[ n ] < 0 )
     982                 :         78 :             pLogCluster[ n ] = p;
     983                 :            :         else
     984                 :    1545979 :             p = pLogCluster[ n ];
     985                 :            :     }
     986                 :            : 
     987                 :            :     // calculate adjusted cluster widths
     988                 :      48457 :     sal_Int32* pNewGlyphWidths = (sal_Int32*)alloca( m_GlyphItems.size() * sizeof(long) );
     989         [ +  + ]:    1594436 :     for( i = 0; i < m_GlyphItems.size(); ++i )
     990                 :    1545979 :         pNewGlyphWidths[ i ] = 0;
     991                 :            : 
     992                 :            :     bool bRTL;
     993 [ +  - ][ +  + ]:    1594514 :     for( int nCharPos = p = -1; rArgs.GetNextPos( &nCharPos, &bRTL ); )
     994                 :            :     {
     995                 :    1546057 :         n = nCharPos - rArgs.mnMinCharPos;
     996 [ +  - ][ -  + ]:    1546057 :         if( (n < 0) || (nCharCount <= n) )  continue;
     997                 :            : 
     998         [ +  - ]:    1546057 :         if( pLogCluster[ n ] >= 0 )
     999                 :    1546057 :             p = pLogCluster[ n ];
    1000         [ +  - ]:    1546057 :         if( p >= 0 )
    1001                 :            :         {
    1002                 :    1546057 :             long nDelta = rArgs.mpDXArray[ n ] ;
    1003         [ +  + ]:    1546057 :             if( n > 0 )
    1004                 :    1497600 :                 nDelta -= rArgs.mpDXArray[ n-1 ];
    1005                 :    1546057 :             pNewGlyphWidths[ p ] += nDelta * mnUnitsPerPixel;
    1006                 :            :         }
    1007                 :            :     }
    1008                 :            : 
    1009                 :            :     // move cluster positions using the adjusted widths
    1010                 :      48457 :     long nDelta = 0;
    1011                 :      48457 :     long nNewPos = 0;
    1012         [ +  + ]:    1594436 :     for( i = 0; i < m_GlyphItems.size(); ++i)
    1013                 :            :     {
    1014         [ +  - ]:    1545979 :         if( m_GlyphItems[i].IsClusterStart() )
    1015                 :            :         {
    1016                 :            :             // calculate original and adjusted cluster width
    1017                 :    1545979 :             int nOldClusterWidth = m_GlyphItems[i].mnNewWidth;
    1018                 :    1545979 :             int nNewClusterWidth = pNewGlyphWidths[i];
    1019                 :            :             size_t j;
    1020         [ +  + ]:    1545979 :             for( j = i; ++j < m_GlyphItems.size(); )
    1021                 :            :             {
    1022         [ +  - ]:    1497522 :                 if( m_GlyphItems[j].IsClusterStart() )
    1023                 :    1497522 :                     break;
    1024         [ #  # ]:          0 :                 if( !m_GlyphItems[j].IsDiacritic() ) // #i99367# ignore diacritics
    1025                 :          0 :                     nOldClusterWidth += m_GlyphItems[j].mnNewWidth;
    1026                 :          0 :                 nNewClusterWidth += pNewGlyphWidths[j];
    1027                 :            :             }
    1028                 :    1545979 :             const int nDiff = nNewClusterWidth - nOldClusterWidth;
    1029                 :            : 
    1030                 :            :             // adjust cluster glyph widths and positions
    1031                 :    1545979 :             nDelta = nBasePointX + (nNewPos - m_GlyphItems[i].maLinearPos.X());
    1032         [ +  - ]:    1545979 :             if( !m_GlyphItems[i].IsRTLGlyph() )
    1033                 :            :             {
    1034                 :            :                 // for LTR case extend rightmost glyph in cluster
    1035                 :    1545979 :                 m_GlyphItems[j - 1].mnNewWidth += nDiff;
    1036                 :            :             }
    1037                 :            :             else
    1038                 :            :             {
    1039                 :            :                 // right align cluster in new space for RTL case
    1040                 :          0 :                 m_GlyphItems[i].mnNewWidth += nDiff;
    1041                 :          0 :                 nDelta += nDiff;
    1042                 :            :             }
    1043                 :            : 
    1044                 :    1545979 :             nNewPos += nNewClusterWidth;
    1045                 :            :         }
    1046                 :            : 
    1047                 :    1545979 :         m_GlyphItems[i].maLinearPos.X() += nDelta;
    1048                 :            :     }
    1049                 :            : }
    1050                 :            : 
    1051                 :            : // -----------------------------------------------------------------------
    1052                 :            : 
    1053                 :       3041 : void GenericSalLayout::Justify( long nNewWidth )
    1054                 :            : {
    1055                 :       3041 :     nNewWidth *= mnUnitsPerPixel;
    1056         [ +  - ]:       3041 :     int nOldWidth = GetTextWidth();
    1057 [ +  - ][ +  + ]:       3041 :     if( !nOldWidth || nNewWidth==nOldWidth )
    1058                 :            :         return;
    1059                 :            : 
    1060         [ +  - ]:        625 :     if(m_GlyphItems.empty())
    1061                 :            :     {
    1062                 :            :         return;
    1063                 :            :     }
    1064                 :            :     // find rightmost glyph, it won't get stretched
    1065                 :        625 :     GlyphVector::iterator pGRight = m_GlyphItems.begin();
    1066                 :        625 :     pGRight += m_GlyphItems.size() - 1;
    1067                 :        625 :     GlyphVector::iterator pG;
    1068                 :            :     // count stretchable glyphs
    1069                 :        625 :     int nStretchable = 0;
    1070                 :        625 :     int nMaxGlyphWidth = 0;
    1071 [ +  - ][ +  + ]:       1398 :     for(pG = m_GlyphItems.begin(); pG != pGRight; ++pG)
    1072                 :            :     {
    1073         [ +  - ]:        773 :         if( !pG->IsDiacritic() )
    1074                 :        773 :             ++nStretchable;
    1075         [ +  + ]:        773 :         if( nMaxGlyphWidth < pG->mnOrigWidth )
    1076                 :        148 :             nMaxGlyphWidth = pG->mnOrigWidth;
    1077                 :            :     }
    1078                 :            : 
    1079                 :            :     // move rightmost glyph to requested position
    1080                 :        625 :     nOldWidth -= pGRight->mnOrigWidth;
    1081         [ +  + ]:        625 :     if( nOldWidth <= 0 )
    1082                 :            :         return;
    1083         [ -  + ]:        148 :     if( nNewWidth < nMaxGlyphWidth)
    1084                 :          0 :         nNewWidth = nMaxGlyphWidth;
    1085                 :        148 :     nNewWidth -= pGRight->mnOrigWidth;
    1086                 :        148 :     pGRight->maLinearPos.X() = maBasePoint.X() + nNewWidth;
    1087                 :            : 
    1088                 :            :     // justify glyph widths and positions
    1089                 :        148 :     int nDiffWidth = nNewWidth - nOldWidth;
    1090         [ +  + ]:        148 :     if( nDiffWidth >= 0) // expanded case
    1091                 :            :     {
    1092                 :            :         // expand width by distributing space between glyphs evenly
    1093                 :         94 :         int nDeltaSum = 0;
    1094 [ +  - ][ +  + ]:        786 :         for( pG = m_GlyphItems.begin(); pG != pGRight; ++pG )
    1095                 :            :         {
    1096                 :            :             // move glyph to justified position
    1097                 :        692 :             pG->maLinearPos.X() += nDeltaSum;
    1098                 :            : 
    1099                 :            :             // do not stretch non-stretchable glyphs
    1100 [ -  + ][ -  + ]:        692 :             if( pG->IsDiacritic() || (nStretchable <= 0) )
                 [ +  - ]
    1101                 :          0 :                 continue;
    1102                 :            : 
    1103                 :            :             // distribute extra space equally to stretchable glyphs
    1104                 :        692 :             int nDeltaWidth = nDiffWidth / nStretchable--;
    1105                 :        692 :             nDiffWidth     -= nDeltaWidth;
    1106                 :        692 :             pG->mnNewWidth += nDeltaWidth;
    1107                 :        692 :             nDeltaSum      += nDeltaWidth;
    1108                 :            :         }
    1109                 :            :     }
    1110                 :            :     else // condensed case
    1111                 :            :     {
    1112                 :            :         // squeeze width by moving glyphs proportionally
    1113                 :         54 :         double fSqueeze = (double)nNewWidth / nOldWidth;
    1114         [ +  - ]:         54 :         if(m_GlyphItems.size() > 1)
    1115                 :            :         {
    1116 [ +  - ][ +  + ]:         81 :             for( pG = m_GlyphItems.begin(); ++pG != pGRight;)
    1117                 :            :             {
    1118                 :         27 :                 int nX = pG->maLinearPos.X() - maBasePoint.X();
    1119                 :         27 :                 nX = (int)(nX * fSqueeze);
    1120                 :         27 :                 pG->maLinearPos.X() = nX + maBasePoint.X();
    1121                 :            :             }
    1122                 :            :         }
    1123                 :            :         // adjust glyph widths to new positions
    1124 [ +  - ][ +  + ]:       3122 :         for( pG = m_GlyphItems.begin(); pG != pGRight; ++pG )
    1125                 :         81 :             pG->mnNewWidth = pG[1].maLinearPos.X() - pG[0].maLinearPos.X();
    1126                 :            :     }
    1127                 :            : }
    1128                 :            : 
    1129                 :            : // -----------------------------------------------------------------------
    1130                 :            : 
    1131                 :          0 : void GenericSalLayout::ApplyAsianKerning( const sal_Unicode* pStr, int nLength )
    1132                 :            : {
    1133                 :          0 :     long nOffset = 0;
    1134                 :            : 
    1135 [ #  # ][ #  # ]:          0 :     for( GlyphVector::iterator pG = m_GlyphItems.begin(), pGEnd = m_GlyphItems.end(); pG != pGEnd; ++pG )
    1136                 :            :     {
    1137                 :          0 :         const int n = pG->mnCharPos;
    1138         [ #  # ]:          0 :         if( n < nLength - 1)
    1139                 :            :         {
    1140                 :            :             // ignore code ranges that are not affected by asian punctuation compression
    1141                 :          0 :             const sal_Unicode cHere = pStr[n];
    1142 [ #  # ][ #  # ]:          0 :             if( ((0x3000 != (cHere & 0xFF00)) && (0x2010 != (cHere & 0xFFF0))) || (0xFF00 != (cHere & 0xFF00)) )
                 [ #  # ]
    1143                 :          0 :                 continue;
    1144                 :          0 :             const sal_Unicode cNext = pStr[n+1];
    1145 [ #  # ][ #  # ]:          0 :             if( ((0x3000 != (cNext & 0xFF00)) && (0x2010 != (cNext & 0xFFF0))) || (0xFF00 != (cNext & 0xFF00)) )
                 [ #  # ]
    1146                 :          0 :                 continue;
    1147                 :            : 
    1148                 :            :             // calculate compression values
    1149                 :          0 :             const bool bVertical = false;
    1150         [ #  # ]:          0 :             long nKernFirst = +CalcAsianKerning( cHere, true, bVertical );
    1151         [ #  # ]:          0 :             long nKernNext  = -CalcAsianKerning( cNext, false, bVertical );
    1152                 :            : 
    1153                 :            :             // apply punctuation compression to logical glyph widths
    1154         [ #  # ]:          0 :             long nDelta = (nKernFirst < nKernNext) ? nKernFirst : nKernNext;
    1155 [ #  # ][ #  # ]:          0 :             if( nDelta<0 && nKernFirst!=0 && nKernNext!=0 )
                 [ #  # ]
    1156                 :            :             {
    1157                 :          0 :                 int nGlyphWidth = pG->mnOrigWidth;
    1158                 :          0 :                 nDelta = (nDelta * nGlyphWidth + 2) / 4;
    1159 [ #  # ][ #  # ]:          0 :                 if( pG+1 == pGEnd )
                 [ #  # ]
    1160                 :          0 :                     pG->mnNewWidth += nDelta;
    1161                 :          0 :                 nOffset += nDelta;
    1162                 :            :             }
    1163                 :            :         }
    1164                 :            : 
    1165                 :            :         // adjust the glyph positions to the new glyph widths
    1166 [ #  # ][ #  # ]:          0 :         if( pG+1 != pGEnd )
                 [ #  # ]
    1167                 :          0 :             pG->maLinearPos.X() += nOffset;
    1168                 :            :     }
    1169                 :          0 : }
    1170                 :            : 
    1171                 :            : // -----------------------------------------------------------------------
    1172                 :            : 
    1173                 :          0 : void GenericSalLayout::KashidaJustify( long nKashidaIndex, int nKashidaWidth )
    1174                 :            : {
    1175                 :            :     // TODO: reimplement method when container type for GlyphItems changes
    1176                 :            : 
    1177                 :            :     // skip if the kashida glyph in the font looks suspicious
    1178         [ #  # ]:          0 :     if( nKashidaWidth <= 0 )
    1179                 :          0 :         return;
    1180                 :            : 
    1181                 :            :     // calculate max number of needed kashidas
    1182                 :          0 :     int nKashidaCount = 0;
    1183 [ #  # ][ #  # ]:          0 :     for (GlyphVector::iterator pG = m_GlyphItems.begin();
    1184                 :          0 :             pG != m_GlyphItems.end(); ++pG)
    1185                 :            :     {
    1186                 :            :         // only inject kashidas in RTL contexts
    1187         [ #  # ]:          0 :         if( !pG->IsRTLGlyph() )
    1188                 :          0 :             continue;
    1189                 :            :         // no kashida-injection for blank justified expansion either
    1190 [ #  # ][ #  # ]:          0 :         if( IsSpacingGlyph( pG->mnGlyphIndex ) )
    1191                 :          0 :             continue;
    1192                 :            : 
    1193                 :            :         // calculate gap, ignore if too small
    1194                 :          0 :         int nGapWidth = pG->mnNewWidth - pG->mnOrigWidth;
    1195                 :            :         // worst case is one kashida even for mini-gaps
    1196         [ #  # ]:          0 :         if( 3 * nGapWidth < nKashidaWidth )
    1197                 :          0 :             continue;
    1198                 :            : 
    1199                 :          0 :         nKashidaCount = 0;
    1200                 :          0 :         Point aPos = pG->maLinearPos;
    1201                 :          0 :         aPos.X() -= nGapWidth; // cluster is already right aligned
    1202                 :          0 :         int const nCharPos = pG->mnCharPos;
    1203                 :          0 :         GlyphVector::iterator pG2 = pG;
    1204         [ #  # ]:          0 :         for(; nGapWidth > nKashidaWidth; nGapWidth -= nKashidaWidth, ++nKashidaCount )
    1205                 :            :         {
    1206                 :            :             pG2 = m_GlyphItems.insert(pG2, GlyphItem(nCharPos, nKashidaIndex, aPos,
    1207         [ #  # ]:          0 :                                                       GlyphItem::IS_IN_CLUSTER|GlyphItem::IS_RTL_GLYPH, nKashidaWidth ));
    1208                 :          0 :             ++pG2;
    1209                 :          0 :             aPos.X() += nKashidaWidth;
    1210                 :            :         }
    1211                 :            : 
    1212                 :            :         // fixup rightmost kashida for gap remainder
    1213         [ #  # ]:          0 :         if( nGapWidth > 0 )
    1214                 :            :         {
    1215                 :            :             pG2 = m_GlyphItems.insert(pG2, GlyphItem(nCharPos, nKashidaIndex, aPos,
    1216 [ #  # ][ #  # ]:          0 :                                                       GlyphItem::IS_IN_CLUSTER|GlyphItem::IS_RTL_GLYPH, nKashidaCount ? nGapWidth : nGapWidth/2 ));
    1217                 :          0 :             ++pG2;
    1218                 :          0 :             aPos.X() += nGapWidth;
    1219                 :            :         }
    1220                 :          0 :         pG = pG2;
    1221                 :            :     }
    1222                 :            : }
    1223                 :            : 
    1224                 :            : // -----------------------------------------------------------------------
    1225                 :            : 
    1226                 :      19933 : void GenericSalLayout::GetCaretPositions( int nMaxIndex, sal_Int32* pCaretXArray ) const
    1227                 :            : {
    1228                 :            :     // initialize result array
    1229                 :      19933 :     long nXPos = -1;
    1230                 :            :     int i;
    1231         [ +  + ]:     245781 :     for( i = 0; i < nMaxIndex; ++i )
    1232                 :     225848 :         pCaretXArray[ i ] = nXPos;
    1233                 :            : 
    1234                 :            :     // calculate caret positions using glyph array
    1235 [ +  - ][ +  + ]:     132732 :     for( GlyphVector::const_iterator pG = m_GlyphItems.begin(), pGEnd = m_GlyphItems.end(); pG != pGEnd; ++pG )
    1236                 :            :     {
    1237                 :     112799 :         nXPos = pG->maLinearPos.X();
    1238                 :     112799 :         long nXRight = nXPos + pG->mnOrigWidth;
    1239                 :     112799 :         int n = pG->mnCharPos;
    1240                 :     112799 :         int nCurrIdx = 2 * (n - mnMinCharPos);
    1241         [ +  + ]:     112799 :         if( !pG->IsRTLGlyph() )
    1242                 :            :         {
    1243                 :            :             // normal positions for LTR case
    1244                 :     112733 :             pCaretXArray[ nCurrIdx ]   = nXPos;
    1245                 :     112733 :             pCaretXArray[ nCurrIdx+1 ] = nXRight;
    1246                 :            :         }
    1247                 :            :         else
    1248                 :            :         {
    1249                 :            :             // reverse positions for RTL case
    1250                 :         66 :             pCaretXArray[ nCurrIdx ]   = nXRight;
    1251                 :         66 :             pCaretXArray[ nCurrIdx+1 ] = nXPos;
    1252                 :            :         }
    1253                 :            :     }
    1254                 :      19933 : }
    1255                 :            : 
    1256                 :            : // -----------------------------------------------------------------------
    1257                 :            : 
    1258                 :      56357 : int GenericSalLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
    1259                 :            : {
    1260                 :      56357 :     int nCharCapacity = mnEndCharPos - mnMinCharPos;
    1261                 :      56357 :     sal_Int32* pCharWidths = (sal_Int32*)alloca( nCharCapacity * sizeof(sal_Int32) );
    1262         [ -  + ]:      56357 :     if( !GetCharWidths( pCharWidths ) )
    1263                 :          0 :         return STRING_LEN;
    1264                 :            : 
    1265                 :      56357 :     long nWidth = 0;
    1266         [ +  + ]:    3083856 :     for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
    1267                 :            :     {
    1268                 :    3068400 :         nWidth += pCharWidths[ i - mnMinCharPos ] * nFactor;
    1269         [ +  + ]:    3068400 :         if( nWidth > nMaxWidth )
    1270                 :      40901 :             return i;
    1271                 :    3027499 :         nWidth += nCharExtra;
    1272                 :            :     }
    1273                 :            : 
    1274                 :      56357 :     return STRING_LEN;
    1275                 :            : }
    1276                 :            : 
    1277                 :            : // -----------------------------------------------------------------------
    1278                 :            : 
    1279                 :    2686218 : int GenericSalLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
    1280                 :            :     int& nStart, sal_Int32* pGlyphAdvAry, int* pCharPosAry ) const
    1281                 :            : {
    1282                 :    2686218 :     GlyphVector::const_iterator pG = m_GlyphItems.begin();
    1283                 :    2686218 :     GlyphVector::const_iterator pGEnd = m_GlyphItems.end();
    1284                 :    2686218 :     pG += nStart;
    1285                 :            : 
    1286                 :            :     // find next glyph in substring
    1287 [ +  - ][ +  + ]:    2686218 :     for(; pG != pGEnd; ++nStart, ++pG )
    1288                 :            :     {
    1289                 :    2354285 :         int n = pG->mnCharPos;
    1290 [ +  - ][ +  - ]:    2354285 :         if( (mnMinCharPos <= n) && (n < mnEndCharPos) )
    1291                 :    2354285 :             break;
    1292                 :            :     }
    1293                 :            : 
    1294                 :            :     // return zero if no more glyph found
    1295         [ +  + ]:    2686218 :     if( nStart >= (int)m_GlyphItems.size() )
    1296                 :     331933 :         return 0;
    1297                 :            : 
    1298                 :            :     // calculate absolute position in pixel units
    1299                 :    2354285 :     Point aRelativePos = pG->maLinearPos - maBasePoint;
    1300                 :            : 
    1301                 :            :     // find more glyphs which can be merged into one drawing instruction
    1302                 :    2354285 :     int nCount = 0;
    1303                 :    2354285 :     long nYPos = pG->maLinearPos.Y();
    1304                 :    2354285 :     long nOldFlags = pG->mnGlyphIndex;
    1305                 :          0 :     for(;;)
    1306                 :            :     {
    1307                 :            :         // update return data with glyph info
    1308                 :    2354285 :         ++nCount;
    1309                 :    2354285 :         *(pGlyphs++) = pG->mnGlyphIndex;
    1310         [ +  + ]:    2354285 :         if( pCharPosAry )
    1311                 :      19308 :             *(pCharPosAry++) = pG->mnCharPos;
    1312         [ +  + ]:    2354285 :         if( pGlyphAdvAry )
    1313                 :      58679 :             *pGlyphAdvAry = pG->mnNewWidth;
    1314                 :            : 
    1315                 :            :         // break at end of glyph list
    1316         [ +  + ]:    2354285 :         if( ++nStart >= (int)m_GlyphItems.size() )
    1317                 :     328692 :             break;
    1318                 :            :         // break when enough glyphs
    1319         [ +  - ]:    2025593 :         if( nCount >= nLen )
    1320                 :    2025593 :             break;
    1321                 :            : 
    1322                 :          0 :         long nGlyphAdvance = pG[1].maLinearPos.X() - pG->maLinearPos.X();
    1323         [ #  # ]:          0 :         if( pGlyphAdvAry )
    1324                 :            :         {
    1325                 :            :             // override default advance width with correct value
    1326                 :          0 :             *(pGlyphAdvAry++) = nGlyphAdvance;
    1327                 :            :         }
    1328                 :            :         else
    1329                 :            :         {
    1330                 :            :             // stop when next x-position is unexpected
    1331         [ #  # ]:          0 :             if( pG->mnOrigWidth != nGlyphAdvance )
    1332                 :          0 :                 break;
    1333                 :            :         }
    1334                 :            : 
    1335                 :            :         // advance to next glyph
    1336                 :          0 :         ++pG;
    1337                 :            : 
    1338                 :            :         // stop when next y-position is unexpected
    1339         [ #  # ]:          0 :         if( nYPos != pG->maLinearPos.Y() )
    1340                 :          0 :             break;
    1341                 :            : 
    1342                 :            :         // stop when no longer in string
    1343                 :          0 :         int n = pG->mnCharPos;
    1344 [ #  # ][ #  # ]:          0 :         if( (n < mnMinCharPos) || (mnEndCharPos <= n) )
    1345                 :          0 :             break;
    1346                 :            : 
    1347                 :            :         // stop when glyph flags change
    1348         [ #  # ]:          0 :         if( (nOldFlags ^ pG->mnGlyphIndex) & GF_FLAGMASK )
    1349                 :          0 :             break;
    1350                 :            : 
    1351                 :          0 :         nOldFlags = pG->mnGlyphIndex; // &GF_FLAGMASK not needed for test above
    1352                 :            :     }
    1353                 :            : 
    1354                 :    2354285 :     aRelativePos.X() /= mnUnitsPerPixel;
    1355                 :    2354285 :     aRelativePos.Y() /= mnUnitsPerPixel;
    1356         [ +  - ]:    2354285 :     rPos = GetDrawPosition( aRelativePos );
    1357                 :            : 
    1358                 :    2686218 :     return nCount;
    1359                 :            : }
    1360                 :            : 
    1361                 :            : // -----------------------------------------------------------------------
    1362                 :            : 
    1363                 :       9357 : void GenericSalLayout::MoveGlyph( int nStart, long nNewXPos )
    1364                 :            : {
    1365         [ +  - ]:       9357 :     if( nStart >= (int)m_GlyphItems.size() )
    1366                 :       9357 :         return;
    1367                 :            : 
    1368                 :       9357 :     GlyphVector::iterator pG = m_GlyphItems.begin();
    1369                 :       9357 :     pG += nStart;
    1370                 :            : 
    1371                 :            :     // the nNewXPos argument determines the new cell position
    1372                 :            :     // as RTL-glyphs are right justified in their cell
    1373                 :            :     // the cell position needs to be adjusted to the glyph position
    1374         [ -  + ]:       9357 :     if( pG->IsRTLGlyph() )
    1375                 :          0 :         nNewXPos += pG->mnNewWidth - pG->mnOrigWidth;
    1376                 :            :     // calculate the x-offset to the old position
    1377                 :       9357 :     long nXDelta = nNewXPos - pG->maLinearPos.X();
    1378                 :            :     // adjust all following glyph positions if needed
    1379         [ -  + ]:       9357 :     if( nXDelta != 0 )
    1380                 :            :     {
    1381 [ #  # ][ #  # ]:       9357 :         for( GlyphVector::iterator pGEnd = m_GlyphItems.end(); pG != pGEnd; ++pG )
    1382                 :            :         {
    1383                 :          0 :             pG->maLinearPos.X() += nXDelta;
    1384                 :            :         }
    1385                 :            :     }
    1386                 :            : }
    1387                 :            : 
    1388                 :            : // -----------------------------------------------------------------------
    1389                 :            : 
    1390                 :       9654 : void GenericSalLayout::DropGlyph( int nStart )
    1391                 :            : {
    1392         [ +  - ]:       9654 :     if( nStart >= (int)m_GlyphItems.size())
    1393                 :       9654 :         return;
    1394                 :            : 
    1395                 :       9654 :     GlyphVector::iterator pG = m_GlyphItems.begin();
    1396                 :       9654 :     pG += nStart;
    1397                 :       9654 :     pG->mnGlyphIndex = GF_DROPPED;
    1398                 :       9654 :     pG->mnCharPos = -1;
    1399                 :            : }
    1400                 :            : 
    1401                 :            : // -----------------------------------------------------------------------
    1402                 :            : 
    1403                 :      18714 : void GenericSalLayout::Simplify( bool bIsBase )
    1404                 :            : {
    1405         [ +  + ]:      18714 :     const sal_GlyphId nDropMarker = bIsBase ? GF_DROPPED : 0;
    1406                 :            : 
    1407                 :            :     // remove dropped glyphs inplace
    1408                 :      18714 :     size_t j = 0;
    1409         [ +  + ]:      38022 :     for(size_t i = 0; i < m_GlyphItems.size(); i++ )
    1410                 :            :     {
    1411         [ +  + ]:      19308 :         if( m_GlyphItems[i].mnGlyphIndex == nDropMarker )
    1412                 :       9654 :             continue;
    1413                 :            : 
    1414         [ -  + ]:       9654 :         if( i != j )
    1415                 :            :         {
    1416                 :          0 :             m_GlyphItems[j] = m_GlyphItems[i];
    1417                 :            :         }
    1418                 :       9654 :         j += 1;
    1419                 :            :     }
    1420 [ +  - ][ +  - ]:      18714 :     m_GlyphItems.erase(m_GlyphItems.begin() + j, m_GlyphItems.end());
    1421                 :      18714 : }
    1422                 :            : 
    1423                 :            : // -----------------------------------------------------------------------
    1424                 :            : 
    1425                 :            : // make sure GlyphItems are sorted left to right
    1426                 :     967999 : void GenericSalLayout::SortGlyphItems()
    1427                 :            : {
    1428                 :            :     // move cluster components behind their cluster start (especially for RTL)
    1429                 :            :     // using insertion sort because the glyph items are "almost sorted"
    1430                 :            : 
    1431 [ +  - ][ +  + ]:   23321895 :     for( GlyphVector::iterator pG = m_GlyphItems.begin(), pGEnd = m_GlyphItems.end(); pG != pGEnd; ++pG )
    1432                 :            :     {
    1433                 :            :         // find a cluster starting with a diacritic
    1434         [ +  + ]:   22353896 :         if( !pG->IsDiacritic() )
    1435                 :   22351319 :             continue;
    1436         [ +  + ]:       2577 :         if( !pG->IsClusterStart() )
    1437                 :        228 :             continue;
    1438 [ +  - ][ +  + ]:       2577 :         for( GlyphVector::iterator pBaseGlyph = pG; ++pBaseGlyph != pGEnd; )
    1439                 :            :         {
    1440                 :            :             // find the base glyph matching to the misplaced diacritic
    1441         [ -  + ]:        228 :             if( pBaseGlyph->IsClusterStart() )
    1442                 :          0 :                 break;
    1443         [ +  - ]:        228 :             if( pBaseGlyph->IsDiacritic() )
    1444                 :        228 :                 continue;
    1445                 :            : 
    1446                 :            :             // found the matching base glyph
    1447                 :            :             // => this base glyph becomes the new cluster start
    1448         [ #  # ]:          0 :             iter_swap(pG, pBaseGlyph);
    1449                 :            : 
    1450                 :            :             // update glyph flags of swapped glyphitems
    1451                 :          0 :             pG->mnFlags &= ~GlyphItem::IS_IN_CLUSTER;
    1452                 :          0 :             pBaseGlyph->mnFlags |= GlyphItem::IS_IN_CLUSTER;
    1453                 :            :             // prepare for checking next cluster
    1454                 :          0 :             pG = pBaseGlyph;
    1455                 :          0 :             break;
    1456                 :            :         }
    1457                 :            :     }
    1458                 :     967999 : }
    1459                 :            : 
    1460                 :            : // =======================================================================
    1461                 :            : 
    1462                 :       9357 : MultiSalLayout::MultiSalLayout( SalLayout& rBaseLayout, const PhysicalFontFace* pBaseFont )
    1463                 :            : :   SalLayout()
    1464                 :            : ,   mnLevel( 1 )
    1465 [ +  - ][ +  +  :     159069 : ,   mbInComplete( false )
             #  #  #  # ]
    1466                 :            : {
    1467                 :            :     //maFallbackRuns[0].Clear();
    1468                 :       9357 :     mpFallbackFonts[ 0 ] = pBaseFont;
    1469                 :       9357 :     mpLayouts[ 0 ]  = &rBaseLayout;
    1470                 :       9357 :     mnUnitsPerPixel = rBaseLayout.GetUnitsPerPixel();
    1471                 :       9357 : }
    1472                 :            : 
    1473                 :          0 : void MultiSalLayout::SetInComplete(bool bInComplete)
    1474                 :            : {
    1475                 :          0 :     mbInComplete = bInComplete;
    1476                 :          0 :     maFallbackRuns[mnLevel-1] = ImplLayoutRuns();
    1477                 :          0 : }
    1478                 :            : 
    1479                 :            : // -----------------------------------------------------------------------
    1480                 :            : 
    1481                 :     159069 : MultiSalLayout::~MultiSalLayout()
    1482                 :            : {
    1483         [ +  + ]:      28071 :     for( int i = 0; i < mnLevel; ++i )
    1484         [ +  - ]:      18714 :         mpLayouts[ i ]->Release();
    1485         [ +  - ]:     177783 : }
           [ +  +  -  + ]
           [ #  #  #  # ]
    1486                 :            : 
    1487                 :            : // -----------------------------------------------------------------------
    1488                 :            : 
    1489                 :       9357 : bool MultiSalLayout::AddFallback( SalLayout& rFallback,
    1490                 :            :     ImplLayoutRuns& rFallbackRuns, const PhysicalFontFace* pFallbackFont )
    1491                 :            : {
    1492         [ -  + ]:       9357 :     if( mnLevel >= MAX_FALLBACK )
    1493                 :          0 :         return false;
    1494                 :            : 
    1495                 :       9357 :     mpFallbackFonts[ mnLevel ]  = pFallbackFont;
    1496                 :       9357 :     mpLayouts[ mnLevel ]        = &rFallback;
    1497                 :       9357 :     maFallbackRuns[ mnLevel-1 ] = rFallbackRuns;
    1498                 :       9357 :     ++mnLevel;
    1499                 :       9357 :     return true;
    1500                 :            : }
    1501                 :            : 
    1502                 :            : // -----------------------------------------------------------------------
    1503                 :            : 
    1504                 :       9357 : bool MultiSalLayout::LayoutText( ImplLayoutArgs& rArgs )
    1505                 :            : {
    1506         [ -  + ]:       9357 :     if( mnLevel <= 1 )
    1507                 :          0 :         return false;
    1508         [ +  - ]:       9357 :     if (!mbInComplete)
    1509                 :       9357 :         maFallbackRuns[ mnLevel-1 ] = rArgs.maRuns;
    1510                 :       9357 :     return true;
    1511                 :            : }
    1512                 :            : 
    1513                 :            : // -----------------------------------------------------------------------
    1514                 :            : 
    1515                 :       9357 : void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
    1516                 :            : {
    1517         [ +  - ]:       9357 :     SalLayout::AdjustLayout( rArgs );
    1518         [ +  - ]:       9357 :     ImplLayoutArgs aMultiArgs = rArgs;
    1519                 :            : 
    1520 [ +  - ][ +  + ]:       9357 :     if( !rArgs.mpDXArray && rArgs.mnLayoutWidth )
    1521                 :            :     {
    1522                 :            :         // for stretched text in a MultiSalLayout the target width needs to be
    1523                 :            :         // distributed by individually adjusting its virtual character widths
    1524                 :        315 :         long nTargetWidth = aMultiArgs.mnLayoutWidth;
    1525                 :        315 :         nTargetWidth *= mnUnitsPerPixel; // convert target width to base font units
    1526                 :        315 :         aMultiArgs.mnLayoutWidth = 0;
    1527                 :            : 
    1528                 :            :         // we need to get the original unmodified layouts ready
    1529         [ +  + ]:        945 :         for( int n = 0; n < mnLevel; ++n )
    1530         [ +  - ]:        630 :             mpLayouts[n]->SalLayout::AdjustLayout( aMultiArgs );
    1531                 :            :         // then we can measure the unmodified metrics
    1532                 :        315 :         int nCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
    1533                 :        315 :         sal_Int32* pJustificationArray = (sal_Int32*)alloca( nCharCount * sizeof(sal_Int32) );
    1534         [ +  - ]:        315 :         FillDXArray( pJustificationArray );
    1535                 :            :         // #i17359# multilayout is not simplified yet, so calculating the
    1536                 :            :         // unjustified width needs handholding; also count the number of
    1537                 :            :         // stretchable virtual char widths
    1538                 :        315 :         long nOrigWidth = 0;
    1539                 :        315 :         int nStretchable = 0;
    1540         [ +  + ]:        630 :         for( int i = 0; i < nCharCount; ++i )
    1541                 :            :         {
    1542                 :            :             // convert array from widths to sum of widths
    1543                 :        315 :             nOrigWidth += pJustificationArray[i];
    1544         [ +  - ]:        315 :             if( pJustificationArray[i] > 0 )
    1545                 :        315 :                 ++nStretchable;
    1546                 :            :         }
    1547                 :            : 
    1548                 :            :         // now we are able to distribute the extra width over the virtual char widths
    1549 [ +  - ][ +  + ]:        315 :         if( nOrigWidth && (nTargetWidth != nOrigWidth) )
    1550                 :            :         {
    1551                 :         54 :             int nDiffWidth = nTargetWidth - nOrigWidth;
    1552                 :         54 :             int nWidthSum = 0;
    1553         [ +  + ]:        108 :             for( int i = 0; i < nCharCount; ++i )
    1554                 :            :             {
    1555                 :         54 :                 int nJustWidth = pJustificationArray[i];
    1556 [ +  - ][ +  - ]:         54 :                 if( (nJustWidth > 0) && (nStretchable > 0) )
    1557                 :            :                 {
    1558                 :         54 :                     int nDeltaWidth = nDiffWidth / nStretchable;
    1559                 :         54 :                     nJustWidth += nDeltaWidth;
    1560                 :         54 :                     nDiffWidth -= nDeltaWidth;
    1561                 :         54 :                     --nStretchable;
    1562                 :            :                 }
    1563                 :         54 :                 nWidthSum += nJustWidth;
    1564                 :         54 :                 pJustificationArray[i] = nWidthSum;
    1565                 :            :             }
    1566         [ -  + ]:         54 :             if( nWidthSum != nTargetWidth )
    1567                 :          0 :                 pJustificationArray[ nCharCount-1 ] = nTargetWidth;
    1568                 :            : 
    1569                 :            :             // the justification array is still in base level units
    1570                 :            :             // => convert it to pixel units
    1571         [ -  + ]:         54 :             if( mnUnitsPerPixel > 1 )
    1572                 :            :             {
    1573         [ #  # ]:          0 :                 for( int i = 0; i < nCharCount; ++i )
    1574                 :            :                 {
    1575                 :          0 :                     sal_Int32 nVal = pJustificationArray[ i ];
    1576                 :          0 :                     nVal += (mnUnitsPerPixel + 1) / 2;
    1577                 :          0 :                     pJustificationArray[ i ] = nVal / mnUnitsPerPixel;
    1578                 :            :                 }
    1579                 :            :             }
    1580                 :            : 
    1581                 :            :             // change the mpDXArray temporarilly (just for the justification)
    1582                 :         54 :             aMultiArgs.mpDXArray = pJustificationArray;
    1583                 :            :         }
    1584                 :            :     }
    1585                 :            : 
    1586                 :            :     // Compute rtl flags, since in some scripts glyphs/char order can be
    1587                 :            :     // reversed for a few character sequencies e.g. Myanmar
    1588         [ +  - ]:       9357 :     std::vector<bool> vRtl(rArgs.mnEndCharPos - rArgs.mnMinCharPos, false);
    1589                 :       9357 :     rArgs.ResetPos();
    1590                 :            :     bool bRtl;
    1591                 :            :     int nRunStart, nRunEnd;
    1592 [ +  - ][ +  + ]:      18714 :     while (rArgs.GetNextRun(&nRunStart, &nRunEnd, &bRtl))
    1593                 :            :     {
    1594         [ -  + ]:       9357 :         if (bRtl) std::fill(vRtl.begin() + (nRunStart - rArgs.mnMinCharPos),
    1595         [ #  # ]:          0 :                             vRtl.begin() + (nRunEnd - rArgs.mnMinCharPos), true);
    1596                 :            :     }
    1597                 :       9357 :     rArgs.ResetPos();
    1598                 :            : 
    1599                 :            :     // prepare "merge sort"
    1600                 :            :     int nStartOld[ MAX_FALLBACK ];
    1601                 :            :     int nStartNew[ MAX_FALLBACK ];
    1602                 :            :     int nCharPos[ MAX_FALLBACK ];
    1603                 :            :     sal_Int32 nGlyphAdv[ MAX_FALLBACK ];
    1604                 :       9357 :     int nValid[ MAX_FALLBACK ] = {0};
    1605                 :            : 
    1606                 :            :     sal_GlyphId nDummy;
    1607                 :       9357 :     Point aPos;
    1608                 :       9357 :     int nLevel = 0, n;
    1609         [ +  + ]:      28071 :     for( n = 0; n < mnLevel; ++n )
    1610                 :            :     {
    1611                 :            :         // now adjust the individual components
    1612         [ +  + ]:      18714 :         if( n > 0 )
    1613                 :            :         {
    1614         [ +  - ]:       9357 :             aMultiArgs.maRuns = maFallbackRuns[ n-1 ];
    1615                 :       9357 :             aMultiArgs.mnFlags |= SAL_LAYOUT_FOR_FALLBACK;
    1616                 :            :         }
    1617         [ +  - ]:      18714 :         mpLayouts[n]->AdjustLayout( aMultiArgs );
    1618                 :            : 
    1619                 :            :         // disable glyph-injection for glyph-fallback SalLayout iteration
    1620         [ +  - ]:      18714 :         mpLayouts[n]->DisableGlyphInjection( true );
    1621                 :            : 
    1622                 :            :         // remove unused parts of component
    1623         [ +  + ]:      18714 :         if( n > 0 )
    1624                 :            :         {
    1625 [ -  + ][ #  # ]:       9357 :             if (mbInComplete && (n == mnLevel-1))
    1626         [ #  # ]:          0 :                 mpLayouts[n]->Simplify( true );
    1627                 :            :             else
    1628         [ +  - ]:       9357 :                 mpLayouts[n]->Simplify( false );
    1629                 :            :         }
    1630                 :            : 
    1631                 :            :         // prepare merging components
    1632                 :      18714 :         nStartNew[ nLevel ] = nStartOld[ nLevel ] = 0;
    1633                 :      37428 :         nValid[ nLevel ] = mpLayouts[n]->GetNextGlyphs( 1, &nDummy, aPos,
    1634         [ +  - ]:      18714 :             nStartNew[ nLevel ], &nGlyphAdv[ nLevel ], &nCharPos[ nLevel ] );
    1635                 :            : #ifdef MULTI_SL_DEBUG
    1636                 :            :         if (nValid[nLevel]) fprintf(mslLog(), "layout[%d]->GetNextGlyphs %d,%d x%d a%d c%d %x\n", n, nStartOld[nLevel], nStartNew[nLevel], aPos.X(), nGlyphAdv[nLevel], nCharPos[nLevel],
    1637                 :            :             rArgs.mpStr[nCharPos[nLevel]]);
    1638                 :            : #endif
    1639 [ +  + ][ -  + ]:      18714 :         if( (n > 0) && !nValid[ nLevel ] )
    1640                 :            :         {
    1641                 :            :             // an empty fallback layout can be released
    1642         [ #  # ]:          0 :             mpLayouts[n]->Release();
    1643                 :            :         }
    1644                 :            :         else
    1645                 :            :         {
    1646                 :            :             // reshuffle used fallbacks if needed
    1647         [ -  + ]:      18714 :             if( nLevel != n )
    1648                 :            :             {
    1649                 :          0 :                 mpLayouts[ nLevel ]         = mpLayouts[ n ];
    1650                 :          0 :                 mpFallbackFonts[ nLevel ]   = mpFallbackFonts[ n ];
    1651         [ #  # ]:          0 :                 maFallbackRuns[ nLevel ]    = maFallbackRuns[ n ];
    1652                 :            :             }
    1653                 :      18714 :             ++nLevel;
    1654                 :            :         }
    1655                 :            :     }
    1656                 :       9357 :     mnLevel = nLevel;
    1657                 :            : 
    1658                 :            :     // merge the fallback levels
    1659                 :       9357 :     long nXPos = 0;
    1660                 :       9357 :     double fUnitMul = 1.0;
    1661         [ +  + ]:      28071 :     for( n = 0; n < nLevel; ++n )
    1662                 :      18714 :         maFallbackRuns[n].ResetPos();
    1663                 :       9357 :     int nActiveCharPos = nCharPos[0];
    1664                 :       9357 :     int nLastRunEndChar = (vRtl[nActiveCharPos - mnMinCharPos])?
    1665 [ +  - ][ -  + ]:       9357 :         rArgs.mnEndCharPos : rArgs.mnMinCharPos - 1;
    1666                 :       9357 :     int nRunVisibleEndChar = nCharPos[0];
    1667 [ +  + ][ +  - ]:      18714 :     while( nValid[0] && (nLevel > 0))
                 [ +  + ]
    1668                 :            :     {
    1669                 :            :         // find best fallback level
    1670         [ +  - ]:      18714 :         for( n = 0; n < nLevel; ++n )
    1671 [ +  - ][ +  - ]:      18714 :             if( nValid[n] && !maFallbackRuns[n].PosIsInAnyRun( nActiveCharPos ) )
         [ +  + ][ +  + ]
    1672                 :            :                 // fallback level n wins when it requested no further fallback
    1673                 :       9357 :                 break;
    1674                 :       9357 :         int nFBLevel = n;
    1675                 :            : 
    1676         [ +  - ]:       9357 :         if( n < nLevel )
    1677                 :            :         {
    1678                 :            :             // use base(n==0) or fallback(n>=1) level
    1679                 :       9357 :             fUnitMul = mnUnitsPerPixel;
    1680                 :       9357 :             fUnitMul /= mpLayouts[n]->GetUnitsPerPixel();
    1681                 :       9357 :             long nNewPos = static_cast<long>(nXPos/fUnitMul + 0.5);
    1682         [ +  - ]:       9357 :             mpLayouts[n]->MoveGlyph( nStartOld[n], nNewPos );
    1683                 :            :         }
    1684                 :            :         else
    1685                 :            :         {
    1686                 :          0 :             n = 0;  // keep NotDef in base level
    1687                 :          0 :             fUnitMul = 1.0;
    1688                 :            :         }
    1689                 :            : 
    1690         [ +  - ]:       9357 :         if( n > 0 )
    1691                 :            :         {
    1692                 :            :             // drop the NotDef glyphs in the base layout run if a fallback run exists
    1693 [ +  - ][ +  - ]:      38022 :             while (
                 [ +  - ]
    1694         [ +  - ]:       9654 :                     (maFallbackRuns[ n-1 ].PosIsInRun( nCharPos[0] ) ) &&
    1695         [ +  - ]:       9654 :                     (!maFallbackRuns[ n ].PosIsInAnyRun( nCharPos[0] ) )
    1696                 :            :                   )
    1697                 :            :             {
    1698         [ +  - ]:       9654 :                 mpLayouts[0]->DropGlyph( nStartOld[0] );
    1699                 :       9654 :                 nStartOld[0] = nStartNew[0];
    1700                 :      19308 :                 nValid[0] = mpLayouts[0]->GetNextGlyphs( 1, &nDummy, aPos,
    1701         [ +  - ]:       9654 :                     nStartNew[0], &nGlyphAdv[0], &nCharPos[0] );
    1702                 :            : #ifdef MULTI_SL_DEBUG
    1703                 :            :                 if (nValid[0]) fprintf(mslLog(), "layout[0]->GetNextGlyphs %d,%d x%d a%d c%d %x\n", nStartOld[0], nStartNew[0], aPos.X(), nGlyphAdv[0], nCharPos[0], rArgs.mpStr[nCharPos[0]]);
    1704                 :            : #endif
    1705         [ +  + ]:       9654 :                 if( !nValid[0] )
    1706                 :       9357 :                    break;
    1707                 :            :             }
    1708                 :            :         }
    1709                 :            : 
    1710                 :            :         // skip to end of layout run and calculate its advance width
    1711                 :       9357 :         int nRunAdvance = 0;
    1712                 :       9357 :         bool bKeepNotDef = (nFBLevel >= nLevel);
    1713                 :        297 :         for(;;)
    1714                 :            :         {
    1715                 :       9654 :             nRunAdvance += nGlyphAdv[n];
    1716                 :            : 
    1717                 :            :             // proceed to next glyph
    1718                 :       9654 :             nStartOld[n] = nStartNew[n];
    1719                 :       9654 :             int nOrigCharPos = nCharPos[n];
    1720                 :      19308 :             nValid[n] = mpLayouts[n]->GetNextGlyphs( 1, &nDummy, aPos,
    1721         [ +  - ]:       9654 :                 nStartNew[n], &nGlyphAdv[n], &nCharPos[n] );
    1722                 :            : #ifdef MULTI_SL_DEBUG
    1723                 :            :             if (nValid[n]) fprintf(mslLog(), "layout[%d]->GetNextGlyphs %d,%d a%d c%d %x\n", n, nStartOld[n], nStartNew[n], nGlyphAdv[n], nCharPos[n], rArgs.mpStr[nCharPos[n]]);
    1724                 :            : #endif
    1725                 :            :             // break after last glyph of active layout
    1726         [ +  + ]:       9654 :             if( !nValid[n] )
    1727                 :            :             {
    1728                 :            :                 // performance optimization (when a fallback layout is no longer needed)
    1729         [ +  - ]:       9357 :                 if( n >= nLevel-1 )
    1730                 :       9357 :                     --nLevel;
    1731                 :       9357 :                 break;
    1732                 :            :             }
    1733                 :            : 
    1734                 :            :             //If the next character is one which belongs to the next level, then we
    1735                 :            :             //are finished here for now, and we'll pick up after the next level has
    1736                 :            :             //been processed
    1737 [ -  + ][ #  # ]:        297 :             if ((n+1 < nLevel) && (nCharPos[n] != nOrigCharPos))
    1738                 :            :             {
    1739         [ #  # ]:          0 :                 if (nOrigCharPos < nCharPos[n])
    1740                 :            :                 {
    1741 [ #  # ][ #  # ]:          0 :                     if (nCharPos[n+1] > nOrigCharPos && (nCharPos[n+1] < nCharPos[n]))
    1742                 :          0 :                         break;
    1743                 :            :                 }
    1744         [ #  # ]:          0 :                 else if (nOrigCharPos > nCharPos[n])
    1745                 :            :                 {
    1746 [ #  # ][ #  # ]:          0 :                     if (nCharPos[n+1] > nCharPos[n] && (nCharPos[n+1] < nOrigCharPos))
    1747                 :          0 :                         break;
    1748                 :            :                 }
    1749                 :            :             }
    1750                 :            : 
    1751                 :            :             // break at end of layout run
    1752         [ +  - ]:        297 :             if( n > 0 )
    1753                 :            :             {
    1754                 :            :                 // skip until end of fallback run
    1755 [ +  - ][ -  + ]:        297 :                 if( !maFallbackRuns[n-1].PosIsInRun( nCharPos[n] ) )
    1756                 :          0 :                     break;
    1757                 :            :             }
    1758                 :            :             else
    1759                 :            :             {
    1760                 :            :                 // break when a fallback is needed and available
    1761         [ #  # ]:          0 :                 bool bNeedFallback = maFallbackRuns[0].PosIsInRun( nCharPos[0] );
    1762         [ #  # ]:          0 :                 if( bNeedFallback )
    1763 [ #  # ][ #  # ]:          0 :                     if( !maFallbackRuns[ nLevel-1 ].PosIsInRun( nCharPos[0] ) )
    1764                 :          0 :                         break;
    1765                 :            :                 // break when change from resolved to unresolved base layout run
    1766 [ #  # ][ #  # ]:          0 :                 if( bKeepNotDef && !bNeedFallback )
    1767                 :          0 :                     { maFallbackRuns[0].NextRun(); break; }
    1768                 :          0 :                 bKeepNotDef = bNeedFallback;
    1769                 :            :             }
    1770                 :            :             // check for reordered glyphs
    1771 [ -  + ][ #  # ]:        297 :             if (aMultiArgs.mpDXArray &&
         [ #  # ][ #  # ]
                 [ #  # ]
    1772                 :            :                 nRunVisibleEndChar < mnEndCharPos &&
    1773                 :            :                 nRunVisibleEndChar >= mnMinCharPos &&
    1774                 :          0 :                 nCharPos[n] < mnEndCharPos &&
    1775                 :          0 :                 nCharPos[n] >= mnMinCharPos)
    1776                 :            :             {
    1777 [ #  # ][ #  # ]:          0 :                 if (vRtl[nActiveCharPos - mnMinCharPos])
    1778                 :            :                 {
    1779         [ #  # ]:          0 :                     if (aMultiArgs.mpDXArray[nRunVisibleEndChar-mnMinCharPos]
    1780                 :          0 :                         >= aMultiArgs.mpDXArray[nCharPos[n] - mnMinCharPos])
    1781                 :            :                     {
    1782                 :          0 :                         nRunVisibleEndChar = nCharPos[n];
    1783                 :            :                     }
    1784                 :            :                 }
    1785         [ #  # ]:          0 :                 else if (aMultiArgs.mpDXArray[nRunVisibleEndChar-mnMinCharPos]
    1786                 :          0 :                          <= aMultiArgs.mpDXArray[nCharPos[n] - mnMinCharPos])
    1787                 :            :                 {
    1788                 :          0 :                     nRunVisibleEndChar = nCharPos[n];
    1789                 :            :                 }
    1790                 :            :             }
    1791                 :            :         }
    1792                 :            : 
    1793                 :            :         // if a justification array is available
    1794                 :            :         // => use it directly to calculate the corresponding run width
    1795         [ +  + ]:       9357 :         if( aMultiArgs.mpDXArray )
    1796                 :            :         {
    1797                 :            :             // the run advance is the width from the first char
    1798                 :            :             // in the run to the first char in the next run
    1799                 :         54 :             nRunAdvance = 0;
    1800                 :            : #ifdef MULTI_SL_DEBUG
    1801                 :            :             const bool bLTR = !(vRtl[nActiveCharPos - mnMinCharPos]);//(nActiveCharPos < nCharPos[0]);
    1802                 :            :             int nOldRunAdv = 0;
    1803                 :            :             int nDXIndex = nCharPos[0] - mnMinCharPos - bLTR;
    1804                 :            :             if( nDXIndex >= 0 )
    1805                 :            :                 nOldRunAdv += aMultiArgs.mpDXArray[ nDXIndex ];
    1806                 :            :             nDXIndex = nActiveCharPos - mnMinCharPos - bLTR;
    1807                 :            :             if( nDXIndex >= 0 )
    1808                 :            :                 nOldRunAdv -= aMultiArgs.mpDXArray[ nDXIndex ];
    1809                 :            :             if( !bLTR )
    1810                 :            :                 nOldRunAdv = -nOldRunAdv;
    1811                 :            : #endif
    1812 [ +  - ][ -  + ]:         54 :             if (vRtl[nActiveCharPos - mnMinCharPos])
    1813                 :            :             {
    1814 [ #  # ][ #  # ]:          0 :               if (nRunVisibleEndChar > mnMinCharPos && nRunVisibleEndChar <= mnEndCharPos)
    1815                 :          0 :                   nRunAdvance -= aMultiArgs.mpDXArray[nRunVisibleEndChar - 1 - mnMinCharPos];
    1816 [ #  # ][ #  # ]:          0 :               if (nLastRunEndChar > mnMinCharPos && nLastRunEndChar <= mnEndCharPos)
    1817                 :          0 :                   nRunAdvance += aMultiArgs.mpDXArray[nLastRunEndChar - 1 - mnMinCharPos];
    1818                 :            : #ifdef MULTI_SL_DEBUG
    1819                 :            :               fprintf(mslLog(), "rtl visible %d-%d,%d-%d adv%d(%d)\n", nLastRunEndChar-1, nRunVisibleEndChar-1, nActiveCharPos - bLTR, nCharPos[0] - bLTR, nRunAdvance, nOldRunAdv);
    1820                 :            : #endif
    1821                 :            :             }
    1822                 :            :             else
    1823                 :            :             {
    1824         [ +  - ]:         54 :                 if (nRunVisibleEndChar >= mnMinCharPos)
    1825                 :         54 :                   nRunAdvance += aMultiArgs.mpDXArray[nRunVisibleEndChar - mnMinCharPos];
    1826         [ -  + ]:         54 :                 if (nLastRunEndChar >= mnMinCharPos)
    1827                 :          0 :                   nRunAdvance -= aMultiArgs.mpDXArray[nLastRunEndChar - mnMinCharPos];
    1828                 :            : #ifdef MULTI_SL_DEBUG
    1829                 :            :                 fprintf(mslLog(), "visible %d-%d,%d-%d adv%d(%d)\n", nLastRunEndChar, nRunVisibleEndChar, nActiveCharPos - bLTR, nCharPos[0] - bLTR, nRunAdvance, nOldRunAdv);
    1830                 :            : #endif
    1831                 :            :             }
    1832                 :         54 :             nLastRunEndChar = nRunVisibleEndChar;
    1833                 :         54 :             nRunVisibleEndChar = nCharPos[0];
    1834                 :            :             // the requested width is still in pixel units
    1835                 :            :             // => convert it to base level font units
    1836                 :         54 :             nRunAdvance *= mnUnitsPerPixel;
    1837                 :            :         }
    1838                 :            :         else
    1839                 :            :         {
    1840                 :            :             // the measured width is still in fallback font units
    1841                 :            :             // => convert it to base level font units
    1842         [ +  - ]:       9303 :             if( n > 0 ) // optimization: because (fUnitMul==1.0) for (n==0)
    1843                 :       9303 :                 nRunAdvance = static_cast<long>(nRunAdvance*fUnitMul + 0.5);
    1844                 :            :         }
    1845                 :            : 
    1846                 :            :         // calculate new x position (in base level units)
    1847                 :       9357 :         nXPos += nRunAdvance;
    1848                 :            : 
    1849                 :            :         // prepare for next fallback run
    1850                 :       9357 :         nActiveCharPos = nCharPos[0];
    1851                 :            :         // it essential that the runs don't get ahead of themselves and in the
    1852                 :            :         // if( bKeepNotDef && !bNeedFallback ) statement above, the next run may
    1853                 :            :         // have already been reached on the base level
    1854         [ +  + ]:      18714 :         for( int i = nFBLevel; --i >= 0;)
    1855                 :            :         {
    1856 [ +  - ][ +  - ]:       9357 :             if (maFallbackRuns[i].GetRun(&nRunStart, &nRunEnd, &bRtl))
    1857                 :            :             {
    1858         [ -  + ]:       9357 :                 if (bRtl)
    1859                 :            :                 {
    1860         [ #  # ]:          0 :                     if (nRunStart > nActiveCharPos)
    1861                 :          0 :                         maFallbackRuns[i].NextRun();
    1862                 :            :                 }
    1863                 :            :                 else
    1864                 :            :                 {
    1865         [ -  + ]:       9357 :                     if (nRunEnd <= nActiveCharPos)
    1866                 :          0 :                         maFallbackRuns[i].NextRun();
    1867                 :            :                 }
    1868                 :            :             }
    1869                 :            :         }
    1870                 :            : //            if( !maFallbackRuns[i].PosIsInRun( nActiveCharPos ) )
    1871                 :            : //                maFallbackRuns[i].NextRun();
    1872                 :            :     }
    1873                 :            : 
    1874         [ +  - ]:       9357 :     mpLayouts[0]->Simplify( true );
    1875                 :            : 
    1876                 :            :     // reenable glyph-injection
    1877         [ +  + ]:      28071 :     for( n = 0; n < mnLevel; ++n )
    1878         [ +  - ]:      28071 :         mpLayouts[n]->DisableGlyphInjection( false );
    1879                 :       9357 : }
    1880                 :            : 
    1881                 :            : // -----------------------------------------------------------------------
    1882                 :            : 
    1883                 :       9357 : void MultiSalLayout::InitFont() const
    1884                 :            : {
    1885         [ +  - ]:       9357 :     if( mnLevel > 0 )
    1886                 :       9357 :         mpLayouts[0]->InitFont();
    1887                 :       9357 : }
    1888                 :            : 
    1889                 :            : // -----------------------------------------------------------------------
    1890                 :            : 
    1891                 :          0 : const PhysicalFontFace* MultiSalLayout::GetFallbackFontData( sal_GlyphId nGlyphId ) const
    1892                 :            : {
    1893                 :          0 :     int nFallbackLevel = (nGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
    1894                 :          0 :     return mpFallbackFonts[ nFallbackLevel ];
    1895                 :            : }
    1896                 :            : 
    1897                 :            : // -----------------------------------------------------------------------
    1898                 :            : 
    1899                 :        519 : void MultiSalLayout::DrawText( SalGraphics& rGraphics ) const
    1900                 :            : {
    1901         [ +  + ]:       1557 :     for( int i = mnLevel; --i >= 0; )
    1902                 :            :     {
    1903                 :       1038 :         SalLayout& rLayout = *mpLayouts[ i ];
    1904                 :       1038 :         rLayout.DrawBase() += maDrawBase;
    1905                 :       1038 :         rLayout.DrawOffset() += maDrawOffset;
    1906                 :       1038 :         rLayout.InitFont();
    1907                 :       1038 :         rLayout.DrawText( rGraphics );
    1908                 :       1038 :         rLayout.DrawOffset() -= maDrawOffset;
    1909                 :       1038 :         rLayout.DrawBase() -= maDrawBase;
    1910                 :            :     }
    1911                 :            :     // NOTE: now the baselevel font is active again
    1912                 :        519 : }
    1913                 :            : 
    1914                 :            :  // -----------------------------------------------------------------------
    1915                 :            : 
    1916                 :          0 : int MultiSalLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
    1917                 :            : {
    1918         [ #  # ]:          0 :     if( mnLevel <= 0 )
    1919                 :          0 :         return STRING_LEN;
    1920         [ #  # ]:          0 :     if( mnLevel == 1 )
    1921                 :          0 :         return mpLayouts[0]->GetTextBreak( nMaxWidth, nCharExtra, nFactor );
    1922                 :            : 
    1923                 :          0 :     int nCharCount = mnEndCharPos - mnMinCharPos;
    1924                 :          0 :     sal_Int32* pCharWidths = (sal_Int32*)alloca( 2*nCharCount * sizeof(sal_Int32) );
    1925                 :          0 :     mpLayouts[0]->FillDXArray( pCharWidths );
    1926                 :            : 
    1927         [ #  # ]:          0 :     for( int n = 1; n < mnLevel; ++n )
    1928                 :            :     {
    1929                 :          0 :         SalLayout& rLayout = *mpLayouts[ n ];
    1930                 :          0 :         rLayout.FillDXArray( pCharWidths + nCharCount );
    1931                 :          0 :         double fUnitMul = mnUnitsPerPixel;
    1932                 :          0 :         fUnitMul /= rLayout.GetUnitsPerPixel();
    1933         [ #  # ]:          0 :         for( int i = 0; i < nCharCount; ++i )
    1934                 :            :         {
    1935                 :          0 :             long w = pCharWidths[ i + nCharCount ];
    1936                 :          0 :             w = static_cast<long>(w*fUnitMul + 0.5);
    1937                 :          0 :             pCharWidths[ i ] += w;
    1938                 :            :         }
    1939                 :            :     }
    1940                 :            : 
    1941                 :          0 :     long nWidth = 0;
    1942         [ #  # ]:          0 :     for( int i = 0; i < nCharCount; ++i )
    1943                 :            :     {
    1944                 :          0 :         nWidth += pCharWidths[ i ] * nFactor;
    1945         [ #  # ]:          0 :         if( nWidth > nMaxWidth )
    1946                 :          0 :             return (i + mnMinCharPos);
    1947                 :          0 :         nWidth += nCharExtra;
    1948                 :            :     }
    1949                 :            : 
    1950                 :          0 :     return STRING_LEN;
    1951                 :            : }
    1952                 :            : 
    1953                 :            : // -----------------------------------------------------------------------
    1954                 :            : 
    1955                 :       6666 : long MultiSalLayout::FillDXArray( sal_Int32* pCharWidths ) const
    1956                 :            : {
    1957                 :       6666 :     long nMaxWidth = 0;
    1958                 :            : 
    1959                 :            :     // prepare merging of fallback levels
    1960                 :       6666 :     sal_Int32* pTempWidths = NULL;
    1961                 :       6666 :     const int nCharCount = mnEndCharPos - mnMinCharPos;
    1962         [ +  + ]:       6666 :     if( pCharWidths )
    1963                 :            :     {
    1964         [ +  + ]:       1266 :         for( int i = 0; i < nCharCount; ++i )
    1965                 :        633 :             pCharWidths[i] = 0;
    1966                 :        633 :         pTempWidths = (sal_Int32*)alloca( nCharCount * sizeof(sal_Int32) );
    1967                 :            :     }
    1968                 :            : 
    1969         [ +  + ]:      19998 :     for( int n = mnLevel; --n >= 0; )
    1970                 :            :     {
    1971                 :            :         // query every fallback level
    1972                 :      13332 :         long nTextWidth = mpLayouts[n]->FillDXArray( pTempWidths );
    1973         [ +  + ]:      13332 :         if( !nTextWidth )
    1974                 :       7707 :             continue;
    1975                 :            :         // merge results from current level
    1976                 :       5625 :         double fUnitMul = mnUnitsPerPixel;
    1977                 :       5625 :         fUnitMul /= mpLayouts[n]->GetUnitsPerPixel();
    1978                 :       5625 :         nTextWidth = static_cast<long>(nTextWidth * fUnitMul + 0.5);
    1979         [ +  + ]:       5625 :         if( nMaxWidth < nTextWidth )
    1980                 :       5310 :             nMaxWidth = nTextWidth;
    1981         [ +  + ]:       5625 :         if( !pCharWidths )
    1982                 :       4743 :             continue;
    1983                 :            :         // calculate virtual char widths using most probable fallback layout
    1984         [ +  + ]:       1764 :         for( int i = 0; i < nCharCount; ++i )
    1985                 :            :         {
    1986                 :            :             // #i17359# restriction:
    1987                 :            :             // one char cannot be resolved from different fallbacks
    1988         [ +  + ]:        882 :             if( pCharWidths[i] != 0 )
    1989                 :        315 :                 continue;
    1990                 :        567 :             long nCharWidth = pTempWidths[i];
    1991         [ -  + ]:        567 :             if( !nCharWidth )
    1992                 :          0 :                 continue;
    1993                 :        567 :             nCharWidth = static_cast<long>(nCharWidth * fUnitMul + 0.5);
    1994                 :        567 :             pCharWidths[i] = nCharWidth;
    1995                 :            :         }
    1996                 :            :     }
    1997                 :            : 
    1998                 :       6666 :     return nMaxWidth;
    1999                 :            : }
    2000                 :            : 
    2001                 :            : // -----------------------------------------------------------------------
    2002                 :            : 
    2003                 :          0 : void MultiSalLayout::GetCaretPositions( int nMaxIndex, sal_Int32* pCaretXArray ) const
    2004                 :            : {
    2005                 :          0 :     SalLayout& rLayout = *mpLayouts[ 0 ];
    2006                 :          0 :     rLayout.GetCaretPositions( nMaxIndex, pCaretXArray );
    2007                 :            : 
    2008         [ #  # ]:          0 :     if( mnLevel > 1 )
    2009                 :            :     {
    2010                 :          0 :         sal_Int32* pTempPos = (sal_Int32*)alloca( nMaxIndex * sizeof(sal_Int32) );
    2011         [ #  # ]:          0 :         for( int n = 1; n < mnLevel; ++n )
    2012                 :            :         {
    2013                 :          0 :             mpLayouts[ n ]->GetCaretPositions( nMaxIndex, pTempPos );
    2014                 :          0 :             double fUnitMul = mnUnitsPerPixel;
    2015                 :          0 :             fUnitMul /= mpLayouts[n]->GetUnitsPerPixel();
    2016         [ #  # ]:          0 :             for( int i = 0; i < nMaxIndex; ++i )
    2017         [ #  # ]:          0 :                 if( pTempPos[i] >= 0 )
    2018                 :            :                 {
    2019                 :          0 :                     long w = pTempPos[i];
    2020                 :          0 :                     w = static_cast<long>(w*fUnitMul + 0.5);
    2021                 :          0 :                     pCaretXArray[i] = w;
    2022                 :            :                 }
    2023                 :            :         }
    2024                 :            :     }
    2025                 :          0 : }
    2026                 :            : 
    2027                 :            : // -----------------------------------------------------------------------
    2028                 :            : 
    2029                 :          0 : int MultiSalLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIdxAry, Point& rPos,
    2030                 :            :     int& nStart, sal_Int32* pGlyphAdvAry, int* pCharPosAry ) const
    2031                 :            : {
    2032                 :            :     // for multi-level fallback only single glyphs should be used
    2033 [ #  # ][ #  # ]:          0 :     if( mnLevel > 1 && nLen > 1 )
    2034                 :          0 :         nLen = 1;
    2035                 :            : 
    2036                 :            :     // NOTE: nStart is tagged with current font index
    2037                 :          0 :     int nLevel = static_cast<unsigned>(nStart) >> GF_FONTSHIFT;
    2038                 :          0 :     nStart &= ~GF_FONTMASK;
    2039         [ #  # ]:          0 :     for(; nLevel < mnLevel; ++nLevel, nStart=0 )
    2040                 :            :     {
    2041                 :          0 :         SalLayout& rLayout = *mpLayouts[ nLevel ];
    2042                 :          0 :         rLayout.InitFont();
    2043                 :            :         int nRetVal = rLayout.GetNextGlyphs( nLen, pGlyphIdxAry, rPos,
    2044                 :          0 :             nStart, pGlyphAdvAry, pCharPosAry );
    2045         [ #  # ]:          0 :         if( nRetVal )
    2046                 :            :         {
    2047                 :          0 :             int nFontTag = nLevel << GF_FONTSHIFT;
    2048                 :          0 :             nStart |= nFontTag;
    2049                 :          0 :             double fUnitMul = mnUnitsPerPixel;
    2050                 :          0 :             fUnitMul /= mpLayouts[nLevel]->GetUnitsPerPixel();
    2051         [ #  # ]:          0 :             for( int i = 0; i < nRetVal; ++i )
    2052                 :            :             {
    2053         [ #  # ]:          0 :                 if( pGlyphAdvAry )
    2054                 :            :                 {
    2055                 :          0 :                     long w = pGlyphAdvAry[i];
    2056                 :          0 :                     w = static_cast<long>(w * fUnitMul + 0.5);
    2057                 :          0 :                     pGlyphAdvAry[i] = w;
    2058                 :            :                 }
    2059                 :          0 :                 pGlyphIdxAry[ i ] |= nFontTag;
    2060                 :            :             }
    2061                 :          0 :             rPos += maDrawBase;
    2062                 :          0 :             rPos += maDrawOffset;
    2063                 :          0 :             return nRetVal;
    2064                 :            :         }
    2065                 :            :     }
    2066                 :            : 
    2067                 :            :     // #111016# reset to base level font when done
    2068                 :          0 :     mpLayouts[0]->InitFont();
    2069                 :          0 :     return 0;
    2070                 :            : }
    2071                 :            : 
    2072                 :            : // -----------------------------------------------------------------------
    2073                 :            : 
    2074                 :        138 : bool MultiSalLayout::GetOutline( SalGraphics& rGraphics,
    2075                 :            :     ::basegfx::B2DPolyPolygonVector& rPPV ) const
    2076                 :            : {
    2077                 :        138 :     bool bRet = false;
    2078                 :            : 
    2079         [ +  + ]:        414 :     for( int i = mnLevel; --i >= 0; )
    2080                 :            :     {
    2081                 :        276 :         SalLayout& rLayout = *mpLayouts[ i ];
    2082                 :        276 :         rLayout.DrawBase() = maDrawBase;
    2083                 :        276 :         rLayout.DrawOffset() += maDrawOffset;
    2084                 :        276 :         rLayout.InitFont();
    2085                 :        276 :         bRet |= rLayout.GetOutline( rGraphics, rPPV );
    2086                 :        276 :         rLayout.DrawOffset() -= maDrawOffset;
    2087                 :            :     }
    2088                 :            : 
    2089                 :        138 :     return bRet;
    2090                 :            : }
    2091                 :            : 
    2092                 :            : // -----------------------------------------------------------------------
    2093                 :            : 
    2094                 :       2454 : bool MultiSalLayout::GetBoundRect( SalGraphics& rGraphics, Rectangle& rRect ) const
    2095                 :            : {
    2096                 :       2454 :     bool bRet = false;
    2097                 :            : 
    2098         [ +  - ]:       2454 :     Rectangle aRectangle;
    2099         [ +  + ]:       7362 :     for( int i = mnLevel; --i >= 0; )
    2100                 :            :     {
    2101                 :       4908 :         SalLayout& rLayout = *mpLayouts[ i ];
    2102                 :       4908 :         rLayout.DrawBase() = maDrawBase;
    2103                 :       4908 :         rLayout.DrawOffset() += maDrawOffset;
    2104         [ +  - ]:       4908 :         rLayout.InitFont();
    2105 [ +  - ][ +  + ]:       4908 :         if( rLayout.GetBoundRect( rGraphics, aRectangle ) )
    2106                 :            :         {
    2107         [ +  - ]:       2454 :             rRect.Union( aRectangle );
    2108                 :       2454 :             bRet = true;
    2109                 :            :         }
    2110                 :       4908 :         rLayout.DrawOffset() -= maDrawOffset;
    2111                 :            :     }
    2112                 :            : 
    2113                 :       2454 :     return bRet;
    2114                 :            : }
    2115                 :            : 
    2116                 :            : // =======================================================================
    2117                 :            : 
    2118                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10