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