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