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

Generated by: LCOV version 1.11