1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 #include "sft.hxx" 32 33 #include "gsub.h" 34 35 #include <osl/diagnose.h> 36 37 #include <vector> 38 #include <map> 39 #include <algorithm> 40 41 namespace vcl 42 { 43 44 typedef sal_uIntPtr sal_uLong; 45 typedef sal_uInt8 FT_Byte; 46 47 typedef std::map<sal_uInt16,sal_uInt16> GlyphSubstitution; 48 49 50 inline long NEXT_Long( const unsigned char* &p ) 51 { 52 long nVal = (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; 53 p += 4; 54 return nVal; 55 } 56 57 inline sal_uInt16 NEXT_UShort( const unsigned char* &p ) 58 { 59 sal_uInt16 nVal = (p[0]<<8) + p[1]; 60 p += 2; 61 return nVal; 62 } 63 64 #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3]) 65 66 int ReadGSUB( struct _TrueTypeFont* pTTFile, 67 int nRequestedScript, int nRequestedLangsys ) 68 { 69 const FT_Byte* pGsubBase = (FT_Byte*)pTTFile->tables[ O_gsub ]; 70 if( !pGsubBase ) 71 return -1; 72 73 // #129682# check offsets inside GSUB table 74 const FT_Byte* pGsubLimit = pGsubBase + pTTFile->tlens[ O_gsub ]; 75 76 // parse GSUB header 77 const FT_Byte* pGsubHeader = pGsubBase; 78 const sal_uLong nVersion = NEXT_Long( pGsubHeader ); 79 const sal_uInt16 nOfsScriptList = NEXT_UShort( pGsubHeader ); 80 const sal_uInt16 nOfsFeatureTable = NEXT_UShort( pGsubHeader ); 81 const sal_uInt16 nOfsLookupList = NEXT_UShort( pGsubHeader ); 82 83 // sanity check the GSUB header 84 if( nVersion != 0x00010000 ) 85 if( nVersion != 0x00001000 ) // workaround for SunBatang etc. 86 return -1; // unknown format or broken 87 88 typedef std::vector<sal_uLong> ReqFeatureTagList; 89 ReqFeatureTagList aReqFeatureTagList; 90 91 aReqFeatureTagList.push_back( MKTAG("vert") ); 92 93 typedef std::vector<sal_uInt16> UshortList; 94 UshortList aFeatureIndexList; 95 UshortList aFeatureOffsetList; 96 97 // parse Script Table 98 const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList; 99 const sal_uInt16 nCntScript = NEXT_UShort( pScriptHeader ); 100 if( pGsubLimit < pScriptHeader + 6 * nCntScript ) 101 return false; 102 for( sal_uInt16 nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex ) 103 { 104 const sal_uLong nTag = NEXT_Long( pScriptHeader ); // e.g. hani/arab/kana/hang 105 const sal_uInt16 nOfsScriptTable= NEXT_UShort( pScriptHeader ); 106 if( (nTag != (sal_uInt16)nRequestedScript) && (nRequestedScript != 0) ) 107 continue; 108 109 const FT_Byte* pScriptTable = pGsubBase + nOfsScriptList + nOfsScriptTable; 110 if( pGsubLimit < pScriptTable + 4 ) 111 return false; 112 const sal_uInt16 nDefaultLangsysOfs = NEXT_UShort( pScriptTable ); 113 const sal_uInt16 nCntLangSystem = NEXT_UShort( pScriptTable ); 114 sal_uInt16 nLangsysOffset = 0; 115 if( pGsubLimit < pScriptTable + 6 * nCntLangSystem ) 116 return false; 117 for( sal_uInt16 nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex ) 118 { 119 const sal_uLong nInnerTag = NEXT_Long( pScriptTable ); // e.g. KOR/ZHS/ZHT/JAN 120 const sal_uInt16 nOffset= NEXT_UShort( pScriptTable ); 121 if( (nInnerTag != (sal_uInt16)nRequestedLangsys) && (nRequestedLangsys != 0) ) 122 continue; 123 nLangsysOffset = nOffset; 124 break; 125 } 126 127 if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) ) 128 { 129 const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs; 130 if( pGsubLimit < pLangSys + 6 ) 131 return false; 132 /*const sal_uInt16 nLookupOrder =*/ NEXT_UShort( pLangSys ); 133 const sal_uInt16 nReqFeatureIdx = NEXT_UShort( pLangSys ); 134 const sal_uInt16 nCntFeature = NEXT_UShort( pLangSys ); 135 if( pGsubLimit < pLangSys + 2 * nCntFeature ) 136 return false; 137 aFeatureIndexList.push_back( nReqFeatureIdx ); 138 for( sal_uInt16 i = 0; i < nCntFeature; ++i ) 139 { 140 const sal_uInt16 nFeatureIndex = NEXT_UShort( pLangSys ); 141 aFeatureIndexList.push_back( nFeatureIndex ); 142 } 143 } 144 145 if( nLangsysOffset != 0 ) 146 { 147 const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset; 148 if( pGsubLimit < pLangSys + 6 ) 149 return false; 150 /*const sal_uInt16 nLookupOrder =*/ NEXT_UShort( pLangSys ); 151 const sal_uInt16 nReqFeatureIdx = NEXT_UShort( pLangSys ); 152 const sal_uInt16 nCntFeature = NEXT_UShort( pLangSys ); 153 if( pGsubLimit < pLangSys + 2 * nCntFeature ) 154 return false; 155 aFeatureIndexList.push_back( nReqFeatureIdx ); 156 for( sal_uInt16 i = 0; i < nCntFeature; ++i ) 157 { 158 const sal_uInt16 nFeatureIndex = NEXT_UShort( pLangSys ); 159 aFeatureIndexList.push_back( nFeatureIndex ); 160 } 161 } 162 } 163 164 if( !aFeatureIndexList.size() ) 165 return true; 166 167 UshortList aLookupIndexList; 168 UshortList aLookupOffsetList; 169 170 // parse Feature Table 171 const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable; 172 if( pGsubLimit < pFeatureHeader + 2 ) 173 return false; 174 const sal_uInt16 nCntFeature = NEXT_UShort( pFeatureHeader ); 175 if( pGsubLimit < pFeatureHeader + 6 * nCntFeature ) 176 return false; 177 for( sal_uInt16 nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex ) 178 { 179 const sal_uLong nTag = NEXT_Long( pFeatureHeader ); // e.g. locl/vert/trad/smpl/liga/fina/... 180 const sal_uInt16 nOffset= NEXT_UShort( pFeatureHeader ); 181 182 // ignore unneeded feature lookups 183 if( aFeatureIndexList[0] != nFeatureIndex ) // do not ignore the required feature 184 { 185 const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex); 186 if( !nRequested ) // ignore features that are not requested 187 continue; 188 const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag); 189 if( !nAvailable ) // some fonts don't provide features they request! 190 continue; 191 } 192 193 const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset; 194 if( pGsubLimit < pFeatureTable + 2 ) 195 return false; 196 const sal_uInt16 nCntLookups = NEXT_UShort( pFeatureTable ); 197 if( pGsubLimit < pFeatureTable + 2 * nCntLookups ) 198 return false; 199 for( sal_uInt16 i = 0; i < nCntLookups; ++i ) 200 { 201 const sal_uInt16 nLookupIndex = NEXT_UShort( pFeatureTable ); 202 aLookupIndexList.push_back( nLookupIndex ); 203 } 204 if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/... 205 aLookupIndexList.push_back( 0 ); 206 } 207 208 // parse Lookup List 209 const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList; 210 if( pGsubLimit < pLookupHeader + 2 ) 211 return false; 212 const sal_uInt16 nCntLookupTable = NEXT_UShort( pLookupHeader ); 213 if( pGsubLimit < pLookupHeader + 2 * nCntLookupTable ) 214 return false; 215 for( sal_uInt16 nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx ) 216 { 217 const sal_uInt16 nOffset = NEXT_UShort( pLookupHeader ); 218 if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) ) 219 aLookupOffsetList.push_back( nOffset ); 220 } 221 222 UshortList::const_iterator it = aLookupOffsetList.begin(); 223 for(; it != aLookupOffsetList.end(); ++it ) 224 { 225 const sal_uInt16 nOfsLookupTable = *it; 226 const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable; 227 if( pGsubLimit < pLookupTable + 6 ) 228 return false; 229 const sal_uInt16 eLookupType = NEXT_UShort( pLookupTable ); 230 /*const sal_uInt16 eLookupFlag =*/ NEXT_UShort( pLookupTable ); 231 const sal_uInt16 nCntLookupSubtable = NEXT_UShort( pLookupTable ); 232 233 // TODO: switch( eLookupType ) 234 if( eLookupType != 1 ) // TODO: once we go beyond SingleSubst 235 continue; 236 237 if( pGsubLimit < pLookupTable + 2 * nCntLookupSubtable ) 238 return false; 239 for( sal_uInt16 nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx ) 240 { 241 const sal_uInt16 nOfsSubLookupTable = NEXT_UShort( pLookupTable ); 242 const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable; 243 if( pGsubLimit < pSubLookup + 6 ) 244 return false; 245 const sal_uInt16 nFmtSubstitution = NEXT_UShort( pSubLookup ); 246 const sal_uInt16 nOfsCoverage = NEXT_UShort( pSubLookup ); 247 248 typedef std::pair<sal_uInt16,sal_uInt16> GlyphSubst; 249 typedef std::vector<GlyphSubst> SubstVector; 250 SubstVector aSubstVector; 251 252 const FT_Byte* pCoverage = pGsubBase 253 + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage; 254 if( pGsubLimit < pCoverage + 4 ) 255 return false; 256 const sal_uInt16 nFmtCoverage = NEXT_UShort( pCoverage ); 257 switch( nFmtCoverage ) 258 { 259 case 1: // Coverage Format 1 260 { 261 const sal_uInt16 nCntGlyph = NEXT_UShort( pCoverage ); 262 if( pGsubLimit < pCoverage + 2 * nCntGlyph ) 263 // TODO? nCntGlyph = (pGsubLimit - pCoverage) / 2; 264 return false; 265 aSubstVector.reserve( nCntGlyph ); 266 for( sal_uInt16 i = 0; i < nCntGlyph; ++i ) 267 { 268 const sal_uInt16 nGlyphId = NEXT_UShort( pCoverage ); 269 aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) ); 270 } 271 } 272 break; 273 274 case 2: // Coverage Format 2 275 { 276 const sal_uInt16 nCntRange = NEXT_UShort( pCoverage ); 277 if( pGsubLimit < pCoverage + 6 * nCntRange ) 278 // TODO? nCntGlyph = (pGsubLimit - pCoverage) / 6; 279 return false; 280 for( int i = nCntRange; --i >= 0; ) 281 { 282 const sal_uInt32 nGlyph0 = NEXT_UShort( pCoverage ); 283 const sal_uInt32 nGlyph1 = NEXT_UShort( pCoverage ); 284 const sal_uInt16 nCovIdx = NEXT_UShort( pCoverage ); 285 for( sal_uInt32 j = nGlyph0; j <= nGlyph1; ++j ) 286 aSubstVector.push_back( GlyphSubst( static_cast<sal_uInt16>(j + nCovIdx), 0 ) ); 287 } 288 } 289 break; 290 } 291 292 SubstVector::iterator subst_it( aSubstVector.begin() ); 293 294 switch( nFmtSubstitution ) 295 { 296 case 1: // Single Substitution Format 1 297 { 298 const sal_uInt16 nDeltaGlyphId = NEXT_UShort( pSubLookup ); 299 300 for(; subst_it != aSubstVector.end(); ++subst_it ) 301 (*subst_it).second = (*subst_it).first + nDeltaGlyphId; 302 } 303 break; 304 305 case 2: // Single Substitution Format 2 306 { 307 const sal_uInt16 nCntGlyph = NEXT_UShort( pSubLookup ); 308 for( int i = nCntGlyph; (subst_it != aSubstVector.end()) && (--i>=0); ++subst_it ) 309 { 310 if( pGsubLimit < pSubLookup + 2 ) 311 return false; 312 const sal_uInt16 nGlyphId = NEXT_UShort( pSubLookup ); 313 (*subst_it).second = nGlyphId; 314 } 315 } 316 break; 317 } 318 319 // now apply the glyph substitutions that have been collected in this subtable 320 if( aSubstVector.size() > 0 ) 321 { 322 GlyphSubstitution* pGSubstitution = new GlyphSubstitution; 323 pTTFile->pGSubstitution = (void*)pGSubstitution; 324 for( subst_it = aSubstVector.begin(); subst_it != aSubstVector.end(); ++subst_it ) 325 (*pGSubstitution)[ (*subst_it).first ] = (*subst_it).second; 326 } 327 } 328 } 329 return true; 330 } 331 332 void ReleaseGSUB(struct _TrueTypeFont* pTTFile) 333 { 334 GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution; 335 if( pGlyphSubstitution ) 336 delete pGlyphSubstitution; 337 } 338 339 int UseGSUB( struct _TrueTypeFont* pTTFile, int nGlyph, int /*wmode*/ ) 340 { 341 GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution; 342 if( pGlyphSubstitution != 0 ) 343 { 344 GlyphSubstitution::const_iterator it( pGlyphSubstitution->find( sal::static_int_cast<sal_uInt16>(nGlyph) ) ); 345 if( it != pGlyphSubstitution->end() ) 346 nGlyph = (*it).second; 347 } 348 349 return nGlyph; 350 } 351 352 int HasVerticalGSUB( struct _TrueTypeFont* pTTFile ) 353 { 354 GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution; 355 return pGlyphSubstitution ? +1 : 0; 356 } 357 358 } 359