LCOV - code coverage report
Current view: top level - vcl/source/fontsubset - gsub.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 147 194 75.8 %
Date: 2012-08-25 Functions: 5 6 83.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 113 222 50.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 "sft.hxx"
      31                 :            : 
      32                 :            : #include "gsub.h"
      33                 :            : 
      34                 :            : #include <osl/diagnose.h>
      35                 :            : 
      36                 :            : #include <vector>
      37                 :            : #include <map>
      38                 :            : #include <algorithm>
      39                 :            : 
      40                 :            : namespace vcl
      41                 :            : {
      42                 :            : 
      43                 :            : typedef sal_uIntPtr sal_uLong;
      44                 :            : typedef sal_uInt8 FT_Byte;
      45                 :            : 
      46                 :            : typedef std::map<sal_uInt16,sal_uInt16> GlyphSubstitution;
      47                 :            : 
      48                 :            : 
      49                 :     147041 : inline sal_uInt32 NEXT_Long( const unsigned char* &p )
      50                 :            : {
      51                 :     147041 :     sal_uInt32 nVal = (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
      52                 :     147041 :     p += 4;
      53                 :     147041 :     return nVal;
      54                 :            : }
      55                 :            : 
      56                 :     756634 : inline sal_uInt16 NEXT_UShort( const unsigned char* &p )
      57                 :            : {
      58                 :     756634 :     sal_uInt16 nVal = (p[0]<<8) + p[1];
      59                 :     756634 :     p += 2;
      60                 :     756634 :     return nVal;
      61                 :            : }
      62                 :            : 
      63                 :            : #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
      64                 :            : 
      65                 :       8655 : int ReadGSUB( struct _TrueTypeFont* pTTFile,
      66                 :            :     int nRequestedScript, int nRequestedLangsys )
      67                 :            : {
      68                 :       8655 :     const FT_Byte* pGsubBase = (FT_Byte*)pTTFile->tables[ O_gsub ];
      69         [ +  + ]:       8655 :     if( !pGsubBase )
      70                 :        486 :         return -1;
      71                 :            : 
      72                 :            :     // #129682# check offsets inside GSUB table
      73                 :       8169 :     const FT_Byte* pGsubLimit = pGsubBase + pTTFile->tlens[ O_gsub ];
      74                 :            : 
      75                 :            :     // parse GSUB header
      76                 :       8169 :     const FT_Byte* pGsubHeader = pGsubBase;
      77                 :       8169 :     const sal_uLong nVersion            = NEXT_Long( pGsubHeader );
      78                 :       8169 :     const sal_uInt16 nOfsScriptList     = NEXT_UShort( pGsubHeader );
      79                 :       8169 :     const sal_uInt16 nOfsFeatureTable   = NEXT_UShort( pGsubHeader );
      80                 :       8169 :     const sal_uInt16 nOfsLookupList     = NEXT_UShort( pGsubHeader );
      81                 :            : 
      82                 :            :     // sanity check the GSUB header
      83         [ -  + ]:       8169 :     if( nVersion != 0x00010000 )
      84         [ #  # ]:          0 :         if( nVersion != 0x00001000 )    // workaround for SunBatang etc.
      85                 :          0 :             return -1;                  // unknown format or broken
      86                 :            : 
      87                 :            :     typedef std::vector<sal_uLong> ReqFeatureTagList;
      88         [ +  - ]:       8169 :     ReqFeatureTagList aReqFeatureTagList;
      89                 :            : 
      90         [ +  - ]:       8169 :     aReqFeatureTagList.push_back( MKTAG("vert") );
      91                 :            : 
      92                 :            :     typedef std::vector<sal_uInt16> UshortList;
      93         [ +  - ]:       8169 :     UshortList aFeatureIndexList;
      94                 :            : 
      95                 :            :     // parse Script Table
      96                 :       8169 :     const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList;
      97                 :       8169 :     const sal_uInt16 nCntScript = NEXT_UShort( pScriptHeader );
      98         [ -  + ]:       8169 :     if( pGsubLimit < pScriptHeader + 6 * nCntScript )
      99                 :          0 :         return false;
     100         [ +  + ]:      50301 :     for( sal_uInt16 nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex )
     101                 :            :     {
     102                 :      42132 :         const sal_uLong nTag            = NEXT_Long( pScriptHeader ); // e.g. hani/arab/kana/hang
     103                 :      42132 :         const sal_uInt16 nOfsScriptTable= NEXT_UShort( pScriptHeader );
     104 [ -  + ][ +  - ]:      42132 :         if( (nTag != (sal_uInt16)nRequestedScript) && (nRequestedScript != 0) )
     105                 :          0 :             continue;
     106                 :            : 
     107                 :      42132 :         const FT_Byte* pScriptTable     = pGsubBase + nOfsScriptList + nOfsScriptTable;
     108         [ -  + ]:      42132 :         if( pGsubLimit < pScriptTable + 4 )
     109                 :          0 :             return false;
     110                 :      42132 :         const sal_uInt16 nDefaultLangsysOfs = NEXT_UShort( pScriptTable );
     111                 :      42132 :         const sal_uInt16 nCntLangSystem     = NEXT_UShort( pScriptTable );
     112                 :      42132 :         sal_uInt16 nLangsysOffset = 0;
     113         [ -  + ]:      42132 :         if( pGsubLimit < pScriptTable + 6 * nCntLangSystem )
     114                 :          0 :             return false;
     115         [ +  + ]:      42132 :         for( sal_uInt16 nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex )
     116                 :            :         {
     117                 :       9297 :             const sal_uLong nInnerTag = NEXT_Long( pScriptTable );    // e.g. KOR/ZHS/ZHT/JAN
     118                 :       9297 :             const sal_uInt16 nOffset= NEXT_UShort( pScriptTable );
     119 [ -  + ][ +  - ]:       9297 :             if( (nInnerTag != (sal_uInt16)nRequestedLangsys) && (nRequestedLangsys != 0) )
     120                 :          0 :                 continue;
     121                 :       9297 :             nLangsysOffset = nOffset;
     122                 :       9297 :             break;
     123                 :            :         }
     124                 :            : 
     125 [ +  + ][ +  + ]:      42132 :         if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) )
     126                 :            :         {
     127                 :      39663 :             const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs;
     128         [ -  + ]:      39663 :             if( pGsubLimit < pLangSys + 6 )
     129                 :          0 :                 return false;
     130                 :      39663 :             /*const sal_uInt16 nLookupOrder   =*/ NEXT_UShort( pLangSys );
     131                 :      39663 :             const sal_uInt16 nReqFeatureIdx = NEXT_UShort( pLangSys );
     132                 :      39663 :             const sal_uInt16 nCntFeature    = NEXT_UShort( pLangSys );
     133         [ -  + ]:      39663 :             if( pGsubLimit < pLangSys + 2 * nCntFeature )
     134                 :          0 :                 return false;
     135         [ +  - ]:      39663 :             aFeatureIndexList.push_back( nReqFeatureIdx );
     136         [ +  + ]:     172667 :             for( sal_uInt16 i = 0; i < nCntFeature; ++i )
     137                 :            :             {
     138                 :     133004 :                 const sal_uInt16 nFeatureIndex = NEXT_UShort( pLangSys );
     139         [ +  - ]:     133004 :                 aFeatureIndexList.push_back( nFeatureIndex );
     140                 :            :             }
     141                 :            :         }
     142                 :            : 
     143         [ +  + ]:      42132 :         if( nLangsysOffset != 0 )
     144                 :            :         {
     145                 :       9297 :             const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset;
     146         [ -  + ]:       9297 :             if( pGsubLimit < pLangSys + 6 )
     147                 :          0 :                 return false;
     148                 :       9297 :             /*const sal_uInt16 nLookupOrder   =*/ NEXT_UShort( pLangSys );
     149                 :       9297 :             const sal_uInt16 nReqFeatureIdx = NEXT_UShort( pLangSys );
     150                 :       9297 :             const sal_uInt16 nCntFeature    = NEXT_UShort( pLangSys );
     151         [ -  + ]:       9297 :             if( pGsubLimit < pLangSys + 2 * nCntFeature )
     152                 :          0 :                 return false;
     153         [ +  - ]:       9297 :             aFeatureIndexList.push_back( nReqFeatureIdx );
     154         [ +  + ]:      87087 :             for( sal_uInt16 i = 0; i < nCntFeature; ++i )
     155                 :            :             {
     156                 :      44955 :                 const sal_uInt16 nFeatureIndex = NEXT_UShort( pLangSys );
     157         [ +  - ]:      44955 :                 aFeatureIndexList.push_back( nFeatureIndex );
     158                 :            :             }
     159                 :            :         }
     160                 :            :     }
     161                 :            : 
     162         [ -  + ]:       8169 :     if( aFeatureIndexList.empty() )
     163                 :          0 :         return true;
     164                 :            : 
     165         [ +  - ]:       8169 :     UshortList aLookupIndexList;
     166         [ +  - ]:       8169 :     UshortList aLookupOffsetList;
     167                 :            : 
     168                 :            :     // parse Feature Table
     169                 :       8169 :     const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable;
     170         [ -  + ]:       8169 :     if( pGsubLimit < pFeatureHeader + 2 )
     171                 :          0 :           return false;
     172                 :       8169 :     const sal_uInt16 nCntFeature = NEXT_UShort( pFeatureHeader );
     173         [ -  + ]:       8169 :     if( pGsubLimit < pFeatureHeader + 6 * nCntFeature )
     174                 :          0 :           return false;
     175         [ +  + ]:      95612 :     for( sal_uInt16 nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex )
     176                 :            :     {
     177                 :      87443 :         const sal_uLong nTag    = NEXT_Long( pFeatureHeader ); // e.g. locl/vert/trad/smpl/liga/fina/...
     178                 :      87443 :         const sal_uInt16 nOffset= NEXT_UShort( pFeatureHeader );
     179                 :            : 
     180                 :            :         // ignore unneeded feature lookups
     181 [ +  + ][ +  - ]:      87443 :         if( aFeatureIndexList[0] != nFeatureIndex ) // do not ignore the required feature
     182                 :            :         {
     183         [ +  - ]:      86981 :             const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex);
     184         [ +  + ]:      86981 :             if( !nRequested )   // ignore features that are not requested
     185                 :      11204 :                 continue;
     186         [ +  - ]:      75777 :             const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag);
     187         [ +  + ]:      75777 :             if( !nAvailable )   // some fonts don't provide features they request!
     188                 :      75437 :                 continue;
     189                 :            :         }
     190                 :            : 
     191                 :        802 :         const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset;
     192         [ -  + ]:        802 :         if( pGsubLimit < pFeatureTable + 2 )
     193                 :          0 :             return false;
     194                 :        802 :         const sal_uInt16 nCntLookups = NEXT_UShort( pFeatureTable );
     195         [ -  + ]:        802 :         if( pGsubLimit < pFeatureTable + 2 * nCntLookups )
     196                 :          0 :             return false;
     197         [ -  + ]:        802 :         for( sal_uInt16 i = 0; i < nCntLookups; ++i )
     198                 :            :         {
     199                 :          0 :             const sal_uInt16 nLookupIndex = NEXT_UShort( pFeatureTable );
     200         [ #  # ]:          0 :             aLookupIndexList.push_back( nLookupIndex );
     201                 :            :         }
     202         [ +  - ]:        802 :         if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
     203         [ +  - ]:      87443 :             aLookupIndexList.push_back( 0 );
     204                 :            :     }
     205                 :            : 
     206                 :            :     // parse Lookup List
     207                 :       8169 :     const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList;
     208         [ -  + ]:       8169 :     if( pGsubLimit < pLookupHeader + 2 )
     209                 :          0 :         return false;
     210                 :       8169 :     const sal_uInt16 nCntLookupTable = NEXT_UShort( pLookupHeader );
     211         [ -  + ]:       8169 :     if( pGsubLimit < pLookupHeader + 2 * nCntLookupTable )
     212                 :          0 :         return false;
     213         [ +  + ]:     159438 :     for( sal_uInt16 nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx )
     214                 :            :     {
     215                 :     151269 :         const sal_uInt16 nOffset = NEXT_UShort( pLookupHeader );
     216 [ +  + ][ +  - ]:     151269 :         if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) )
     217         [ +  - ]:        802 :             aLookupOffsetList.push_back( nOffset );
     218                 :            :     }
     219                 :            : 
     220         [ +  - ]:       8169 :     UshortList::const_iterator it = aLookupOffsetList.begin();
     221 [ +  - ][ +  - ]:       8971 :     for(; it != aLookupOffsetList.end(); ++it )
                 [ +  + ]
     222                 :            :     {
     223         [ +  - ]:        802 :         const sal_uInt16 nOfsLookupTable = *it;
     224                 :        802 :         const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable;
     225         [ -  + ]:        802 :         if( pGsubLimit < pLookupTable + 6 )
     226                 :          0 :             return false;
     227                 :        802 :         const sal_uInt16 eLookupType        = NEXT_UShort( pLookupTable );
     228                 :        802 :         /*const sal_uInt16 eLookupFlag        =*/ NEXT_UShort( pLookupTable );
     229                 :        802 :         const sal_uInt16 nCntLookupSubtable = NEXT_UShort( pLookupTable );
     230                 :            : 
     231                 :            :         // TODO: switch( eLookupType )
     232         [ +  + ]:        802 :         if( eLookupType != 1 )  // TODO: once we go beyond SingleSubst
     233                 :        734 :             continue;
     234                 :            : 
     235         [ -  + ]:         68 :         if( pGsubLimit < pLookupTable + 2 * nCntLookupSubtable )
     236                 :          0 :             return false;
     237         [ +  + ]:        136 :         for( sal_uInt16 nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx )
     238                 :            :         {
     239                 :         68 :             const sal_uInt16 nOfsSubLookupTable = NEXT_UShort( pLookupTable );
     240                 :         68 :             const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable;
     241         [ -  + ]:         68 :             if( pGsubLimit < pSubLookup + 6 )
     242                 :          0 :                 return false;
     243                 :         68 :             const sal_uInt16 nFmtSubstitution   = NEXT_UShort( pSubLookup );
     244                 :         68 :             const sal_uInt16 nOfsCoverage       = NEXT_UShort( pSubLookup );
     245                 :            : 
     246                 :            :             typedef std::pair<sal_uInt16,sal_uInt16> GlyphSubst;
     247                 :            :             typedef std::vector<GlyphSubst> SubstVector;
     248         [ +  - ]:         68 :             SubstVector aSubstVector;
     249                 :            : 
     250                 :            :             const FT_Byte* pCoverage    = pGsubBase
     251                 :         68 :                 + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage;
     252         [ -  + ]:         68 :             if( pGsubLimit < pCoverage + 4 )
     253                 :          0 :                 return false;
     254                 :         68 :             const sal_uInt16 nFmtCoverage   = NEXT_UShort( pCoverage );
     255      [ +  -  - ]:         68 :             switch( nFmtCoverage )
     256                 :            :             {
     257                 :            :                 case 1:         // Coverage Format 1
     258                 :            :                 {
     259                 :         68 :                     const sal_uInt16 nCntGlyph = NEXT_UShort( pCoverage );
     260         [ -  + ]:         68 :                     if( pGsubLimit < pCoverage + 2 * nCntGlyph )
     261                 :            :                         // TODO? nCntGlyph = (pGsubLimit - pCoverage) / 2;
     262                 :          0 :                         return false;
     263         [ +  - ]:         68 :                     aSubstVector.reserve( nCntGlyph );
     264         [ +  + ]:       2448 :                     for( sal_uInt16 i = 0; i < nCntGlyph; ++i )
     265                 :            :                     {
     266                 :       2380 :                         const sal_uInt16 nGlyphId = NEXT_UShort( pCoverage );
     267 [ +  - ][ +  - ]:       2380 :                         aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) );
     268                 :            :                     }
     269                 :            :                 }
     270                 :         68 :                 break;
     271                 :            : 
     272                 :            :                 case 2:         // Coverage Format 2
     273                 :            :                 {
     274                 :          0 :                     const sal_uInt16 nCntRange = NEXT_UShort( pCoverage );
     275         [ #  # ]:          0 :                     if( pGsubLimit < pCoverage + 6 * nCntRange )
     276                 :            :                         // TODO? nCntGlyph = (pGsubLimit - pCoverage) / 6;
     277                 :          0 :                         return false;
     278         [ #  # ]:          0 :                     for( int i = nCntRange; --i >= 0; )
     279                 :            :                     {
     280                 :          0 :                         const sal_uInt32 nGlyph0 = NEXT_UShort( pCoverage );
     281                 :          0 :                         const sal_uInt32 nGlyph1 = NEXT_UShort( pCoverage );
     282                 :          0 :                         const sal_uInt16 nCovIdx = NEXT_UShort( pCoverage );
     283         [ #  # ]:          0 :                         for( sal_uInt32 j = nGlyph0; j <= nGlyph1; ++j )
     284 [ #  # ][ #  # ]:          0 :                             aSubstVector.push_back( GlyphSubst( static_cast<sal_uInt16>(j + nCovIdx), 0 ) );
     285                 :            :                     }
     286                 :            :                 }
     287                 :          0 :                 break;
     288                 :            :             }
     289                 :            : 
     290                 :         68 :             SubstVector::iterator subst_it( aSubstVector.begin() );
     291                 :            : 
     292      [ -  +  - ]:         68 :             switch( nFmtSubstitution )
     293                 :            :             {
     294                 :            :                 case 1:     // Single Substitution Format 1
     295                 :            :                 {
     296                 :          0 :                     const sal_uInt16 nDeltaGlyphId = NEXT_UShort( pSubLookup );
     297                 :            : 
     298 [ #  # ][ #  # ]:          0 :                     for(; subst_it != aSubstVector.end(); ++subst_it )
                 [ #  # ]
     299 [ #  # ][ #  # ]:          0 :                         (*subst_it).second = (*subst_it).first + nDeltaGlyphId;
     300                 :            :                 }
     301                 :          0 :                 break;
     302                 :            : 
     303                 :            :                 case 2:     // Single Substitution Format 2
     304                 :            :                 {
     305                 :         68 :                     const sal_uInt16 nCntGlyph = NEXT_UShort( pSubLookup );
     306 [ +  - ][ +  - ]:       2448 :                     for( int i = nCntGlyph; (subst_it != aSubstVector.end()) && (--i>=0); ++subst_it )
         [ +  + ][ +  - ]
                 [ +  - ]
           [ +  +  #  # ]
     307                 :            :                     {
     308         [ -  + ]:       2380 :                         if( pGsubLimit < pSubLookup + 2 )
     309                 :          0 :                             return false;
     310                 :       2380 :                         const sal_uInt16 nGlyphId = NEXT_UShort( pSubLookup );
     311         [ +  - ]:       2380 :                         (*subst_it).second = nGlyphId;
     312                 :            :                     }
     313                 :            :                 }
     314                 :         68 :                 break;
     315                 :            :             }
     316                 :            : 
     317                 :            :             // now apply the glyph substitutions that have been collected in this subtable
     318         [ +  - ]:         68 :             if( !aSubstVector.empty() )
     319                 :            :             {
     320 [ +  - ][ +  - ]:         68 :                 GlyphSubstitution* pGSubstitution = new GlyphSubstitution;
     321                 :         68 :                 pTTFile->pGSubstitution = (void*)pGSubstitution;
     322 [ +  - ][ +  - ]:       2448 :                 for( subst_it = aSubstVector.begin(); subst_it != aSubstVector.end(); ++subst_it )
                 [ +  + ]
     323 [ +  - ][ +  - ]:       2380 :                     (*pGSubstitution)[ (*subst_it).first ] =  (*subst_it).second;
                 [ +  - ]
     324                 :            :             }
     325         [ +  - ]:         68 :         }
     326                 :            :     }
     327                 :       8655 :     return true;
     328                 :            : }
     329                 :            : 
     330                 :       8655 : void ReleaseGSUB(struct _TrueTypeFont* pTTFile)
     331                 :            : {
     332                 :       8655 :     GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution;
     333         [ +  + ]:       8655 :     if( pGlyphSubstitution )
     334         [ +  - ]:         68 :         delete pGlyphSubstitution;
     335                 :       8655 : }
     336                 :            : 
     337                 :          0 : int UseGSUB( struct _TrueTypeFont* pTTFile, int nGlyph, int /*wmode*/ )
     338                 :            : {
     339                 :          0 :     GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution;
     340         [ #  # ]:          0 :     if( pGlyphSubstitution != 0 )
     341                 :            :     {
     342 [ #  # ][ #  # ]:          0 :         GlyphSubstitution::const_iterator it( pGlyphSubstitution->find( sal::static_int_cast<sal_uInt16>(nGlyph) ) );
     343 [ #  # ][ #  # ]:          0 :         if( it != pGlyphSubstitution->end() )
                 [ #  # ]
     344         [ #  # ]:          0 :             nGlyph = (*it).second;
     345                 :            :     }
     346                 :            : 
     347                 :          0 :     return nGlyph;
     348                 :            : }
     349                 :            : 
     350                 :       8655 : int HasVerticalGSUB( struct _TrueTypeFont* pTTFile )
     351                 :            : {
     352                 :       8655 :     GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution;
     353         [ +  + ]:       8655 :     return pGlyphSubstitution ? +1 : 0;
     354                 :            : }
     355                 :            : 
     356                 :            : }
     357                 :            : 
     358                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10