LCOV - code coverage report
Current view: top level - vcl/source/gdi - impfont.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 208 452 46.0 %
Date: 2014-11-03 Functions: 24 30 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * This file is part of the LibreOffice project.
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * This file incorporates work covered by the following license notice:
       9             :  *
      10             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      11             :  *   contributor license agreements. See the NOTICE file distributed
      12             :  *   with this work for additional information regarding copyright
      13             :  *   ownership. The ASF licenses this file to you under the Apache
      14             :  *   License, Version 2.0 (the "License"); you may not use this file
      15             :  *   except in compliance with the License. You may obtain a copy of
      16             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      17             :  */
      18             : #include <vcl/metric.hxx>
      19             : #include <outfont.hxx>
      20             : #include <impfont.hxx>
      21             : 
      22             : #include <vector>
      23             : #include <set>
      24             : 
      25       11490 : CmapResult::CmapResult( bool bSymbolic,
      26             :     const sal_UCS4* pRangeCodes, int nRangeCount,
      27             :     const int* pStartGlyphs, const sal_uInt16* pExtraGlyphIds )
      28             : :   mpRangeCodes( pRangeCodes)
      29             : ,   mpStartGlyphs( pStartGlyphs)
      30             : ,   mpGlyphIds( pExtraGlyphIds)
      31             : ,   mnRangeCount( nRangeCount)
      32             : ,   mbSymbolic( bSymbolic)
      33       11490 : ,   mbRecoded( false)
      34       11490 : {}
      35             : 
      36         411 : static ImplFontCharMapPtr pDefaultImplFontCharMap;
      37             : static const sal_UCS4 aDefaultUnicodeRanges[] = {0x0020,0xD800, 0xE000,0xFFF0};
      38             : static const sal_UCS4 aDefaultSymbolRanges[] = {0x0020,0x0100, 0xF020,0xF100};
      39             : 
      40       22980 : ImplFontCharMap::~ImplFontCharMap()
      41             : {
      42       11490 :     if( isDefaultMap() )
      43       11116 :         return;
      44         374 :     delete[] mpRangeCodes;
      45         374 :     delete[] mpStartGlyphs;
      46         374 :     delete[] mpGlyphIds;
      47       11864 : }
      48             : 
      49       11490 : ImplFontCharMap::ImplFontCharMap( const CmapResult& rCR )
      50             : :   mpRangeCodes( rCR.mpRangeCodes )
      51             : ,   mpStartGlyphs( rCR.mpStartGlyphs )
      52             : ,   mpGlyphIds( rCR.mpGlyphIds )
      53             : ,   mnRangeCount( rCR.mnRangeCount )
      54             : ,   mnCharCount( 0 )
      55       11490 : ,   mnRefCount( 0 )
      56             : {
      57       11490 :     const sal_UCS4* pRangePtr = mpRangeCodes;
      58      112358 :     for( int i = mnRangeCount; --i >= 0; pRangePtr += 2 )
      59             :     {
      60      100868 :         sal_UCS4 cFirst = pRangePtr[0];
      61      100868 :         sal_UCS4 cLast  = pRangePtr[1];
      62      100868 :         mnCharCount += cLast - cFirst;
      63             :     }
      64       11490 : }
      65             : 
      66       11116 : ImplFontCharMapPtr ImplFontCharMap::getDefaultMap( bool bSymbols )
      67             : {
      68       11116 :     const sal_UCS4* pRangeCodes = aDefaultUnicodeRanges;
      69       11116 :     int nCodesCount = sizeof(aDefaultUnicodeRanges) / sizeof(*pRangeCodes);
      70       11116 :     if( bSymbols )
      71             :     {
      72           0 :         pRangeCodes = aDefaultSymbolRanges;
      73           0 :         nCodesCount = sizeof(aDefaultSymbolRanges) / sizeof(*pRangeCodes);
      74             :     }
      75             : 
      76       11116 :     CmapResult aDefaultCR( bSymbols, pRangeCodes, nCodesCount/2 );
      77       11116 :     pDefaultImplFontCharMap.reset( new ImplFontCharMap( aDefaultCR ) );
      78             : 
      79       11116 :     return pDefaultImplFontCharMap;
      80             : }
      81             : 
      82       25402 : bool ImplFontCharMap::isDefaultMap() const
      83             : {
      84       25402 :     const bool bIsDefault = (mpRangeCodes == aDefaultUnicodeRanges) || (mpRangeCodes == aDefaultSymbolRanges);
      85       25402 :     return bIsDefault;
      86             : }
      87             : 
      88      192994 : static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
      89       87868 : static unsigned Getsal_uInt16( const unsigned char* p ){ return((p[0]<<8) | p[1]);}
      90       14694 : static int GetSShort( const unsigned char* p ){ return static_cast<sal_Int16>((p[0]<<8)|p[1]);}
      91             : 
      92             : // TODO: move CMAP parsing directly into the ImplFontCharMap class
      93         368 : bool ParseCMAP( const unsigned char* pCmap, int nLength, CmapResult& rResult )
      94             : {
      95         368 :     rResult.mpRangeCodes = NULL;
      96         368 :     rResult.mpStartGlyphs= NULL;
      97         368 :     rResult.mpGlyphIds   = NULL;
      98         368 :     rResult.mnRangeCount = 0;
      99         368 :     rResult.mbRecoded    = false;
     100         368 :     rResult.mbSymbolic   = false;
     101             : 
     102             :     // parse the table header and check for validity
     103         368 :     if( !pCmap || (nLength < 24) )
     104           0 :         return false;
     105             : 
     106         368 :     if( Getsal_uInt16( pCmap ) != 0x0000 ) // simple check for CMAP corruption
     107           0 :         return false;
     108             : 
     109         368 :     int nSubTables = Getsal_uInt16( pCmap + 2 );
     110         368 :     if( (nSubTables <= 0) || (nLength < (24 + 8*nSubTables)) )
     111           0 :         return false;
     112             : 
     113             :     // find the most interesting subtable in the CMAP
     114         368 :     rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE;
     115         368 :     int nOffset = 0;
     116         368 :     int nFormat = -1;
     117         368 :     int nBestVal = 0;
     118        1956 :     for( const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8 )
     119             :     {
     120        1588 :         int nPlatform = Getsal_uInt16( p );
     121        1588 :         int nEncoding = Getsal_uInt16( p+2 );
     122        1588 :         int nPlatformEncoding = (nPlatform << 8) + nEncoding;
     123             : 
     124             :         int nValue;
     125        1588 :         rtl_TextEncoding eTmpEncoding = RTL_TEXTENCODING_UNICODE;
     126        1588 :         switch( nPlatformEncoding )
     127             :         {
     128           0 :             case 0x000: nValue = 20; break;                             // Unicode 1.0
     129           0 :             case 0x001: nValue = 21; break;                             // Unicode 1.1
     130           0 :             case 0x002: nValue = 22; break;                             // iso10646_1993
     131         362 :             case 0x003: nValue = 23; break;                             // UCS-2
     132         246 :             case 0x004: nValue = 24; break;                             // UCS-4
     133         366 :             case 0x100: nValue = 22; break;                             // Mac Unicode<2.0
     134           0 :             case 0x103: nValue = 23; break;                             // Mac Unicode>2.0
     135           0 :             case 0x300: nValue =  5; rResult.mbSymbolic = true; break;  // Win Symbol
     136         368 :             case 0x301: nValue = 28; break;                             // Win UCS-2
     137         246 :             case 0x30A: nValue = 29; break;                             // Win-UCS-4
     138           0 :             case 0x302: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_SHIFT_JIS; break;
     139           0 :             case 0x303: nValue = 12; eTmpEncoding = RTL_TEXTENCODING_GB_18030; break;
     140           0 :             case 0x304: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_BIG5; break;
     141           0 :             case 0x305: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_949; break;
     142           0 :             case 0x306: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_1361; break;
     143           0 :             default:    nValue = 0; break;
     144             :         }
     145             : 
     146        1588 :         if( nValue <= 0 )   // ignore unknown encodings
     147           0 :             continue;
     148             : 
     149        1588 :         int nTmpOffset = GetUInt( p+4 );
     150        1588 :         int nTmpFormat = Getsal_uInt16( pCmap + nTmpOffset );
     151        1588 :         if( nTmpFormat == 12 )                  // 32bit code -> glyph map format
     152         492 :             nValue += 3;
     153        1096 :         else if( nTmpFormat != 4 )              // 16bit code -> glyph map format
     154         366 :             continue;                           // ignore other formats
     155             : 
     156        1222 :         if( nBestVal < nValue )
     157             :         {
     158        1222 :             nBestVal = nValue;
     159        1222 :             nOffset = nTmpOffset;
     160        1222 :             nFormat = nTmpFormat;
     161        1222 :             eRecodeFrom = eTmpEncoding;
     162             :         }
     163             :     }
     164             : 
     165             :     // parse the best CMAP subtable
     166         368 :     int nRangeCount = 0;
     167         368 :     sal_UCS4* pCodePairs = NULL;
     168         368 :     int* pStartGlyphs = NULL;
     169             : 
     170             :     typedef std::vector<sal_uInt16> U16Vector;
     171         368 :     U16Vector aGlyphIdArray;
     172         368 :     aGlyphIdArray.reserve( 0x1000 );
     173         368 :     aGlyphIdArray.push_back( 0 );
     174             : 
     175             :     // format 4, the most common 16bit char mapping table
     176         368 :     if( (nFormat == 4) && ((nOffset+16) < nLength) )
     177             :     {
     178         122 :         int nSegCountX2 = Getsal_uInt16( pCmap + nOffset + 6 );
     179         122 :         nRangeCount = nSegCountX2/2 - 1;
     180         122 :         pCodePairs = new sal_UCS4[ nRangeCount * 2 ];
     181         122 :         pStartGlyphs = new int[ nRangeCount ];
     182         122 :         const unsigned char* pLimitBase = pCmap + nOffset + 14;
     183         122 :         const unsigned char* pBeginBase = pLimitBase + nSegCountX2 + 2;
     184         122 :         const unsigned char* pDeltaBase = pBeginBase + nSegCountX2;
     185         122 :         const unsigned char* pOffsetBase = pDeltaBase + nSegCountX2;
     186         122 :         sal_UCS4* pCP = pCodePairs;
     187       14816 :         for( int i = 0; i < nRangeCount; ++i )
     188             :         {
     189       14694 :             const sal_UCS4 cMinChar = Getsal_uInt16( pBeginBase + 2*i );
     190       14694 :             const sal_UCS4 cMaxChar = Getsal_uInt16( pLimitBase + 2*i );
     191       14694 :             const int nGlyphDelta  = GetSShort( pDeltaBase + 2*i );
     192       14694 :             const int nRangeOffset = Getsal_uInt16( pOffsetBase + 2*i );
     193       14694 :             if( cMinChar > cMaxChar ) {  // no sane font should trigger this
     194             :                 SAL_WARN("vcl.gdi", "Min char should never be more than the max char!");
     195           0 :                 break;
     196             :             }
     197       14694 :             if( cMaxChar == 0xFFFF ) {
     198             :                 SAL_WARN("vcl.gdi", "Format 4 char should not be 0xFFFF");
     199           0 :                 break;
     200             :             }
     201       14694 :             *(pCP++) = cMinChar;
     202       14694 :             *(pCP++) = cMaxChar + 1;
     203       14694 :             if( !nRangeOffset ) {
     204             :                 // glyphid can be calculated directly
     205       13304 :                 pStartGlyphs[i] = (cMinChar + nGlyphDelta) & 0xFFFF;
     206             :             } else {
     207             :                 // update the glyphid-array with the glyphs in this range
     208        1390 :                 pStartGlyphs[i] = -(int)aGlyphIdArray.size();
     209        1390 :                 const unsigned char* pGlyphIdPtr = pOffsetBase + 2*i + nRangeOffset;
     210       39554 :                 for( sal_UCS4 c = cMinChar; c <= cMaxChar; ++c, pGlyphIdPtr+=2 ) {
     211       38164 :                     const int nGlyphIndex = Getsal_uInt16( pGlyphIdPtr ) + nGlyphDelta;
     212       38164 :                     aGlyphIdArray.push_back( static_cast<sal_uInt16>(nGlyphIndex) );
     213             :                 }
     214             :             }
     215             :         }
     216         122 :         nRangeCount = (pCP - pCodePairs) / 2;
     217             :     }
     218             :     // format 12, the most common 32bit char mapping table
     219         246 :     else if( (nFormat == 12) && ((nOffset+16) < nLength) )
     220             :     {
     221         246 :         nRangeCount = GetUInt( pCmap + nOffset + 12 );
     222         246 :         pCodePairs = new sal_UCS4[ nRangeCount * 2 ];
     223         246 :         pStartGlyphs = new int[ nRangeCount ];
     224         246 :         const unsigned char* pGroup = pCmap + nOffset + 16;
     225         246 :         sal_UCS4* pCP = pCodePairs;
     226       63966 :         for( int i = 0; i < nRangeCount; ++i )
     227             :         {
     228       63720 :             sal_UCS4 cMinChar = GetUInt( pGroup + 0 );
     229       63720 :             sal_UCS4 cMaxChar = GetUInt( pGroup + 4 );
     230       63720 :             int nGlyphId = GetUInt( pGroup + 8 );
     231       63720 :             pGroup += 12;
     232             : 
     233       63720 :             if( cMinChar > cMaxChar ) {   // no sane font should trigger this
     234             :                 SAL_WARN("vcl.gdi", "Min char should never be more than the max char!");
     235           0 :                 break;
     236             :             }
     237             : 
     238       63720 :             *(pCP++) = cMinChar;
     239       63720 :             *(pCP++) = cMaxChar + 1;
     240       63720 :             pStartGlyphs[i] = nGlyphId;
     241             :         }
     242         246 :         nRangeCount = (pCP - pCodePairs) / 2;
     243             :     }
     244             : 
     245             :     // check if any subtable resulted in something usable
     246         368 :     if( nRangeCount <= 0 )
     247             :     {
     248           0 :         delete[] pCodePairs;
     249           0 :         delete[] pStartGlyphs;
     250             : 
     251             :         // even when no CMAP is available we know it for symbol fonts
     252           0 :         if( rResult.mbSymbolic )
     253             :         {
     254           0 :             pCodePairs = new sal_UCS4[4];
     255           0 :             pCodePairs[0] = 0x0020;    // aliased symbols
     256           0 :             pCodePairs[1] = 0x0100;
     257           0 :             pCodePairs[2] = 0xF020;    // original symbols
     258           0 :             pCodePairs[3] = 0xF100;
     259           0 :             rResult.mpRangeCodes = pCodePairs;
     260           0 :             rResult.mnRangeCount = 2;
     261           0 :             return true;
     262             :         }
     263             : 
     264           0 :         return false;
     265             :     }
     266             : 
     267             :     // recode the code ranges to their unicode encoded ranges if needed
     268         368 :     rtl_TextToUnicodeConverter aConverter = NULL;
     269         368 :     rtl_UnicodeToTextContext aCvtContext = NULL;
     270             : 
     271         368 :     rResult.mbRecoded = ( eRecodeFrom != RTL_TEXTENCODING_UNICODE );
     272         368 :     if( rResult.mbRecoded )
     273             :     {
     274           0 :         aConverter = rtl_createTextToUnicodeConverter( eRecodeFrom );
     275           0 :         aCvtContext = rtl_createTextToUnicodeContext( aConverter );
     276             :     }
     277             : 
     278         368 :     if( aConverter && aCvtContext )
     279             :     {
     280             :         // determine the set of supported unicodes from encoded ranges
     281             :         typedef std::set<sal_UCS4> Ucs4Set;
     282           0 :         Ucs4Set aSupportedUnicodes;
     283             : 
     284             :         static const int NINSIZE = 64;
     285             :         static const int NOUTSIZE = 64;
     286             :         sal_Char    cCharsInp[ NINSIZE ];
     287             :         sal_Unicode cCharsOut[ NOUTSIZE ];
     288           0 :         sal_UCS4* pCP = pCodePairs;
     289           0 :         for( int i = 0; i < nRangeCount; ++i )
     290             :         {
     291           0 :             sal_UCS4 cMin = *(pCP++);
     292           0 :             sal_UCS4 cEnd = *(pCP++);
     293           0 :             while( cMin < cEnd )
     294             :             {
     295           0 :                 int j = 0;
     296           0 :                 for(; (cMin < cEnd) && (j < NINSIZE); ++cMin )
     297             :                 {
     298           0 :                     if( cMin >= 0x0100 )
     299           0 :                         cCharsInp[ j++ ] = static_cast<sal_Char>(cMin >> 8);
     300           0 :                     if( (cMin >= 0x0100) || (cMin < 0x00A0)  )
     301           0 :                         cCharsInp[ j++ ] = static_cast<sal_Char>(cMin);
     302             :                 }
     303             : 
     304             :                 sal_uInt32 nCvtInfo;
     305             :                 sal_Size nSrcCvtBytes;
     306             :                 int nOutLen = rtl_convertTextToUnicode(
     307             :                     aConverter, aCvtContext,
     308             :                     cCharsInp, j, cCharsOut, NOUTSIZE,
     309             :                     RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE
     310             :                     | RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE,
     311           0 :                     &nCvtInfo, &nSrcCvtBytes );
     312             : 
     313           0 :                 for( j = 0; j < nOutLen; ++j )
     314           0 :                     aSupportedUnicodes.insert( cCharsOut[j] );
     315             :             }
     316             :         }
     317             : 
     318           0 :         rtl_destroyTextToUnicodeConverter( aCvtContext );
     319           0 :         rtl_destroyTextToUnicodeConverter( aConverter );
     320             : 
     321             :         // convert the set of supported unicodes to ranges
     322             :         typedef std::vector<sal_UCS4> Ucs4Vector;
     323           0 :         Ucs4Vector aSupportedRanges;
     324             : 
     325           0 :         Ucs4Set::const_iterator itChar = aSupportedUnicodes.begin();
     326           0 :         for(; itChar != aSupportedUnicodes.end(); ++itChar )
     327             :         {
     328           0 :             if( aSupportedRanges.empty()
     329           0 :             || (aSupportedRanges.back() != *itChar) )
     330             :             {
     331             :                 // add new range beginning with current unicode
     332           0 :                 aSupportedRanges.push_back( *itChar );
     333           0 :                 aSupportedRanges.push_back( 0 );
     334             :             }
     335             : 
     336             :             // extend existing range to include current unicode
     337           0 :             aSupportedRanges.back() = *itChar + 1;
     338             :         }
     339             : 
     340             :         // glyph mapping for non-unicode fonts not implemented
     341           0 :         delete[] pStartGlyphs;
     342           0 :         pStartGlyphs = NULL;
     343           0 :         aGlyphIdArray.clear();
     344             : 
     345             :         // make a pCodePairs array using the vector from above
     346           0 :         delete[] pCodePairs;
     347           0 :         nRangeCount = aSupportedRanges.size() / 2;
     348           0 :         if( nRangeCount <= 0 )
     349           0 :             return false;
     350           0 :         pCodePairs = new sal_UCS4[ nRangeCount * 2 ];
     351           0 :         Ucs4Vector::const_iterator itInt = aSupportedRanges.begin();
     352           0 :         for( pCP = pCodePairs; itInt != aSupportedRanges.end(); ++itInt )
     353           0 :             *(pCP++) = *itInt;
     354             :     }
     355             : 
     356             :     // prepare the glyphid-array if needed
     357             :     // TODO: merge ranges if they are close enough?
     358         368 :     sal_uInt16* pGlyphIds = NULL;
     359         368 :     if( !aGlyphIdArray.empty())
     360             :     {
     361         368 :         pGlyphIds = new sal_uInt16[ aGlyphIdArray.size() ];
     362         368 :         sal_uInt16* pOut = pGlyphIds;
     363         368 :         U16Vector::const_iterator it = aGlyphIdArray.begin();
     364       39268 :         while( it != aGlyphIdArray.end() )
     365       38532 :             *(pOut++) = *(it++);
     366             :     }
     367             : 
     368             :     // update the result struct
     369         368 :     rResult.mpRangeCodes = pCodePairs;
     370         368 :     rResult.mpStartGlyphs = pStartGlyphs;
     371         368 :     rResult.mnRangeCount = nRangeCount;
     372         368 :     rResult.mpGlyphIds = pGlyphIds;
     373         368 :     return true;
     374             : }
     375             : 
     376       11116 : FontCharMap::FontCharMap()
     377             :     : mpImplFontCharMap( ImplFontCharMap::getDefaultMap() )
     378       11116 :     , mnRefCount(0)
     379       11116 : {}
     380             : 
     381           0 : FontCharMap::FontCharMap( ImplFontCharMapPtr pIFCMap )
     382             :     : mpImplFontCharMap( pIFCMap )
     383           0 :     , mnRefCount(0)
     384           0 : {}
     385             : 
     386         374 : FontCharMap::FontCharMap( const CmapResult& rCR )
     387         374 :     : mnRefCount(0)
     388             : {
     389         374 :     ImplFontCharMapPtr pImplFontCharMap( new ImplFontCharMap(rCR) );
     390         374 :     mpImplFontCharMap = pImplFontCharMap;
     391             : 
     392         374 :     const sal_UCS4* pRangePtr = mpImplFontCharMap->mpRangeCodes;
     393       79010 :     for( int i = mpImplFontCharMap->mnRangeCount; --i >= 0; pRangePtr += 2 )
     394             :     {
     395       78636 :         sal_UCS4 cFirst = pRangePtr[0];
     396       78636 :         sal_UCS4 cLast  = pRangePtr[1];
     397       78636 :         mpImplFontCharMap->mnCharCount += cLast - cFirst;
     398         374 :     }
     399         374 : }
     400             : 
     401       22980 : FontCharMap::~FontCharMap()
     402             : {
     403       11490 :     mpImplFontCharMap = 0;
     404       11490 : }
     405             : 
     406           0 : FontCharMapPtr FontCharMap::GetDefaultMap( bool bSymbol )
     407             : {
     408           0 :     FontCharMapPtr pFontCharMap( new FontCharMap( ImplFontCharMap::getDefaultMap( bSymbol ) ) );
     409           0 :     return pFontCharMap;
     410             : }
     411             : 
     412       13912 : bool FontCharMap::IsDefaultMap() const
     413             : {
     414       13912 :     return mpImplFontCharMap->isDefaultMap();
     415             : }
     416             : 
     417           8 : int FontCharMap::GetCharCount() const
     418             : {
     419           8 :     return mpImplFontCharMap->mnCharCount;
     420             : }
     421             : 
     422           0 : int FontCharMap::CountCharsInRange( sal_UCS4 cMin, sal_UCS4 cMax ) const
     423             : {
     424           0 :     int nCount = 0;
     425             : 
     426             :     // find and adjust range and char count for cMin
     427           0 :     int nRangeMin = findRangeIndex( cMin );
     428           0 :     if( nRangeMin & 1 )
     429           0 :         ++nRangeMin;
     430           0 :     else if( cMin > mpImplFontCharMap->mpRangeCodes[ nRangeMin ] )
     431           0 :         nCount -= cMin - mpImplFontCharMap->mpRangeCodes[ nRangeMin ];
     432             : 
     433             :     // find and adjust range and char count for cMax
     434           0 :     int nRangeMax = findRangeIndex( cMax );
     435           0 :     if( nRangeMax & 1 )
     436           0 :         --nRangeMax;
     437             :     else
     438           0 :         nCount -= mpImplFontCharMap->mpRangeCodes[ nRangeMax+1 ] - cMax - 1;
     439             : 
     440             :     // count chars in complete ranges between cMin and cMax
     441           0 :     for( int i = nRangeMin; i <= nRangeMax; i+=2 )
     442           0 :         nCount += mpImplFontCharMap->mpRangeCodes[i+1] - mpImplFontCharMap->mpRangeCodes[i];
     443             : 
     444           0 :     return nCount;
     445             : }
     446             : 
     447       83584 : bool FontCharMap::HasChar( sal_UCS4 cChar ) const
     448             : {
     449       83584 :     bool bHasChar = false;
     450             : 
     451       83584 :     if( mpImplFontCharMap->mpStartGlyphs  == NULL ) { // only the char-ranges are known
     452         176 :         const int nRange = findRangeIndex( cChar );
     453         176 :         if( nRange==0 && cChar < mpImplFontCharMap->mpRangeCodes[0] )
     454           0 :             return false;
     455         176 :         bHasChar = ((nRange & 1) == 0); // inside a range
     456             :     } else { // glyph mapping is available
     457       83408 :         const int nGlyphIndex = GetGlyphIndex( cChar );
     458       83408 :         bHasChar = (nGlyphIndex != 0); // not the notdef-glyph
     459             :     }
     460             : 
     461       83584 :     return bHasChar;
     462             : }
     463             : 
     464        1250 : sal_UCS4 FontCharMap::GetFirstChar() const
     465             : {
     466        1250 :     return mpImplFontCharMap->mpRangeCodes[0];
     467             : }
     468             : 
     469         572 : sal_UCS4 FontCharMap::GetLastChar() const
     470             : {
     471         572 :     return (mpImplFontCharMap->mpRangeCodes[ 2*mpImplFontCharMap->mnRangeCount-1 ] - 1);
     472             : }
     473             : 
     474           2 : sal_UCS4 FontCharMap::GetNextChar( sal_UCS4 cChar ) const
     475             : {
     476           2 :     if( cChar < GetFirstChar() )
     477           0 :         return GetFirstChar();
     478           2 :     if( cChar >= GetLastChar() )
     479           0 :         return GetLastChar();
     480             : 
     481           2 :     int nRange = findRangeIndex( cChar + 1 );
     482           2 :     if( nRange & 1 )                       // outside of range?
     483           2 :         return mpImplFontCharMap->mpRangeCodes[ nRange + 1 ]; // => first in next range
     484           0 :     return (cChar + 1);
     485             : }
     486             : 
     487         560 : sal_UCS4 FontCharMap::GetPrevChar( sal_UCS4 cChar ) const
     488             : {
     489         560 :     if( cChar <= GetFirstChar() )
     490           0 :         return GetFirstChar();
     491         560 :     if( cChar > GetLastChar() )
     492           8 :         return GetLastChar();
     493             : 
     494         552 :     int nRange = findRangeIndex( cChar - 1 );
     495         552 :     if( nRange & 1 )                            // outside a range?
     496          20 :         return (mpImplFontCharMap->mpRangeCodes[ nRange ] - 1);    // => last in prev range
     497         532 :     return (cChar - 1);
     498             : }
     499             : 
     500           0 : int FontCharMap::GetIndexFromChar( sal_UCS4 cChar ) const
     501             : {
     502             :     // TODO: improve linear walk?
     503           0 :     int nCharIndex = 0;
     504           0 :     const sal_UCS4* pRange = &mpImplFontCharMap->mpRangeCodes[0];
     505           0 :     for( int i = 0; i < mpImplFontCharMap->mnRangeCount; ++i )
     506             :     {
     507           0 :         sal_UCS4 cFirst = *(pRange++);
     508           0 :         sal_UCS4 cLast  = *(pRange++);
     509           0 :         if( cChar >= cLast )
     510           0 :             nCharIndex += cLast - cFirst;
     511           0 :         else if( cChar >= cFirst )
     512           0 :             return nCharIndex + (cChar - cFirst);
     513             :         else
     514           0 :             break;
     515             :     }
     516             : 
     517           0 :     return -1;
     518             : }
     519             : 
     520           0 : sal_UCS4 FontCharMap::GetCharFromIndex( int nIndex ) const
     521             : {
     522             :     // TODO: improve linear walk?
     523           0 :     const sal_UCS4* pRange = &mpImplFontCharMap->mpRangeCodes[0];
     524           0 :     for( int i = 0; i < mpImplFontCharMap->mnRangeCount; ++i )
     525             :     {
     526           0 :         sal_UCS4 cFirst = *(pRange++);
     527           0 :         sal_UCS4 cLast  = *(pRange++);
     528           0 :         nIndex -= cLast - cFirst;
     529           0 :         if( nIndex < 0 )
     530           0 :             return (cLast + nIndex);
     531             :     }
     532             : 
     533             :     // we can only get here with an out-of-bounds charindex
     534           0 :     return mpImplFontCharMap->mpRangeCodes[0];
     535             : }
     536             : 
     537       84138 : int FontCharMap::findRangeIndex( sal_UCS4 cChar ) const
     538             : {
     539       84138 :     int nLower = 0;
     540       84138 :     int nMid   = mpImplFontCharMap->mnRangeCount;
     541       84138 :     int nUpper = 2 * mpImplFontCharMap->mnRangeCount - 1;
     542      822868 :     while( nLower < nUpper )
     543             :     {
     544      654592 :         if( cChar >= mpImplFontCharMap->mpRangeCodes[ nMid ] )
     545      220862 :             nLower = nMid;
     546             :         else
     547      433730 :             nUpper = nMid - 1;
     548      654592 :         nMid = (nLower + nUpper + 1) / 2;
     549             :     }
     550             : 
     551       84138 :     return nMid;
     552             : }
     553             : 
     554       83408 : int FontCharMap::GetGlyphIndex( sal_UCS4 cChar ) const
     555             : {
     556             :     // return -1 if the object doesn't know the glyph ids
     557       83408 :     if( !mpImplFontCharMap->mpStartGlyphs )
     558           0 :         return -1;
     559             : 
     560             :     // return 0 if the unicode doesn't have a matching glyph
     561       83408 :     int nRange = findRangeIndex( cChar );
     562             :     // check that we are inside any range
     563       83408 :     if( (nRange == 0) && (cChar < mpImplFontCharMap->mpRangeCodes[0]) ) {
     564             :         // symbol aliasing gives symbol fonts a second chance
     565           0 :         const bool bSymbolic = cChar <= 0xFF && (mpImplFontCharMap->mpRangeCodes[0]>=0xF000) &&
     566           0 :                                                 (mpImplFontCharMap->mpRangeCodes[1]<=0xF0FF);
     567           0 :         if( !bSymbolic )
     568           0 :             return 0;
     569             :         // check for symbol aliasing (U+F0xx -> U+00xx)
     570           0 :         cChar |= 0xF000;
     571           0 :         nRange = findRangeIndex( cChar );
     572           0 :         if( (nRange == 0) && (cChar < mpImplFontCharMap->mpRangeCodes[0]) ) {
     573           0 :             return 0;
     574             :         }
     575             :     }
     576             :     // check that we are inside a range
     577       83408 :     if( (nRange & 1) != 0 )
     578       40264 :         return 0;
     579             : 
     580             :     // get glyph index directly or indirectly
     581       43144 :     int nGlyphIndex = cChar - mpImplFontCharMap->mpRangeCodes[ nRange ];
     582       43144 :     const int nStartIndex = mpImplFontCharMap->mpStartGlyphs[ nRange/2 ];
     583       43144 :     if( nStartIndex >= 0 ) {
     584             :         // the glyph index can be calculated
     585       43140 :         nGlyphIndex += nStartIndex;
     586             :     } else {
     587             :         // the glyphid array has the glyph index
     588           4 :         nGlyphIndex = mpImplFontCharMap->mpGlyphIds[ nGlyphIndex - nStartIndex];
     589             :     }
     590             : 
     591       43144 :     return nGlyphIndex;
     592             : }
     593             : 
     594             : // on some systems we have to get the font attributes from the name table
     595             : // since neither head's macStyle nor OS/2's panose are easily available
     596             : // during font enumeration. macStyle bits would be not sufficient anyway
     597             : // and SFNT fonts on Mac usually do not contain an OS/2 table.
     598           0 : void UpdateAttributesFromPSName( const OUString& rPSName, ImplDevFontAttributes& rDFA )
     599             : {
     600           0 :     OString aPSName( OUStringToOString( rPSName, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() );
     601             : 
     602             :     // TODO: use a multi-string ignore-case matcher once it becomes available
     603           0 :     if( (aPSName.indexOf("regular") != -1)
     604           0 :     ||  (aPSName.indexOf("normal") != -1)
     605           0 :     ||  (aPSName.indexOf("roman") != -1)
     606           0 :     ||  (aPSName.indexOf("medium") != -1)
     607           0 :     ||  (aPSName.indexOf("plain") != -1)
     608           0 :     ||  (aPSName.indexOf("standard") != -1)
     609           0 :     ||  (aPSName.indexOf("std") != -1) )
     610             :     {
     611           0 :         rDFA.SetWidthType(WIDTH_NORMAL);
     612           0 :         rDFA.SetWeight(WEIGHT_NORMAL);
     613           0 :         rDFA.SetItalic(ITALIC_NONE);
     614             :     }
     615             : 
     616             :     // heuristics for font weight
     617           0 :     if (aPSName.indexOf("extrablack") != -1)
     618           0 :         rDFA.SetWeight(WEIGHT_BLACK);
     619           0 :     else if (aPSName.indexOf("black") != -1)
     620           0 :         rDFA.SetWeight(WEIGHT_BLACK);
     621           0 :     else if( (aPSName.indexOf("semibold") != -1)
     622           0 :     ||  (aPSName.indexOf("smbd") != -1))
     623           0 :         rDFA.SetWeight(WEIGHT_SEMIBOLD);
     624           0 :     else if (aPSName.indexOf("ultrabold") != -1)
     625           0 :         rDFA.SetWeight(WEIGHT_ULTRABOLD);
     626           0 :     else if (aPSName.indexOf("extrabold") != -1)
     627           0 :         rDFA.SetWeight(WEIGHT_BLACK);
     628           0 :     else if( (aPSName.indexOf("bold") != -1)
     629           0 :     ||  (aPSName.indexOf("-bd") != -1))
     630           0 :         rDFA.SetWeight(WEIGHT_BOLD);
     631           0 :     else if (aPSName.indexOf("extralight") != -1)
     632           0 :         rDFA.SetWeight(WEIGHT_ULTRALIGHT);
     633           0 :     else if (aPSName.indexOf("ultralight") != -1)
     634           0 :         rDFA.SetWeight(WEIGHT_ULTRALIGHT);
     635           0 :     else if (aPSName.indexOf("light") != -1)
     636           0 :         rDFA.SetWeight(WEIGHT_LIGHT);
     637           0 :     else if (aPSName.indexOf("thin") != -1)
     638           0 :         rDFA.SetWeight(WEIGHT_THIN);
     639           0 :     else if (aPSName.indexOf("-w3") != -1)
     640           0 :         rDFA.SetWeight(WEIGHT_LIGHT);
     641           0 :     else if (aPSName.indexOf("-w4") != -1)
     642           0 :         rDFA.SetWeight(WEIGHT_SEMILIGHT);
     643           0 :     else if (aPSName.indexOf("-w5") != -1)
     644           0 :         rDFA.SetWeight(WEIGHT_NORMAL);
     645           0 :     else if (aPSName.indexOf("-w6") != -1)
     646           0 :         rDFA.SetWeight(WEIGHT_SEMIBOLD);
     647           0 :     else if (aPSName.indexOf("-w7") != -1)
     648           0 :         rDFA.SetWeight(WEIGHT_BOLD);
     649           0 :     else if (aPSName.indexOf("-w8") != -1)
     650           0 :         rDFA.SetWeight(WEIGHT_ULTRABOLD);
     651           0 :     else if (aPSName.indexOf("-w9") != -1)
     652           0 :         rDFA.SetWeight(WEIGHT_BLACK);
     653             : 
     654             :     // heuristics for font slant
     655           0 :     if( (aPSName.indexOf("italic") != -1)
     656           0 :     ||  (aPSName.indexOf(" ital") != -1)
     657           0 :     ||  (aPSName.indexOf("cursive") != -1)
     658           0 :     ||  (aPSName.indexOf("-it") != -1)
     659           0 :     ||  (aPSName.indexOf("lightit") != -1)
     660           0 :     ||  (aPSName.indexOf("mediumit") != -1)
     661           0 :     ||  (aPSName.indexOf("boldit") != -1)
     662           0 :     ||  (aPSName.indexOf("cnit") != -1)
     663           0 :     ||  (aPSName.indexOf("bdcn") != -1)
     664           0 :     ||  (aPSName.indexOf("bdit") != -1)
     665           0 :     ||  (aPSName.indexOf("condit") != -1)
     666           0 :     ||  (aPSName.indexOf("bookit") != -1)
     667           0 :     ||  (aPSName.indexOf("blackit") != -1) )
     668           0 :         rDFA.SetItalic(ITALIC_NORMAL);
     669           0 :     if( (aPSName.indexOf("oblique") != -1)
     670           0 :     ||  (aPSName.indexOf("inclined") != -1)
     671           0 :     ||  (aPSName.indexOf("slanted") != -1) )
     672           0 :         rDFA.SetItalic(ITALIC_OBLIQUE);
     673             : 
     674             :     // heuristics for font width
     675           0 :     if( (aPSName.indexOf("condensed") != -1)
     676           0 :     ||  (aPSName.indexOf("-cond") != -1)
     677           0 :     ||  (aPSName.indexOf("boldcond") != -1)
     678           0 :     ||  (aPSName.indexOf("boldcn") != -1)
     679           0 :     ||  (aPSName.indexOf("cnit") != -1) )
     680           0 :         rDFA.SetWidthType(WIDTH_CONDENSED);
     681           0 :     else if (aPSName.indexOf("narrow") != -1)
     682           0 :         rDFA.SetWidthType(WIDTH_SEMI_CONDENSED);
     683           0 :     else if (aPSName.indexOf("expanded") != -1)
     684           0 :         rDFA.SetWidthType(WIDTH_EXPANDED);
     685           0 :     else if (aPSName.indexOf("wide") != -1)
     686           0 :         rDFA.SetWidthType(WIDTH_EXPANDED);
     687             : 
     688             :     // heuristics for font pitch
     689           0 :     if( (aPSName.indexOf("mono") != -1)
     690           0 :     ||  (aPSName.indexOf("courier") != -1)
     691           0 :     ||  (aPSName.indexOf("monaco") != -1)
     692           0 :     ||  (aPSName.indexOf("typewriter") != -1) )
     693           0 :         rDFA.SetPitch(PITCH_FIXED);
     694             : 
     695             :     // heuristics for font family type
     696           0 :     if( (aPSName.indexOf("script") != -1)
     697           0 :     ||  (aPSName.indexOf("chancery") != -1)
     698           0 :     ||  (aPSName.indexOf("zapfino") != -1))
     699           0 :         rDFA.SetFamilyType(FAMILY_SCRIPT);
     700           0 :     else if( (aPSName.indexOf("comic") != -1)
     701           0 :     ||  (aPSName.indexOf("outline") != -1)
     702           0 :     ||  (aPSName.indexOf("pinpoint") != -1) )
     703           0 :         rDFA.SetFamilyType(FAMILY_DECORATIVE);
     704           0 :     else if( (aPSName.indexOf("sans") != -1)
     705           0 :     ||  (aPSName.indexOf("arial") != -1) )
     706           0 :         rDFA.SetFamilyType(FAMILY_SWISS);
     707           0 :     else if( (aPSName.indexOf("roman") != -1)
     708           0 :     ||  (aPSName.indexOf("times") != -1) )
     709           0 :         rDFA.SetFamilyType(FAMILY_ROMAN);
     710             : 
     711             :     // heuristics for codepoint semantic
     712           0 :     if( (aPSName.indexOf("symbol") != -1)
     713           0 :     ||  (aPSName.indexOf("dings") != -1)
     714           0 :     ||  (aPSName.indexOf("dingbats") != -1)
     715           0 :     ||  (aPSName.indexOf("ornaments") != -1)
     716           0 :     ||  (aPSName.indexOf("embellishments") != -1) )
     717           0 :         rDFA.SetSymbolFlag(true);
     718             : 
     719             :    // #i100020# special heuristic for names with single-char styles
     720             :    // NOTE: we are checking name that hasn't been lower-cased
     721           0 :    if( rPSName.getLength() > 3 )
     722             :    {
     723           0 :         int i = rPSName.getLength();
     724           0 :         sal_Unicode c = rPSName[--i];
     725           0 :         if( c == 'C' ) { // "capitals"
     726           0 :             rDFA.SetFamilyType(FAMILY_DECORATIVE);
     727           0 :             c = rPSName[--i];
     728             :         }
     729           0 :         if( c == 'O' ) { // CFF-based OpenType
     730           0 :             c = rPSName[--i];
     731             :         }
     732           0 :         if( c == 'I' ) { // "italic"
     733           0 :             rDFA.SetItalic(ITALIC_NORMAL);
     734           0 :             c = rPSName[--i];
     735             :         }
     736           0 :         if( c == 'B' )   // "bold"
     737           0 :             rDFA.SetWeight(WEIGHT_BOLD);
     738           0 :         if( c == 'C' )   // "capitals"
     739           0 :             rDFA.SetFamilyType(FAMILY_DECORATIVE);
     740             :         // TODO: check that all single-char styles have been resolved?
     741           0 :     }
     742        1233 : }
     743             : 
     744             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10