1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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"
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];
56 inline USHORT
NEXT_UShort( const unsigned char* &p
)
58 USHORT nVal
= (p
[0]<<8) + p
[1];
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
];
72 // #129682# check offsets inside GSUB table
73 const FT_Byte
* pGsubLimit
= pGsubBase
+ pTTFile
->tlens
[ O_gsub
];
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
;
97 const FT_Byte
* pScriptHeader
= pGsubBase
+ nOfsScriptList
;
98 const USHORT nCntScript
= NEXT_UShort( pScriptHeader
);
99 if( pGsubLimit
< pScriptHeader
+ 6 * nCntScript
)
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) )
108 const FT_Byte
* pScriptTable
= pGsubBase
+ nOfsScriptList
+ nOfsScriptTable
;
109 if( pGsubLimit
< pScriptTable
+ 4 )
111 const USHORT nDefaultLangsysOfs
= NEXT_UShort( pScriptTable
);
112 const USHORT nCntLangSystem
= NEXT_UShort( pScriptTable
);
113 USHORT nLangsysOffset
= 0;
114 if( pGsubLimit
< pScriptTable
+ 6 * nCntLangSystem
)
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) )
122 nLangsysOffset
= nOffset
;
126 if( (nDefaultLangsysOfs
!= 0) && (nDefaultLangsysOfs
!= nLangsysOffset
) )
128 const FT_Byte
* pLangSys
= pGsubBase
+ nOfsScriptList
+ nOfsScriptTable
+ nDefaultLangsysOfs
;
129 if( pGsubLimit
< pLangSys
+ 6 )
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
)
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 )
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
)
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() )
166 UshortList aLookupIndexList
;
167 UshortList aLookupOffsetList
;
169 // parse Feature Table
170 const FT_Byte
* pFeatureHeader
= pGsubBase
+ nOfsFeatureTable
;
171 if( pGsubLimit
< pFeatureHeader
+ 2 )
173 const USHORT nCntFeature
= NEXT_UShort( pFeatureHeader
);
174 if( pGsubLimit
< pFeatureHeader
+ 6 * nCntFeature
)
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
187 const int nAvailable
= std::count( aReqFeatureTagList
.begin(), aReqFeatureTagList
.end(), nTag
);
188 if( !nAvailable
) // some fonts don't provide features they request!
192 const FT_Byte
* pFeatureTable
= pGsubBase
+ nOfsFeatureTable
+ nOffset
;
193 if( pGsubLimit
< pFeatureTable
+ 2 )
195 const USHORT nCntLookups
= NEXT_UShort( pFeatureTable
);
196 if( pGsubLimit
< pFeatureTable
+ 2 * nCntLookups
)
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 );
208 const FT_Byte
* pLookupHeader
= pGsubBase
+ nOfsLookupList
;
209 if( pGsubLimit
< pLookupHeader
+ 2 )
211 const USHORT nCntLookupTable
= NEXT_UShort( pLookupHeader
);
212 if( pGsubLimit
< pLookupHeader
+ 2 * nCntLookupTable
)
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 )
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
236 if( pGsubLimit
< pLookupTable
+ 2 * nCntLookupSubtable
)
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 )
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 )
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;
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 ) );
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;
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 ) );
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
;
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 )
311 const USHORT nGlyphId
= NEXT_UShort( pSubLookup
);
312 (*subst_it
).second
= nGlyphId
;
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
;
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
;
351 int HasVerticalGSUB( struct _TrueTypeFont
* pTTFile
)
353 GlyphSubstitution
* pGlyphSubstitution
= (GlyphSubstitution
*)pTTFile
->pGSubstitution
;
354 return pGlyphSubstitution
? +1 : 0;