PageRenderTime 102ms CodeModel.GetById 28ms RepoModel.GetById 6ms app.codeStats 0ms

/vcl/source/fontsubset/gsub.cxx

https://bitbucket.org/markjenkins/libreoffice_ubuntu-debian-fixes
C++ | 349 lines | 273 code | 46 blank | 30 comment | 75 complexity | 75383746b60f3d3156ac0f0e729c16e3 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause-No-Nuclear-License-2014
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /*
  3. * This file is part of the LibreOffice project.
  4. *
  5. * This Source Code Form is subject to the terms of the Mozilla Public
  6. * License, v. 2.0. If a copy of the MPL was not distributed with this
  7. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8. *
  9. * This file incorporates work covered by the following license notice:
  10. *
  11. * Licensed to the Apache Software Foundation (ASF) under one or more
  12. * contributor license agreements. See the NOTICE file distributed
  13. * with this work for additional information regarding copyright
  14. * ownership. The ASF licenses this file to you under the Apache
  15. * License, Version 2.0 (the "License"); you may not use this file
  16. * except in compliance with the License. You may obtain a copy of
  17. * the License at http://www.apache.org/licenses/LICENSE-2.0 .
  18. */
  19. #include "sft.hxx"
  20. #include "gsub.h"
  21. #include <osl/diagnose.h>
  22. #include <vector>
  23. #include <map>
  24. #include <algorithm>
  25. namespace vcl
  26. {
  27. typedef sal_uIntPtr sal_uLong;
  28. typedef sal_uInt8 FT_Byte;
  29. typedef std::map<sal_uInt16,sal_uInt16> GlyphSubstitution;
  30. inline sal_uInt32 NEXT_Long( const unsigned char* &p )
  31. {
  32. sal_uInt32 nVal = (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
  33. p += 4;
  34. return nVal;
  35. }
  36. inline sal_uInt16 NEXT_UShort( const unsigned char* &p )
  37. {
  38. sal_uInt16 nVal = (p[0]<<8) + p[1];
  39. p += 2;
  40. return nVal;
  41. }
  42. #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
  43. int ReadGSUB( struct _TrueTypeFont* pTTFile,
  44. int nRequestedScript, int nRequestedLangsys )
  45. {
  46. const FT_Byte* pGsubBase = (FT_Byte*)pTTFile->tables[ O_gsub ];
  47. if( !pGsubBase )
  48. return -1;
  49. // #129682# check offsets inside GSUB table
  50. const FT_Byte* pGsubLimit = pGsubBase + pTTFile->tlens[ O_gsub ];
  51. // parse GSUB header
  52. const FT_Byte* pGsubHeader = pGsubBase;
  53. const sal_uLong nVersion = NEXT_Long( pGsubHeader );
  54. const sal_uInt16 nOfsScriptList = NEXT_UShort( pGsubHeader );
  55. const sal_uInt16 nOfsFeatureTable = NEXT_UShort( pGsubHeader );
  56. const sal_uInt16 nOfsLookupList = NEXT_UShort( pGsubHeader );
  57. // sanity check the GSUB header
  58. if( nVersion != 0x00010000 )
  59. if( nVersion != 0x00001000 ) // workaround for SunBatang etc.
  60. return -1; // unknown format or broken
  61. typedef std::vector<sal_uLong> ReqFeatureTagList;
  62. ReqFeatureTagList aReqFeatureTagList;
  63. aReqFeatureTagList.push_back( MKTAG("vert") );
  64. typedef std::vector<sal_uInt16> UshortList;
  65. UshortList aFeatureIndexList;
  66. // parse Script Table
  67. const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList;
  68. const sal_uInt16 nCntScript = NEXT_UShort( pScriptHeader );
  69. if( pGsubLimit < pScriptHeader + 6 * nCntScript )
  70. return false;
  71. for( sal_uInt16 nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex )
  72. {
  73. const sal_uLong nTag = NEXT_Long( pScriptHeader ); // e.g. hani/arab/kana/hang
  74. const sal_uInt16 nOfsScriptTable= NEXT_UShort( pScriptHeader );
  75. if( (nTag != (sal_uInt16)nRequestedScript) && (nRequestedScript != 0) )
  76. continue;
  77. const FT_Byte* pScriptTable = pGsubBase + nOfsScriptList + nOfsScriptTable;
  78. if( pGsubLimit < pScriptTable + 4 )
  79. return false;
  80. const sal_uInt16 nDefaultLangsysOfs = NEXT_UShort( pScriptTable );
  81. const sal_uInt16 nCntLangSystem = NEXT_UShort( pScriptTable );
  82. sal_uInt16 nLangsysOffset = 0;
  83. if( pGsubLimit < pScriptTable + 6 * nCntLangSystem )
  84. return false;
  85. for( sal_uInt16 nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex )
  86. {
  87. const sal_uLong nInnerTag = NEXT_Long( pScriptTable ); // e.g. KOR/ZHS/ZHT/JAN
  88. const sal_uInt16 nOffset= NEXT_UShort( pScriptTable );
  89. if( (nInnerTag != (sal_uInt16)nRequestedLangsys) && (nRequestedLangsys != 0) )
  90. continue;
  91. nLangsysOffset = nOffset;
  92. break;
  93. }
  94. if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) )
  95. {
  96. const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs;
  97. if( pGsubLimit < pLangSys + 6 )
  98. return false;
  99. /*const sal_uInt16 nLookupOrder =*/ NEXT_UShort( pLangSys );
  100. const sal_uInt16 nReqFeatureIdx = NEXT_UShort( pLangSys );
  101. const sal_uInt16 nCntFeature = NEXT_UShort( pLangSys );
  102. if( pGsubLimit < pLangSys + 2 * nCntFeature )
  103. return false;
  104. aFeatureIndexList.push_back( nReqFeatureIdx );
  105. for( sal_uInt16 i = 0; i < nCntFeature; ++i )
  106. {
  107. const sal_uInt16 nFeatureIndex = NEXT_UShort( pLangSys );
  108. aFeatureIndexList.push_back( nFeatureIndex );
  109. }
  110. }
  111. if( nLangsysOffset != 0 )
  112. {
  113. const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset;
  114. if( pGsubLimit < pLangSys + 6 )
  115. return false;
  116. /*const sal_uInt16 nLookupOrder =*/ NEXT_UShort( pLangSys );
  117. const sal_uInt16 nReqFeatureIdx = NEXT_UShort( pLangSys );
  118. const sal_uInt16 nCntFeature = NEXT_UShort( pLangSys );
  119. if( pGsubLimit < pLangSys + 2 * nCntFeature )
  120. return false;
  121. aFeatureIndexList.push_back( nReqFeatureIdx );
  122. for( sal_uInt16 i = 0; i < nCntFeature; ++i )
  123. {
  124. const sal_uInt16 nFeatureIndex = NEXT_UShort( pLangSys );
  125. aFeatureIndexList.push_back( nFeatureIndex );
  126. }
  127. }
  128. }
  129. if( aFeatureIndexList.empty() )
  130. return true;
  131. UshortList aLookupIndexList;
  132. UshortList aLookupOffsetList;
  133. // parse Feature Table
  134. const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable;
  135. if( pGsubLimit < pFeatureHeader + 2 )
  136. return false;
  137. const sal_uInt16 nCntFeature = NEXT_UShort( pFeatureHeader );
  138. if( pGsubLimit < pFeatureHeader + 6 * nCntFeature )
  139. return false;
  140. for( sal_uInt16 nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex )
  141. {
  142. const sal_uLong nTag = NEXT_Long( pFeatureHeader ); // e.g. locl/vert/trad/smpl/liga/fina/...
  143. const sal_uInt16 nOffset= NEXT_UShort( pFeatureHeader );
  144. // ignore unneeded feature lookups
  145. if( aFeatureIndexList[0] != nFeatureIndex ) // do not ignore the required feature
  146. {
  147. const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex);
  148. if( !nRequested ) // ignore features that are not requested
  149. continue;
  150. const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag);
  151. if( !nAvailable ) // some fonts don't provide features they request!
  152. continue;
  153. }
  154. const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset;
  155. if( pGsubLimit < pFeatureTable + 2 )
  156. return false;
  157. const sal_uInt16 nCntLookups = NEXT_UShort( pFeatureTable );
  158. if( pGsubLimit < pFeatureTable + 2 * nCntLookups )
  159. return false;
  160. for( sal_uInt16 i = 0; i < nCntLookups; ++i )
  161. {
  162. const sal_uInt16 nLookupIndex = NEXT_UShort( pFeatureTable );
  163. aLookupIndexList.push_back( nLookupIndex );
  164. }
  165. if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
  166. aLookupIndexList.push_back( 0 );
  167. }
  168. // parse Lookup List
  169. const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList;
  170. if( pGsubLimit < pLookupHeader + 2 )
  171. return false;
  172. const sal_uInt16 nCntLookupTable = NEXT_UShort( pLookupHeader );
  173. if( pGsubLimit < pLookupHeader + 2 * nCntLookupTable )
  174. return false;
  175. for( sal_uInt16 nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx )
  176. {
  177. const sal_uInt16 nOffset = NEXT_UShort( pLookupHeader );
  178. if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) )
  179. aLookupOffsetList.push_back( nOffset );
  180. }
  181. UshortList::const_iterator it = aLookupOffsetList.begin();
  182. for(; it != aLookupOffsetList.end(); ++it )
  183. {
  184. const sal_uInt16 nOfsLookupTable = *it;
  185. const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable;
  186. if( pGsubLimit < pLookupTable + 6 )
  187. return false;
  188. const sal_uInt16 eLookupType = NEXT_UShort( pLookupTable );
  189. /*const sal_uInt16 eLookupFlag =*/ NEXT_UShort( pLookupTable );
  190. const sal_uInt16 nCntLookupSubtable = NEXT_UShort( pLookupTable );
  191. // TODO: switch( eLookupType )
  192. if( eLookupType != 1 ) // TODO: once we go beyond SingleSubst
  193. continue;
  194. if( pGsubLimit < pLookupTable + 2 * nCntLookupSubtable )
  195. return false;
  196. for( sal_uInt16 nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx )
  197. {
  198. const sal_uInt16 nOfsSubLookupTable = NEXT_UShort( pLookupTable );
  199. const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable;
  200. if( pGsubLimit < pSubLookup + 6 )
  201. return false;
  202. const sal_uInt16 nFmtSubstitution = NEXT_UShort( pSubLookup );
  203. const sal_uInt16 nOfsCoverage = NEXT_UShort( pSubLookup );
  204. typedef std::pair<sal_uInt16,sal_uInt16> GlyphSubst;
  205. typedef std::vector<GlyphSubst> SubstVector;
  206. SubstVector aSubstVector;
  207. const FT_Byte* pCoverage = pGsubBase
  208. + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage;
  209. if( pGsubLimit < pCoverage + 4 )
  210. return false;
  211. const sal_uInt16 nFmtCoverage = NEXT_UShort( pCoverage );
  212. switch( nFmtCoverage )
  213. {
  214. case 1: // Coverage Format 1
  215. {
  216. const sal_uInt16 nCntGlyph = NEXT_UShort( pCoverage );
  217. if( pGsubLimit < pCoverage + 2 * nCntGlyph )
  218. // TODO? nCntGlyph = (pGsubLimit - pCoverage) / 2;
  219. return false;
  220. aSubstVector.reserve( nCntGlyph );
  221. for( sal_uInt16 i = 0; i < nCntGlyph; ++i )
  222. {
  223. const sal_uInt16 nGlyphId = NEXT_UShort( pCoverage );
  224. aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) );
  225. }
  226. }
  227. break;
  228. case 2: // Coverage Format 2
  229. {
  230. const sal_uInt16 nCntRange = NEXT_UShort( pCoverage );
  231. if( pGsubLimit < pCoverage + 6 * nCntRange )
  232. // TODO? nCntGlyph = (pGsubLimit - pCoverage) / 6;
  233. return false;
  234. for( int i = nCntRange; --i >= 0; )
  235. {
  236. const sal_uInt32 nGlyph0 = NEXT_UShort( pCoverage );
  237. const sal_uInt32 nGlyph1 = NEXT_UShort( pCoverage );
  238. const sal_uInt16 nCovIdx = NEXT_UShort( pCoverage );
  239. for( sal_uInt32 j = nGlyph0; j <= nGlyph1; ++j )
  240. aSubstVector.push_back( GlyphSubst( static_cast<sal_uInt16>(j + nCovIdx), 0 ) );
  241. }
  242. }
  243. break;
  244. }
  245. SubstVector::iterator subst_it( aSubstVector.begin() );
  246. switch( nFmtSubstitution )
  247. {
  248. case 1: // Single Substitution Format 1
  249. {
  250. const sal_uInt16 nDeltaGlyphId = NEXT_UShort( pSubLookup );
  251. for(; subst_it != aSubstVector.end(); ++subst_it )
  252. (*subst_it).second = (*subst_it).first + nDeltaGlyphId;
  253. }
  254. break;
  255. case 2: // Single Substitution Format 2
  256. {
  257. const sal_uInt16 nCntGlyph = NEXT_UShort( pSubLookup );
  258. for( int i = nCntGlyph; (subst_it != aSubstVector.end()) && (--i>=0); ++subst_it )
  259. {
  260. if( pGsubLimit < pSubLookup + 2 )
  261. return false;
  262. const sal_uInt16 nGlyphId = NEXT_UShort( pSubLookup );
  263. (*subst_it).second = nGlyphId;
  264. }
  265. }
  266. break;
  267. }
  268. // now apply the glyph substitutions that have been collected in this subtable
  269. if( !aSubstVector.empty() )
  270. {
  271. GlyphSubstitution* pGSubstitution = new GlyphSubstitution;
  272. pTTFile->pGSubstitution = (void*)pGSubstitution;
  273. for( subst_it = aSubstVector.begin(); subst_it != aSubstVector.end(); ++subst_it )
  274. (*pGSubstitution)[ (*subst_it).first ] = (*subst_it).second;
  275. }
  276. }
  277. }
  278. return true;
  279. }
  280. void ReleaseGSUB(struct _TrueTypeFont* pTTFile)
  281. {
  282. GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution;
  283. if( pGlyphSubstitution )
  284. delete pGlyphSubstitution;
  285. }
  286. int UseGSUB( struct _TrueTypeFont* pTTFile, int nGlyph, int /*wmode*/ )
  287. {
  288. GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution;
  289. if( pGlyphSubstitution != 0 )
  290. {
  291. GlyphSubstitution::const_iterator it( pGlyphSubstitution->find( sal::static_int_cast<sal_uInt16>(nGlyph) ) );
  292. if( it != pGlyphSubstitution->end() )
  293. nGlyph = (*it).second;
  294. }
  295. return nGlyph;
  296. }
  297. int HasVerticalGSUB( struct _TrueTypeFont* pTTFile )
  298. {
  299. GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution;
  300. return pGlyphSubstitution ? +1 : 0;
  301. }
  302. }
  303. /* vim:set shiftwidth=4 softtabstop=4 expandtab: */