PageRenderTime 100ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 1ms

/OOO330_m20/vcl/source/fontsubset/gsub.cxx

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