merge the formfield patch from ooo-build
[ooovba.git] / vcl / source / fontsubset / gsub.cxx
blob09d53b6087f39ee819c7d7bda2e34eff658128a3
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
31 #include "sft.hxx"
33 #include "gsub.h"
35 #include <vector>
36 #include <map>
37 #include <algorithm>
39 namespace vcl
42 typedef sal_uInt32 ULONG;
43 typedef sal_uInt16 USHORT;
44 typedef sal_uInt8 FT_Byte;
46 typedef std::map<USHORT,USHORT> GlyphSubstitution;
49 inline long NEXT_Long( const unsigned char* &p )
51 long nVal = (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
52 p += 4;
53 return nVal;
56 inline USHORT NEXT_UShort( const unsigned char* &p )
58 USHORT nVal = (p[0]<<8) + p[1];
59 p += 2;
60 return nVal;
63 #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
65 int ReadGSUB( struct _TrueTypeFont* pTTFile,
66 int nRequestedScript, int nRequestedLangsys )
68 const FT_Byte* pGsubBase = (FT_Byte*)pTTFile->tables[ O_gsub ];
69 if( !pGsubBase )
70 return -1;
72 // #129682# check offsets inside GSUB table
73 const FT_Byte* pGsubLimit = pGsubBase + pTTFile->tlens[ O_gsub ];
75 // parse GSUB header
76 const FT_Byte* pGsubHeader = pGsubBase;
77 const ULONG nVersion = NEXT_Long( pGsubHeader );
78 const USHORT nOfsScriptList = NEXT_UShort( pGsubHeader );
79 const USHORT nOfsFeatureTable = NEXT_UShort( pGsubHeader );
80 const USHORT nOfsLookupList = NEXT_UShort( pGsubHeader );
82 // sanity check the GSUB header
83 if( nVersion != 0x00010000 )
84 if( nVersion != 0x00001000 ) // workaround for SunBatang etc.
85 return -1; // unknown format or broken
87 typedef std::vector<ULONG> ReqFeatureTagList;
88 ReqFeatureTagList aReqFeatureTagList;
90 aReqFeatureTagList.push_back( MKTAG("vert") );
92 typedef std::vector<USHORT> UshortList;
93 UshortList aFeatureIndexList;
94 UshortList aFeatureOffsetList;
96 // parse Script Table
97 const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList;
98 const USHORT nCntScript = NEXT_UShort( pScriptHeader );
99 if( pGsubLimit < pScriptHeader + 6 * nCntScript )
100 return false;
101 for( USHORT nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex )
103 const ULONG nTag = NEXT_Long( pScriptHeader ); // e.g. hani/arab/kana/hang
104 const USHORT nOfsScriptTable= NEXT_UShort( pScriptHeader );
105 if( (nTag != (USHORT)nRequestedScript) && (nRequestedScript != 0) )
106 continue;
108 const FT_Byte* pScriptTable = pGsubBase + nOfsScriptList + nOfsScriptTable;
109 if( pGsubLimit < pScriptTable + 4 )
110 return false;
111 const USHORT nDefaultLangsysOfs = NEXT_UShort( pScriptTable );
112 const USHORT nCntLangSystem = NEXT_UShort( pScriptTable );
113 USHORT nLangsysOffset = 0;
114 if( pGsubLimit < pScriptTable + 6 * nCntLangSystem )
115 return false;
116 for( USHORT nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex )
118 const ULONG nInnerTag = NEXT_Long( pScriptTable ); // e.g. KOR/ZHS/ZHT/JAN
119 const USHORT nOffset= NEXT_UShort( pScriptTable );
120 if( (nInnerTag != (USHORT)nRequestedLangsys) && (nRequestedLangsys != 0) )
121 continue;
122 nLangsysOffset = nOffset;
123 break;
126 if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) )
128 const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs;
129 if( pGsubLimit < pLangSys + 6 )
130 return false;
131 /*const USHORT nLookupOrder =*/ NEXT_UShort( pLangSys );
132 const USHORT nReqFeatureIdx = NEXT_UShort( pLangSys );
133 const USHORT nCntFeature = NEXT_UShort( pLangSys );
134 if( pGsubLimit < pLangSys + 2 * nCntFeature )
135 return false;
136 aFeatureIndexList.push_back( nReqFeatureIdx );
137 for( USHORT i = 0; i < nCntFeature; ++i )
139 const USHORT nFeatureIndex = NEXT_UShort( pLangSys );
140 aFeatureIndexList.push_back( nFeatureIndex );
144 if( nLangsysOffset != 0 )
146 const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset;
147 if( pGsubLimit < pLangSys + 6 )
148 return false;
149 /*const USHORT nLookupOrder =*/ NEXT_UShort( pLangSys );
150 const USHORT nReqFeatureIdx = NEXT_UShort( pLangSys );
151 const USHORT nCntFeature = NEXT_UShort( pLangSys );
152 if( pGsubLimit < pLangSys + 2 * nCntFeature )
153 return false;
154 aFeatureIndexList.push_back( nReqFeatureIdx );
155 for( USHORT i = 0; i < nCntFeature; ++i )
157 const USHORT nFeatureIndex = NEXT_UShort( pLangSys );
158 aFeatureIndexList.push_back( nFeatureIndex );
163 if( !aFeatureIndexList.size() )
164 return true;
166 UshortList aLookupIndexList;
167 UshortList aLookupOffsetList;
169 // parse Feature Table
170 const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable;
171 if( pGsubLimit < pFeatureHeader + 2 )
172 return false;
173 const USHORT nCntFeature = NEXT_UShort( pFeatureHeader );
174 if( pGsubLimit < pFeatureHeader + 6 * nCntFeature )
175 return false;
176 for( USHORT nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex )
178 const ULONG nTag = NEXT_Long( pFeatureHeader ); // e.g. locl/vert/trad/smpl/liga/fina/...
179 const USHORT nOffset= NEXT_UShort( pFeatureHeader );
181 // ignore unneeded feature lookups
182 if( aFeatureIndexList[0] != nFeatureIndex ) // do not ignore the required feature
184 const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex);
185 if( !nRequested ) // ignore features that are not requested
186 continue;
187 const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag);
188 if( !nAvailable ) // some fonts don't provide features they request!
189 continue;
192 const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset;
193 if( pGsubLimit < pFeatureTable + 2 )
194 return false;
195 const USHORT nCntLookups = NEXT_UShort( pFeatureTable );
196 if( pGsubLimit < pFeatureTable + 2 * nCntLookups )
197 return false;
198 for( USHORT i = 0; i < nCntLookups; ++i )
200 const USHORT nLookupIndex = NEXT_UShort( pFeatureTable );
201 aLookupIndexList.push_back( nLookupIndex );
203 if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
204 aLookupIndexList.push_back( 0 );
207 // parse Lookup List
208 const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList;
209 if( pGsubLimit < pLookupHeader + 2 )
210 return false;
211 const USHORT nCntLookupTable = NEXT_UShort( pLookupHeader );
212 if( pGsubLimit < pLookupHeader + 2 * nCntLookupTable )
213 return false;
214 for( USHORT nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx )
216 const USHORT nOffset = NEXT_UShort( pLookupHeader );
217 if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) )
218 aLookupOffsetList.push_back( nOffset );
221 UshortList::const_iterator it = aLookupOffsetList.begin();
222 for(; it != aLookupOffsetList.end(); ++it )
224 const USHORT nOfsLookupTable = *it;
225 const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable;
226 if( pGsubLimit < pLookupTable + 6 )
227 return false;
228 const USHORT eLookupType = NEXT_UShort( pLookupTable );
229 /*const USHORT eLookupFlag =*/ NEXT_UShort( pLookupTable );
230 const USHORT nCntLookupSubtable = NEXT_UShort( pLookupTable );
232 // TODO: switch( eLookupType )
233 if( eLookupType != 1 ) // TODO: once we go beyond SingleSubst
234 continue;
236 if( pGsubLimit < pLookupTable + 2 * nCntLookupSubtable )
237 return false;
238 for( USHORT nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx )
240 const USHORT nOfsSubLookupTable = NEXT_UShort( pLookupTable );
241 const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable;
242 if( pGsubLimit < pSubLookup + 6 )
243 return false;
244 const USHORT nFmtSubstitution = NEXT_UShort( pSubLookup );
245 const USHORT nOfsCoverage = NEXT_UShort( pSubLookup );
247 typedef std::pair<USHORT,USHORT> GlyphSubst;
248 typedef std::vector<GlyphSubst> SubstVector;
249 SubstVector aSubstVector;
251 const FT_Byte* pCoverage = pGsubBase
252 + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage;
253 if( pGsubLimit < pCoverage + 4 )
254 return false;
255 const USHORT nFmtCoverage = NEXT_UShort( pCoverage );
256 switch( nFmtCoverage )
258 case 1: // Coverage Format 1
260 const USHORT nCntGlyph = NEXT_UShort( pCoverage );
261 if( pGsubLimit < pCoverage + 2 * nCntGlyph )
262 // TODO? nCntGlyph = (pGsubLimit - pCoverage) / 2;
263 return false;
264 aSubstVector.reserve( nCntGlyph );
265 for( USHORT i = 0; i < nCntGlyph; ++i )
267 const USHORT nGlyphId = NEXT_UShort( pCoverage );
268 aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) );
271 break;
273 case 2: // Coverage Format 2
275 const USHORT nCntRange = NEXT_UShort( pCoverage );
276 if( pGsubLimit < pCoverage + 6 * nCntRange )
277 // TODO? nCntGlyph = (pGsubLimit - pCoverage) / 6;
278 return false;
279 for( int i = nCntRange; --i >= 0; )
281 const USHORT nGlyph0 = NEXT_UShort( pCoverage );
282 const USHORT nGlyph1 = NEXT_UShort( pCoverage );
283 const USHORT nCovIdx = NEXT_UShort( pCoverage );
284 for( USHORT j = nGlyph0; j <= nGlyph1; ++j )
285 aSubstVector.push_back( GlyphSubst( j + nCovIdx, 0 ) );
288 break;
291 SubstVector::iterator subst_it( aSubstVector.begin() );
293 switch( nFmtSubstitution )
295 case 1: // Single Substitution Format 1
297 const USHORT nDeltaGlyphId = NEXT_UShort( pSubLookup );
299 for(; subst_it != aSubstVector.end(); ++subst_it )
300 (*subst_it).second = (*subst_it).first + nDeltaGlyphId;
302 break;
304 case 2: // Single Substitution Format 2
306 const USHORT nCntGlyph = NEXT_UShort( pSubLookup );
307 for( int i = nCntGlyph; (subst_it != aSubstVector.end()) && (--i>=0); ++subst_it )
309 if( pGsubLimit < pSubLookup + 2 )
310 return false;
311 const USHORT nGlyphId = NEXT_UShort( pSubLookup );
312 (*subst_it).second = nGlyphId;
315 break;
318 // now apply the glyph substitutions that have been collected in this subtable
319 if( aSubstVector.size() > 0 )
321 GlyphSubstitution* pGSubstitution = new GlyphSubstitution;
322 pTTFile->pGSubstitution = (void*)pGSubstitution;
323 for( subst_it = aSubstVector.begin(); subst_it != aSubstVector.end(); ++subst_it )
324 (*pGSubstitution)[ (*subst_it).first ] = (*subst_it).second;
328 return true;
331 void ReleaseGSUB(struct _TrueTypeFont* pTTFile)
333 GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution;
334 if( pGlyphSubstitution )
335 delete pGlyphSubstitution;
338 int UseGSUB( struct _TrueTypeFont* pTTFile, int nGlyph, int /*wmode*/ )
340 GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution;
341 if( pGlyphSubstitution != 0 )
343 GlyphSubstitution::const_iterator it( pGlyphSubstitution->find( sal::static_int_cast<USHORT>(nGlyph) ) );
344 if( it != pGlyphSubstitution->end() )
345 nGlyph = (*it).second;
348 return nGlyph;
351 int HasVerticalGSUB( struct _TrueTypeFont* pTTFile )
353 GlyphSubstitution* pGlyphSubstitution = (GlyphSubstitution*)pTTFile->pGSubstitution;
354 return pGlyphSubstitution ? +1 : 0;