1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
25 #include <osl/diagnose.h>
34 typedef sal_uIntPtr sal_uLong
;
35 typedef sal_uInt8 FT_Byte
;
37 typedef std::map
<sal_uInt16
,sal_uInt16
> GlyphSubstitution
;
40 inline sal_uInt32
NEXT_Long( const unsigned char* &p
)
42 sal_uInt32 nVal
= (p
[0]<<24) + (p
[1]<<16) + (p
[2]<<8) + p
[3];
47 inline sal_uInt16
NEXT_UShort( const unsigned char* &p
)
49 sal_uInt16 nVal
= (p
[0]<<8) + p
[1];
54 #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
56 int ReadGSUB( struct _TrueTypeFont
* pTTFile
,
57 int nRequestedScript
, int nRequestedLangsys
)
59 const FT_Byte
* pGsubBase
= (FT_Byte
*)pTTFile
->tables
[ O_gsub
];
63 // #129682# check offsets inside GSUB table
64 const FT_Byte
* pGsubLimit
= pGsubBase
+ pTTFile
->tlens
[ O_gsub
];
67 const FT_Byte
* pGsubHeader
= pGsubBase
;
68 const sal_uLong nVersion
= NEXT_Long( pGsubHeader
);
69 const sal_uInt16 nOfsScriptList
= NEXT_UShort( pGsubHeader
);
70 const sal_uInt16 nOfsFeatureTable
= NEXT_UShort( pGsubHeader
);
71 const sal_uInt16 nOfsLookupList
= NEXT_UShort( pGsubHeader
);
73 // sanity check the GSUB header
74 if( nVersion
!= 0x00010000 )
75 if( nVersion
!= 0x00001000 ) // workaround for SunBatang etc.
76 return -1; // unknown format or broken
78 typedef std::vector
<sal_uLong
> ReqFeatureTagList
;
79 ReqFeatureTagList aReqFeatureTagList
;
81 aReqFeatureTagList
.push_back( MKTAG("vert") );
83 typedef std::vector
<sal_uInt16
> UshortList
;
84 UshortList aFeatureIndexList
;
87 const FT_Byte
* pScriptHeader
= pGsubBase
+ nOfsScriptList
;
88 const sal_uInt16 nCntScript
= NEXT_UShort( pScriptHeader
);
89 if( pGsubLimit
< pScriptHeader
+ 6 * nCntScript
)
91 for( sal_uInt16 nScriptIndex
= 0; nScriptIndex
< nCntScript
; ++nScriptIndex
)
93 const sal_uLong nTag
= NEXT_Long( pScriptHeader
); // e.g. hani/arab/kana/hang
94 const sal_uInt16 nOfsScriptTable
= NEXT_UShort( pScriptHeader
);
95 if( (nTag
!= (sal_uInt16
)nRequestedScript
) && (nRequestedScript
!= 0) )
98 const FT_Byte
* pScriptTable
= pGsubBase
+ nOfsScriptList
+ nOfsScriptTable
;
99 if( pGsubLimit
< pScriptTable
+ 4 )
101 const sal_uInt16 nDefaultLangsysOfs
= NEXT_UShort( pScriptTable
);
102 const sal_uInt16 nCntLangSystem
= NEXT_UShort( pScriptTable
);
103 sal_uInt16 nLangsysOffset
= 0;
104 if( pGsubLimit
< pScriptTable
+ 6 * nCntLangSystem
)
106 for( sal_uInt16 nLangsysIndex
= 0; nLangsysIndex
< nCntLangSystem
; ++nLangsysIndex
)
108 const sal_uLong nInnerTag
= NEXT_Long( pScriptTable
); // e.g. KOR/ZHS/ZHT/JAN
109 const sal_uInt16 nOffset
= NEXT_UShort( pScriptTable
);
110 if( (nInnerTag
!= (sal_uInt16
)nRequestedLangsys
) && (nRequestedLangsys
!= 0) )
112 nLangsysOffset
= nOffset
;
116 if( (nDefaultLangsysOfs
!= 0) && (nDefaultLangsysOfs
!= nLangsysOffset
) )
118 const FT_Byte
* pLangSys
= pGsubBase
+ nOfsScriptList
+ nOfsScriptTable
+ nDefaultLangsysOfs
;
119 if( pGsubLimit
< pLangSys
+ 6 )
121 /*const sal_uInt16 nLookupOrder =*/ NEXT_UShort( pLangSys
);
122 const sal_uInt16 nReqFeatureIdx
= NEXT_UShort( pLangSys
);
123 const sal_uInt16 nCntFeature
= NEXT_UShort( pLangSys
);
124 if( pGsubLimit
< pLangSys
+ 2 * nCntFeature
)
126 aFeatureIndexList
.push_back( nReqFeatureIdx
);
127 for( sal_uInt16 i
= 0; i
< nCntFeature
; ++i
)
129 const sal_uInt16 nFeatureIndex
= NEXT_UShort( pLangSys
);
130 aFeatureIndexList
.push_back( nFeatureIndex
);
134 if( nLangsysOffset
!= 0 )
136 const FT_Byte
* pLangSys
= pGsubBase
+ nOfsScriptList
+ nOfsScriptTable
+ nLangsysOffset
;
137 if( pGsubLimit
< pLangSys
+ 6 )
139 /*const sal_uInt16 nLookupOrder =*/ NEXT_UShort( pLangSys
);
140 const sal_uInt16 nReqFeatureIdx
= NEXT_UShort( pLangSys
);
141 const sal_uInt16 nCntFeature
= NEXT_UShort( pLangSys
);
142 if( pGsubLimit
< pLangSys
+ 2 * nCntFeature
)
144 aFeatureIndexList
.push_back( nReqFeatureIdx
);
145 for( sal_uInt16 i
= 0; i
< nCntFeature
; ++i
)
147 const sal_uInt16 nFeatureIndex
= NEXT_UShort( pLangSys
);
148 aFeatureIndexList
.push_back( nFeatureIndex
);
153 if( aFeatureIndexList
.empty() )
156 UshortList aLookupIndexList
;
157 UshortList aLookupOffsetList
;
159 // parse Feature Table
160 const FT_Byte
* pFeatureHeader
= pGsubBase
+ nOfsFeatureTable
;
161 if( pGsubLimit
< pFeatureHeader
+ 2 )
163 const sal_uInt16 nCntFeature
= NEXT_UShort( pFeatureHeader
);
164 if( pGsubLimit
< pFeatureHeader
+ 6 * nCntFeature
)
166 for( sal_uInt16 nFeatureIndex
= 0; nFeatureIndex
< nCntFeature
; ++nFeatureIndex
)
168 const sal_uLong nTag
= NEXT_Long( pFeatureHeader
); // e.g. locl/vert/trad/smpl/liga/fina/...
169 const sal_uInt16 nOffset
= NEXT_UShort( pFeatureHeader
);
171 // ignore unneeded feature lookups
172 if( aFeatureIndexList
[0] != nFeatureIndex
) // do not ignore the required feature
174 const int nRequested
= std::count( aFeatureIndexList
.begin(), aFeatureIndexList
.end(), nFeatureIndex
);
175 if( !nRequested
) // ignore features that are not requested
177 const int nAvailable
= std::count( aReqFeatureTagList
.begin(), aReqFeatureTagList
.end(), nTag
);
178 if( !nAvailable
) // some fonts don't provide features they request!
182 const FT_Byte
* pFeatureTable
= pGsubBase
+ nOfsFeatureTable
+ nOffset
;
183 if( pGsubLimit
< pFeatureTable
+ 2 )
185 const sal_uInt16 nCntLookups
= NEXT_UShort( pFeatureTable
);
186 if( pGsubLimit
< pFeatureTable
+ 2 * nCntLookups
)
188 for( sal_uInt16 i
= 0; i
< nCntLookups
; ++i
)
190 const sal_uInt16 nLookupIndex
= NEXT_UShort( pFeatureTable
);
191 aLookupIndexList
.push_back( nLookupIndex
);
193 if( nCntLookups
== 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
194 aLookupIndexList
.push_back( 0 );
198 const FT_Byte
* pLookupHeader
= pGsubBase
+ nOfsLookupList
;
199 if( pGsubLimit
< pLookupHeader
+ 2 )
201 const sal_uInt16 nCntLookupTable
= NEXT_UShort( pLookupHeader
);
202 if( pGsubLimit
< pLookupHeader
+ 2 * nCntLookupTable
)
204 for( sal_uInt16 nLookupIdx
= 0; nLookupIdx
< nCntLookupTable
; ++nLookupIdx
)
206 const sal_uInt16 nOffset
= NEXT_UShort( pLookupHeader
);
207 if( std::count( aLookupIndexList
.begin(), aLookupIndexList
.end(), nLookupIdx
) )
208 aLookupOffsetList
.push_back( nOffset
);
211 UshortList::const_iterator it
= aLookupOffsetList
.begin();
212 for(; it
!= aLookupOffsetList
.end(); ++it
)
214 const sal_uInt16 nOfsLookupTable
= *it
;
215 const FT_Byte
* pLookupTable
= pGsubBase
+ nOfsLookupList
+ nOfsLookupTable
;
216 if( pGsubLimit
< pLookupTable
+ 6 )
218 const sal_uInt16 eLookupType
= NEXT_UShort( pLookupTable
);
219 /*const sal_uInt16 eLookupFlag =*/ NEXT_UShort( pLookupTable
);
220 const sal_uInt16 nCntLookupSubtable
= NEXT_UShort( pLookupTable
);
222 // TODO: switch( eLookupType )
223 if( eLookupType
!= 1 ) // TODO: once we go beyond SingleSubst
226 if( pGsubLimit
< pLookupTable
+ 2 * nCntLookupSubtable
)
228 for( sal_uInt16 nSubTableIdx
= 0; nSubTableIdx
< nCntLookupSubtable
; ++nSubTableIdx
)
230 const sal_uInt16 nOfsSubLookupTable
= NEXT_UShort( pLookupTable
);
231 const FT_Byte
* pSubLookup
= pGsubBase
+ nOfsLookupList
+ nOfsLookupTable
+ nOfsSubLookupTable
;
232 if( pGsubLimit
< pSubLookup
+ 6 )
234 const sal_uInt16 nFmtSubstitution
= NEXT_UShort( pSubLookup
);
235 const sal_uInt16 nOfsCoverage
= NEXT_UShort( pSubLookup
);
237 typedef std::pair
<sal_uInt16
,sal_uInt16
> GlyphSubst
;
238 typedef std::vector
<GlyphSubst
> SubstVector
;
239 SubstVector aSubstVector
;
241 const FT_Byte
* pCoverage
= pGsubBase
242 + nOfsLookupList
+ nOfsLookupTable
+ nOfsSubLookupTable
+ nOfsCoverage
;
243 if( pGsubLimit
< pCoverage
+ 4 )
245 const sal_uInt16 nFmtCoverage
= NEXT_UShort( pCoverage
);
246 switch( nFmtCoverage
)
248 case 1: // Coverage Format 1
250 const sal_uInt16 nCntGlyph
= NEXT_UShort( pCoverage
);
251 if( pGsubLimit
< pCoverage
+ 2 * nCntGlyph
)
252 // TODO? nCntGlyph = (pGsubLimit - pCoverage) / 2;
254 aSubstVector
.reserve( nCntGlyph
);
255 for( sal_uInt16 i
= 0; i
< nCntGlyph
; ++i
)
257 const sal_uInt16 nGlyphId
= NEXT_UShort( pCoverage
);
258 aSubstVector
.push_back( GlyphSubst( nGlyphId
, 0 ) );
263 case 2: // Coverage Format 2
265 const sal_uInt16 nCntRange
= NEXT_UShort( pCoverage
);
266 if( pGsubLimit
< pCoverage
+ 6 * nCntRange
)
267 // TODO? nCntGlyph = (pGsubLimit - pCoverage) / 6;
269 for( int i
= nCntRange
; --i
>= 0; )
271 const sal_uInt32 nGlyph0
= NEXT_UShort( pCoverage
);
272 const sal_uInt32 nGlyph1
= NEXT_UShort( pCoverage
);
273 const sal_uInt16 nCovIdx
= NEXT_UShort( pCoverage
);
274 for( sal_uInt32 j
= nGlyph0
; j
<= nGlyph1
; ++j
)
275 aSubstVector
.push_back( GlyphSubst( static_cast<sal_uInt16
>(j
+ nCovIdx
), 0 ) );
281 SubstVector::iterator
subst_it( aSubstVector
.begin() );
283 switch( nFmtSubstitution
)
285 case 1: // Single Substitution Format 1
287 const sal_uInt16 nDeltaGlyphId
= NEXT_UShort( pSubLookup
);
289 for(; subst_it
!= aSubstVector
.end(); ++subst_it
)
290 (*subst_it
).second
= (*subst_it
).first
+ nDeltaGlyphId
;
294 case 2: // Single Substitution Format 2
296 const sal_uInt16 nCntGlyph
= NEXT_UShort( pSubLookup
);
297 for( int i
= nCntGlyph
; (subst_it
!= aSubstVector
.end()) && (--i
>=0); ++subst_it
)
299 if( pGsubLimit
< pSubLookup
+ 2 )
301 const sal_uInt16 nGlyphId
= NEXT_UShort( pSubLookup
);
302 (*subst_it
).second
= nGlyphId
;
308 // now apply the glyph substitutions that have been collected in this subtable
309 if( !aSubstVector
.empty() )
311 GlyphSubstitution
* pGSubstitution
= new GlyphSubstitution
;
312 pTTFile
->pGSubstitution
= (void*)pGSubstitution
;
313 for( subst_it
= aSubstVector
.begin(); subst_it
!= aSubstVector
.end(); ++subst_it
)
314 (*pGSubstitution
)[ (*subst_it
).first
] = (*subst_it
).second
;
321 void ReleaseGSUB(struct _TrueTypeFont
* pTTFile
)
323 GlyphSubstitution
* pGlyphSubstitution
= (GlyphSubstitution
*)pTTFile
->pGSubstitution
;
324 if( pGlyphSubstitution
)
325 delete pGlyphSubstitution
;
328 int UseGSUB( struct _TrueTypeFont
* pTTFile
, int nGlyph
, int /*wmode*/ )
330 GlyphSubstitution
* pGlyphSubstitution
= (GlyphSubstitution
*)pTTFile
->pGSubstitution
;
331 if( pGlyphSubstitution
!= 0 )
333 GlyphSubstitution::const_iterator
it( pGlyphSubstitution
->find( sal::static_int_cast
<sal_uInt16
>(nGlyph
) ) );
334 if( it
!= pGlyphSubstitution
->end() )
335 nGlyph
= (*it
).second
;
341 int HasVerticalGSUB( struct _TrueTypeFont
* pTTFile
)
343 GlyphSubstitution
* pGlyphSubstitution
= (GlyphSubstitution
*)pTTFile
->pGSubstitution
;
344 return pGlyphSubstitution
? +1 : 0;
349 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */