PageRenderTime 53ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/libreoffice-3.6.0.2/vcl/source/fontsubset/gsub.cxx

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