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 <impfont.hxx>
31 : : #include <vcl/metric.hxx>
32 : :
33 : : #include <vector>
34 : : #include <set>
35 : :
36 : : #include <cstdio>
37 : :
38 : : // =======================================================================
39 : :
40 : 1143989 : ImplFontMetric::ImplFontMetric()
41 : : : mnAscent( 0 ),
42 : : mnDescent( 0 ),
43 : : mnIntLeading( 0 ),
44 : : mnExtLeading( 0 ),
45 : : mnLineHeight( 0 ),
46 : : mnSlant( 0 ),
47 : : mnMiscFlags( 0 ),
48 : 1143989 : mnRefCount( 1 )
49 : 1143989 : {}
50 : :
51 : : // -----------------------------------------------------------------------
52 : :
53 : 597757 : inline void ImplFontMetric::AddReference()
54 : : {
55 : : // TODO: disable refcounting on the default maps?
56 : 597757 : ++mnRefCount;
57 : 597757 : }
58 : :
59 : : // -----------------------------------------------------------------------
60 : :
61 : 1718228 : inline void ImplFontMetric::DeReference()
62 : : {
63 : : // TODO: disable refcounting on the default maps?
64 [ + + ]: 1718228 : if( --mnRefCount <= 0 )
65 : 1120471 : delete this;
66 : 1718228 : }
67 : :
68 : : // -----------------------------------------------------------------------
69 : :
70 : 0 : bool ImplFontMetric::operator==( const ImplFontMetric& r ) const
71 : : {
72 [ # # ]: 0 : if( mnMiscFlags != r.mnMiscFlags )
73 : 0 : return false;
74 [ # # ]: 0 : if( mnAscent != r.mnAscent )
75 : 0 : return false;
76 [ # # ]: 0 : if( mnDescent != r.mnDescent )
77 : 0 : return false;
78 [ # # ]: 0 : if( mnIntLeading != r.mnIntLeading )
79 : 0 : return false;
80 [ # # ]: 0 : if( mnExtLeading != r.mnExtLeading )
81 : 0 : return false;
82 [ # # ]: 0 : if( mnSlant != r.mnSlant )
83 : 0 : return false;
84 : :
85 : 0 : return true;
86 : : }
87 : :
88 : : // =======================================================================
89 : :
90 : 1143989 : FontInfo::FontInfo()
91 [ + - ]: 1143989 : : mpImplMetric( new ImplFontMetric )
92 : 1143989 : {}
93 : :
94 : : // -----------------------------------------------------------------------
95 : :
96 : 594330 : FontInfo::FontInfo( const FontInfo& rInfo )
97 : 594330 : : Font( rInfo )
98 : : {
99 : 594330 : mpImplMetric = rInfo.mpImplMetric;
100 : 594330 : mpImplMetric->AddReference();
101 : 594330 : }
102 : :
103 : : // -----------------------------------------------------------------------
104 : :
105 : 1714801 : FontInfo::~FontInfo()
106 : : {
107 : 1714801 : mpImplMetric->DeReference();
108 : 1714801 : }
109 : :
110 : : // -----------------------------------------------------------------------
111 : :
112 : 3427 : FontInfo& FontInfo::operator=( const FontInfo& rInfo )
113 : : {
114 : 3427 : Font::operator=( rInfo );
115 : :
116 [ + - ]: 3427 : if( mpImplMetric != rInfo.mpImplMetric )
117 : : {
118 : 3427 : mpImplMetric->DeReference();
119 : 3427 : mpImplMetric = rInfo.mpImplMetric;
120 : 3427 : mpImplMetric->AddReference();
121 : : }
122 : :
123 : 3427 : return *this;
124 : : }
125 : :
126 : : // -----------------------------------------------------------------------
127 : :
128 : 0 : sal_Bool FontInfo::operator==( const FontInfo& rInfo ) const
129 : : {
130 [ # # ]: 0 : if( !Font::operator==( rInfo ) )
131 : 0 : return sal_False;
132 [ # # ]: 0 : if( mpImplMetric == rInfo.mpImplMetric )
133 : 0 : return sal_True;
134 [ # # ]: 0 : if( *mpImplMetric == *rInfo.mpImplMetric )
135 : 0 : return sal_True;
136 : 0 : return sal_False;
137 : : }
138 : :
139 : : // -----------------------------------------------------------------------
140 : :
141 : 752769 : FontType FontInfo::GetType() const
142 : : {
143 [ + - ]: 752769 : return (mpImplMetric->IsScalable() ? TYPE_SCALABLE : TYPE_RASTER);
144 : : }
145 : :
146 : 0 : FontMetric::FontMetric( const FontMetric& rMetric )
147 : 0 : : FontInfo( rMetric )
148 : 0 : {}
149 : :
150 : : // -----------------------------------------------------------------------
151 : :
152 : 522721 : long FontMetric::GetAscent() const
153 : : {
154 : 522721 : return mpImplMetric->GetAscent();
155 : : }
156 : :
157 : : // -----------------------------------------------------------------------
158 : :
159 : 450533 : long FontMetric::GetDescent() const
160 : : {
161 : 450533 : return mpImplMetric->GetDescent();
162 : : }
163 : :
164 : : // -----------------------------------------------------------------------
165 : :
166 : 889347 : long FontMetric::GetIntLeading() const
167 : : {
168 : 889347 : return mpImplMetric->GetIntLeading();
169 : : }
170 : :
171 : : // -----------------------------------------------------------------------
172 : :
173 : 3864 : long FontMetric::GetExtLeading() const
174 : : {
175 : 3864 : return mpImplMetric->GetExtLeading();
176 : : }
177 : :
178 : : // -----------------------------------------------------------------------
179 : :
180 : 0 : long FontMetric::GetLineHeight() const
181 : : {
182 : 0 : return mpImplMetric->GetLineHeight();
183 : : }
184 : :
185 : : // -----------------------------------------------------------------------
186 : :
187 : 0 : long FontMetric::GetSlant() const
188 : : {
189 : 0 : return mpImplMetric->GetSlant();
190 : : }
191 : :
192 : : // -----------------------------------------------------------------------
193 : :
194 : 1583 : FontMetric& FontMetric::operator =( const FontMetric& rMetric )
195 : : {
196 : 1583 : FontInfo::operator=( rMetric );
197 : 1583 : return *this;
198 : : }
199 : :
200 : : // -----------------------------------------------------------------------
201 : :
202 : 0 : sal_Bool FontMetric::operator==( const FontMetric& rMetric ) const
203 : : {
204 : 0 : return FontInfo::operator==( rMetric );
205 : : }
206 : :
207 : : // =======================================================================
208 : :
209 : 484 : CmapResult::CmapResult( bool bSymbolic,
210 : : const sal_uInt32* pRangeCodes, int nRangeCount,
211 : : const int* pStartGlyphs, const sal_uInt16* pExtraGlyphIds )
212 : : : mpRangeCodes( pRangeCodes)
213 : : , mpStartGlyphs( pStartGlyphs)
214 : : , mpGlyphIds( pExtraGlyphIds)
215 : : , mnRangeCount( nRangeCount)
216 : : , mbSymbolic( bSymbolic)
217 : 484 : , mbRecoded( false)
218 : 484 : {}
219 : :
220 : : // =======================================================================
221 : :
222 : 484 : ImplFontCharMap::ImplFontCharMap( const CmapResult& rCR )
223 : : : mpRangeCodes( rCR.mpRangeCodes )
224 : : , mpStartGlyphs( rCR.mpStartGlyphs )
225 : : , mpGlyphIds( rCR.mpGlyphIds )
226 : : , mnRangeCount( rCR.mnRangeCount )
227 : : , mnCharCount( 0 )
228 : 484 : , mnRefCount( 0 )
229 : : {
230 : 484 : const sal_uInt32* pRangePtr = mpRangeCodes;
231 [ + + ]: 61905 : for( int i = mnRangeCount; --i >= 0; pRangePtr += 2 )
232 : : {
233 : 61421 : sal_uInt32 cFirst = pRangePtr[0];
234 : 61421 : sal_uInt32 cLast = pRangePtr[1];
235 : 61421 : mnCharCount += cLast - cFirst;
236 : : }
237 : 484 : }
238 : :
239 : : static ImplFontCharMap* pDefaultUnicodeImplFontCharMap = NULL;
240 : : static ImplFontCharMap* pDefaultSymbolImplFontCharMap = NULL;
241 : : static const sal_uInt32 aDefaultUnicodeRanges[] = {0x0020,0xD800, 0xE000,0xFFF0};
242 : : static const sal_uInt32 aDefaultSymbolRanges[] = {0x0020,0x0100, 0xF020,0xF100};
243 : :
244 : : // -----------------------------------------------------------------------
245 : :
246 : 10985 : bool ImplFontCharMap::IsDefaultMap() const
247 : : {
248 [ + - ][ - + ]: 10985 : const bool bIsDefault = (mpRangeCodes == aDefaultUnicodeRanges) || (mpRangeCodes == aDefaultSymbolRanges);
249 : 10985 : return bIsDefault;
250 : : }
251 : :
252 : : // -----------------------------------------------------------------------
253 : :
254 : 538 : ImplFontCharMap::~ImplFontCharMap()
255 : : {
256 [ - + ]: 269 : if( IsDefaultMap() )
257 : 0 : return;
258 [ + - ]: 269 : delete[] mpRangeCodes;
259 [ + + ]: 269 : delete[] mpStartGlyphs;
260 [ + + ]: 269 : delete[] mpGlyphIds;
261 [ - + ]: 538 : }
262 : :
263 : : // -----------------------------------------------------------------------
264 : :
265 : : namespace
266 : : {
267 : 21432 : ImplFontCharMap *GetDefaultUnicodeMap()
268 : : {
269 [ + + ]: 21432 : if( !pDefaultUnicodeImplFontCharMap )
270 : : {
271 : 215 : const sal_uInt32* pRangeCodes = aDefaultUnicodeRanges;
272 : 215 : int nCodesCount = sizeof(aDefaultUnicodeRanges) / sizeof(*pRangeCodes);
273 [ + - ]: 215 : CmapResult aDefaultCR( false, pRangeCodes, nCodesCount/2 );
274 [ + - ][ + - ]: 215 : pDefaultUnicodeImplFontCharMap = new ImplFontCharMap( aDefaultCR );
275 [ + - ]: 215 : pDefaultUnicodeImplFontCharMap->AddReference();
276 : : }
277 : :
278 : 21432 : return pDefaultUnicodeImplFontCharMap;
279 : : }
280 : :
281 : 0 : ImplFontCharMap *GetDefaultSymbolMap()
282 : : {
283 [ # # ]: 0 : if( !pDefaultSymbolImplFontCharMap )
284 : : {
285 : 0 : const sal_uInt32* pRangeCodes = aDefaultSymbolRanges;
286 : 0 : int nCodesCount = sizeof(aDefaultSymbolRanges) / sizeof(*pRangeCodes);
287 [ # # ]: 0 : CmapResult aDefaultCR( true, pRangeCodes, nCodesCount/2 );
288 [ # # ][ # # ]: 0 : pDefaultSymbolImplFontCharMap = new ImplFontCharMap( aDefaultCR );
289 [ # # ]: 0 : pDefaultSymbolImplFontCharMap->AddReference();
290 : : }
291 : :
292 : 0 : return pDefaultSymbolImplFontCharMap;
293 : : }
294 : : }
295 : :
296 : 21432 : ImplFontCharMap* ImplFontCharMap::GetDefaultMap( bool bSymbols)
297 : : {
298 [ - + ]: 21432 : return bSymbols ? GetDefaultSymbolMap() : GetDefaultUnicodeMap();
299 : : }
300 : :
301 : : // -----------------------------------------------------------------------
302 : :
303 : 32632 : void ImplFontCharMap::AddReference( void ) const
304 : : {
305 : : // TODO: disable refcounting on the default maps?
306 : 32632 : ++mnRefCount;
307 : 32632 : }
308 : :
309 : : // -----------------------------------------------------------------------
310 : :
311 : 32417 : void ImplFontCharMap::DeReference( void ) const
312 : : {
313 [ + + ]: 32417 : if( --mnRefCount <= 0 )
314 [ + - ][ + - ]: 269 : if( (this != pDefaultUnicodeImplFontCharMap) && (this != pDefaultSymbolImplFontCharMap) )
315 [ + - ]: 269 : delete this;
316 : 32417 : }
317 : :
318 : : // -----------------------------------------------------------------------
319 : :
320 : 0 : int ImplFontCharMap::GetCharCount() const
321 : : {
322 : 0 : return mnCharCount;
323 : : }
324 : :
325 : : // -----------------------------------------------------------------------
326 : :
327 : 44603 : int ImplFontCharMap::ImplFindRangeIndex( sal_uInt32 cChar ) const
328 : : {
329 : 44603 : int nLower = 0;
330 : 44603 : int nMid = mnRangeCount;
331 : 44603 : int nUpper = 2 * mnRangeCount - 1;
332 [ + + ]: 420137 : while( nLower < nUpper )
333 : : {
334 [ + + ]: 375534 : if( cChar >= mpRangeCodes[ nMid ] )
335 : 208017 : nLower = nMid;
336 : : else
337 : 167517 : nUpper = nMid - 1;
338 : 375534 : nMid = (nLower + nUpper + 1) / 2;
339 : : }
340 : :
341 : 44603 : return nMid;
342 : : }
343 : :
344 : : // -----------------------------------------------------------------------
345 : :
346 : 44603 : bool ImplFontCharMap::HasChar( sal_uInt32 cChar ) const
347 : : {
348 : 44603 : bool bHasChar = false;
349 : :
350 [ - + ]: 44603 : if( mpStartGlyphs == NULL ) { // only the char-ranges are known
351 : 0 : const int nRange = ImplFindRangeIndex( cChar );
352 [ # # ][ # # ]: 0 : if( nRange==0 && cChar<mpRangeCodes[0] )
353 : 0 : return false;
354 : 0 : bHasChar = ((nRange & 1) == 0); // inside a range
355 : : } else { // glyph mapping is available
356 : 44603 : const int nGlyphIndex = GetGlyphIndex( cChar );
357 : 44603 : bHasChar = (nGlyphIndex != 0); // not the notdef-glyph
358 : : }
359 : :
360 : 44603 : return bHasChar;
361 : : }
362 : :
363 : : // -----------------------------------------------------------------------
364 : :
365 : 44603 : int ImplFontCharMap::GetGlyphIndex( sal_uInt32 cChar ) const
366 : : {
367 : : // return -1 if the object doesn't know the glyph ids
368 [ - + ]: 44603 : if( !mpStartGlyphs )
369 : 0 : return -1;
370 : :
371 : : // return 0 if the unicode doesn't have a matching glyph
372 : 44603 : int nRange = ImplFindRangeIndex( cChar );
373 : : // check that we are inside any range
374 [ - + ][ + + ]: 44603 : if( (nRange == 0) && (cChar < mpRangeCodes[0]) ) {
375 : : // symbol aliasing gives symbol fonts a second chance
376 : 0 : const bool bSymbolic = (mpRangeCodes[0]>=0xF000) & (mpRangeCodes[1]<=0xF0FF);
377 [ # # ]: 0 : if( !bSymbolic )
378 : 0 : return 0;
379 : : // check for symbol aliasing (U+00xx <-> U+F0xx)
380 : 0 : cChar |= 0xF000;
381 : 0 : nRange = ImplFindRangeIndex( cChar );
382 : : }
383 : : // check that we are inside a range
384 [ + + ]: 44603 : if( (nRange & 1) != 0 )
385 : 32912 : return 0;
386 : :
387 : : // get glyph index directly or indirectly
388 : 11691 : int nGlyphIndex = cChar - mpRangeCodes[ nRange ];
389 : 11691 : const int nStartIndex = mpStartGlyphs[ nRange/2 ];
390 [ + - ]: 11691 : if( nStartIndex >= 0 ) {
391 : : // the glyph index can be calculated
392 : 11691 : nGlyphIndex += nStartIndex;
393 : : } else {
394 : : // the glyphid array has the glyph index
395 : 0 : nGlyphIndex = mpGlyphIds[ nGlyphIndex - nStartIndex ];
396 : : }
397 : :
398 : 44603 : return nGlyphIndex;
399 : : }
400 : :
401 : : // -----------------------------------------------------------------------
402 : :
403 : : // returns the number of chars supported by the font, which
404 : : // are inside the unicode range from cMin to cMax (inclusive)
405 : 0 : int ImplFontCharMap::CountCharsInRange( sal_uInt32 cMin, sal_uInt32 cMax ) const
406 : : {
407 : 0 : int nCount = 0;
408 : :
409 : : // find and adjust range and char count for cMin
410 : 0 : int nRangeMin = ImplFindRangeIndex( cMin );
411 [ # # ]: 0 : if( nRangeMin & 1 )
412 : 0 : ++nRangeMin;
413 [ # # ]: 0 : else if( cMin > mpRangeCodes[ nRangeMin ] )
414 : 0 : nCount -= cMin - mpRangeCodes[ nRangeMin ];
415 : :
416 : : // find and adjust range and char count for cMax
417 : 0 : int nRangeMax = ImplFindRangeIndex( cMax );
418 [ # # ]: 0 : if( nRangeMax & 1 )
419 : 0 : --nRangeMax;
420 : : else
421 : 0 : nCount -= mpRangeCodes[ nRangeMax+1 ] - cMax - 1;
422 : :
423 : : // count chars in complete ranges between cMin and cMax
424 [ # # ]: 0 : for( int i = nRangeMin; i <= nRangeMax; i+=2 )
425 : 0 : nCount += mpRangeCodes[i+1] - mpRangeCodes[i];
426 : :
427 : 0 : return nCount;
428 : : }
429 : :
430 : : // -----------------------------------------------------------------------
431 : :
432 : 1655 : sal_uInt32 ImplFontCharMap::GetFirstChar() const
433 : : {
434 : 1655 : return mpRangeCodes[0];
435 : : }
436 : :
437 : : // -----------------------------------------------------------------------
438 : :
439 : 0 : sal_uInt32 ImplFontCharMap::GetLastChar() const
440 : : {
441 : 0 : return (mpRangeCodes[ 2*mnRangeCount-1 ] - 1);
442 : : }
443 : :
444 : : // -----------------------------------------------------------------------
445 : :
446 : 0 : sal_uInt32 ImplFontCharMap::GetNextChar( sal_uInt32 cChar ) const
447 : : {
448 [ # # ]: 0 : if( cChar < GetFirstChar() )
449 : 0 : return GetFirstChar();
450 [ # # ]: 0 : if( cChar >= GetLastChar() )
451 : 0 : return GetLastChar();
452 : :
453 : 0 : int nRange = ImplFindRangeIndex( cChar + 1 );
454 [ # # ]: 0 : if( nRange & 1 ) // outside of range?
455 : 0 : return mpRangeCodes[ nRange + 1 ]; // => first in next range
456 : 0 : return (cChar + 1);
457 : : }
458 : :
459 : : // -----------------------------------------------------------------------
460 : :
461 : 0 : sal_uInt32 ImplFontCharMap::GetPrevChar( sal_uInt32 cChar ) const
462 : : {
463 [ # # ]: 0 : if( cChar <= GetFirstChar() )
464 : 0 : return GetFirstChar();
465 [ # # ]: 0 : if( cChar > GetLastChar() )
466 : 0 : return GetLastChar();
467 : :
468 : 0 : int nRange = ImplFindRangeIndex( cChar - 1 );
469 [ # # ]: 0 : if( nRange & 1 ) // outside a range?
470 : 0 : return (mpRangeCodes[ nRange ] - 1); // => last in prev range
471 : 0 : return (cChar - 1);
472 : : }
473 : :
474 : : // -----------------------------------------------------------------------
475 : :
476 : 0 : int ImplFontCharMap::GetIndexFromChar( sal_uInt32 cChar ) const
477 : : {
478 : : // TODO: improve linear walk?
479 : 0 : int nCharIndex = 0;
480 : 0 : const sal_uInt32* pRange = &mpRangeCodes[0];
481 [ # # ]: 0 : for( int i = 0; i < mnRangeCount; ++i )
482 : : {
483 : 0 : sal_uInt32 cFirst = *(pRange++);
484 : 0 : sal_uInt32 cLast = *(pRange++);
485 [ # # ]: 0 : if( cChar >= cLast )
486 : 0 : nCharIndex += cLast - cFirst;
487 [ # # ]: 0 : else if( cChar >= cFirst )
488 : 0 : return nCharIndex + (cChar - cFirst);
489 : : else
490 : 0 : break;
491 : : }
492 : :
493 : 0 : return -1;
494 : : }
495 : :
496 : : // -----------------------------------------------------------------------
497 : :
498 : 0 : sal_uInt32 ImplFontCharMap::GetCharFromIndex( int nCharIndex ) const
499 : : {
500 : : // TODO: improve linear walk?
501 : 0 : const sal_uInt32* pRange = &mpRangeCodes[0];
502 [ # # ]: 0 : for( int i = 0; i < mnRangeCount; ++i )
503 : : {
504 : 0 : sal_uInt32 cFirst = *(pRange++);
505 : 0 : sal_uInt32 cLast = *(pRange++);
506 : 0 : nCharIndex -= cLast - cFirst;
507 [ # # ]: 0 : if( nCharIndex < 0 )
508 : 0 : return (cLast + nCharIndex);
509 : : }
510 : :
511 : : // we can only get here with an out-of-bounds charindex
512 : 0 : return mpRangeCodes[0];
513 : : }
514 : :
515 : : // =======================================================================
516 : :
517 : 170427 : static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
518 : 30939 : static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8) | p[1]);}
519 : 4646 : static int GetSShort( const unsigned char* p ){ return((static_cast<signed char>(p[0])<<8)|p[1]);}
520 : :
521 : : // TODO: move CMAP parsing directly into the ImplFontCharMap class
522 : 264 : bool ParseCMAP( const unsigned char* pCmap, int nLength, CmapResult& rResult )
523 : : {
524 : 264 : rResult.mpRangeCodes = NULL;
525 : 264 : rResult.mpStartGlyphs= NULL;
526 : 264 : rResult.mpGlyphIds = NULL;
527 : 264 : rResult.mnRangeCount = 0;
528 : 264 : rResult.mbRecoded = false;
529 : 264 : rResult.mbSymbolic = false;
530 : :
531 : : // parse the table header and check for validity
532 [ + - ][ - + ]: 264 : if( !pCmap || (nLength < 24) )
533 : 0 : return false;
534 : :
535 [ - + ]: 264 : if( GetUShort( pCmap ) != 0x0000 ) // simple check for CMAP corruption
536 : 0 : return false;
537 : :
538 : 264 : int nSubTables = GetUShort( pCmap + 2 );
539 [ - + ][ + - ]: 264 : if( (nSubTables <= 0) || (nLength < (24 + 8*nSubTables)) )
540 : 0 : return false;
541 : :
542 : : // find the most interesting subtable in the CMAP
543 : 264 : rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE;
544 : 264 : int nOffset = 0;
545 : 264 : int nFormat = -1;
546 : 264 : int nBestVal = 0;
547 [ + + ]: 1486 : for( const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8 )
548 : : {
549 : 1222 : int nPlatform = GetUShort( p );
550 : 1222 : int nEncoding = GetUShort( p+2 );
551 : 1222 : int nPlatformEncoding = (nPlatform << 8) + nEncoding;
552 : :
553 : : int nValue;
554 : 1222 : rtl_TextEncoding eTmpEncoding = RTL_TEXTENCODING_UNICODE;
555 [ - - - + : 1222 : switch( nPlatformEncoding )
+ + - - +
+ - - - -
- - ]
556 : : {
557 : 0 : case 0x000: nValue = 20; break; // Unicode 1.0
558 : 0 : case 0x001: nValue = 21; break; // Unicode 1.1
559 : 0 : case 0x002: nValue = 22; break; // iso10646_1993
560 : 264 : case 0x003: nValue = 23; break; // UCS-2
561 : 215 : case 0x004: nValue = 24; break; // UCS-4
562 : 264 : case 0x100: nValue = 22; break; // Mac Unicode<2.0
563 : 0 : case 0x103: nValue = 23; break; // Mac Unicode>2.0
564 : 0 : case 0x300: nValue = 5; rResult.mbSymbolic = true; break; // Win Symbol
565 : 264 : case 0x301: nValue = 28; break; // Win UCS-2
566 : 215 : case 0x30A: nValue = 29; break; // Win-UCS-4
567 : 0 : case 0x302: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_SHIFT_JIS; break;
568 : 0 : case 0x303: nValue = 12; eTmpEncoding = RTL_TEXTENCODING_GB_18030; break;
569 : 0 : case 0x304: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_BIG5; break;
570 : 0 : case 0x305: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_949; break;
571 : 0 : case 0x306: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_1361; break;
572 : 0 : default: nValue = 0; break;
573 : : }
574 : :
575 [ - + ]: 1222 : if( nValue <= 0 ) // ignore unknown encodings
576 : 0 : continue;
577 : :
578 : 1222 : int nTmpOffset = GetUInt( p+4 );
579 : 1222 : int nTmpFormat = GetUShort( pCmap + nTmpOffset );
580 [ + + ]: 1222 : if( nTmpFormat == 12 ) // 32bit code -> glyph map format
581 : 430 : nValue += 3;
582 [ + + ]: 792 : else if( nTmpFormat != 4 ) // 16bit code -> glyph map format
583 : 264 : continue; // ignore other formats
584 : :
585 [ + - ]: 958 : if( nBestVal < nValue )
586 : : {
587 : 958 : nBestVal = nValue;
588 : 958 : nOffset = nTmpOffset;
589 : 958 : nFormat = nTmpFormat;
590 : 958 : eRecodeFrom = eTmpEncoding;
591 : : }
592 : : }
593 : :
594 : : // parse the best CMAP subtable
595 : 264 : int nRangeCount = 0;
596 : 264 : sal_uInt32* pCodePairs = NULL;
597 : 264 : int* pStartGlyphs = NULL;
598 : :
599 : : typedef std::vector<sal_uInt16> U16Vector;
600 [ + - ]: 264 : U16Vector aGlyphIdArray;
601 [ + - ]: 264 : aGlyphIdArray.reserve( 0x1000 );
602 [ + - ]: 264 : aGlyphIdArray.push_back( 0 );
603 : :
604 : : // format 4, the most common 16bit char mapping table
605 [ + + ][ + - ]: 264 : if( (nFormat == 4) && ((nOffset+16) < nLength) )
606 : : {
607 : 49 : int nSegCountX2 = GetUShort( pCmap + nOffset + 6 );
608 : 49 : nRangeCount = nSegCountX2/2 - 1;
609 [ + - ]: 49 : pCodePairs = new sal_uInt32[ nRangeCount * 2 ];
610 [ + - ]: 49 : pStartGlyphs = new int[ nRangeCount ];
611 : 49 : const unsigned char* pLimitBase = pCmap + nOffset + 14;
612 : 49 : const unsigned char* pBeginBase = pLimitBase + nSegCountX2 + 2;
613 : 49 : const unsigned char* pDeltaBase = pBeginBase + nSegCountX2;
614 : 49 : const unsigned char* pOffsetBase = pDeltaBase + nSegCountX2;
615 : 49 : sal_uInt32* pCP = pCodePairs;
616 [ + + ]: 4695 : for( int i = 0; i < nRangeCount; ++i )
617 : : {
618 : 4646 : const sal_uInt32 cMinChar = GetUShort( pBeginBase + 2*i );
619 : 4646 : const sal_uInt32 cMaxChar = GetUShort( pLimitBase + 2*i );
620 : 4646 : const int nGlyphDelta = GetSShort( pDeltaBase + 2*i );
621 : 4646 : const int nRangeOffset = GetUShort( pOffsetBase + 2*i );
622 [ - + ]: 4646 : if( cMinChar > cMaxChar ) // no sane font should trigger this
623 : 0 : break;
624 [ - + ]: 4646 : if( cMaxChar == 0xFFFF )
625 : 0 : break;
626 : 4646 : *(pCP++) = cMinChar;
627 : 4646 : *(pCP++) = cMaxChar + 1;
628 [ + + ]: 4646 : if( !nRangeOffset ) {
629 : : // glyphid can be calculated directly
630 : 4547 : pStartGlyphs[i] = (cMinChar + nGlyphDelta) & 0xFFFF;
631 : : } else {
632 : : // update the glyphid-array with the glyphs in this range
633 : 99 : pStartGlyphs[i] = -(int)aGlyphIdArray.size();
634 : 99 : const unsigned char* pGlyphIdPtr = pOffsetBase + 2*i + nRangeOffset;
635 [ + + ]: 12857 : for( sal_uInt32 c = cMinChar; c <= cMaxChar; ++c, pGlyphIdPtr+=2 ) {
636 : 12758 : const int nGlyphIndex = GetUShort( pGlyphIdPtr ) + nGlyphDelta;
637 [ + - ]: 12758 : aGlyphIdArray.push_back( static_cast<sal_uInt16>(nGlyphIndex) );
638 : : }
639 : : }
640 : : }
641 : 49 : nRangeCount = (pCP - pCodePairs) / 2;
642 : : }
643 : : // format 12, the most common 32bit char mapping table
644 [ + - ][ + - ]: 215 : else if( (nFormat == 12) && ((nOffset+16) < nLength) )
645 : : {
646 : 215 : nRangeCount = GetUInt( pCmap + nOffset + 12 );
647 [ + - ]: 215 : pCodePairs = new sal_uInt32[ nRangeCount * 2 ];
648 [ + - ]: 215 : pStartGlyphs = new int[ nRangeCount ];
649 : 215 : const unsigned char* pGroup = pCmap + nOffset + 16;
650 : 215 : sal_uInt32* pCP = pCodePairs;
651 [ + + ]: 56545 : for( int i = 0; i < nRangeCount; ++i )
652 : : {
653 : 56330 : sal_uInt32 cMinChar = GetUInt( pGroup + 0 );
654 : 56330 : sal_uInt32 cMaxChar = GetUInt( pGroup + 4 );
655 : 56330 : int nGlyphId = GetUInt( pGroup + 8 );
656 : 56330 : pGroup += 12;
657 [ - + ]: 56330 : if( cMinChar > cMaxChar ) // no sane font should trigger this
658 : 0 : break;
659 : 56330 : *(pCP++) = cMinChar;
660 : 56330 : *(pCP++) = cMaxChar + 1;
661 : 56330 : pStartGlyphs[i] = nGlyphId;
662 : : }
663 : 215 : nRangeCount = (pCP - pCodePairs) / 2;
664 : : }
665 : :
666 : : // check if any subtable resulted in something usable
667 [ - + ]: 264 : if( nRangeCount <= 0 )
668 : : {
669 [ # # ]: 0 : delete[] pCodePairs;
670 [ # # ]: 0 : delete[] pStartGlyphs;
671 : :
672 : : // even when no CMAP is available we know it for symbol fonts
673 [ # # ]: 0 : if( rResult.mbSymbolic )
674 : : {
675 [ # # ]: 0 : pCodePairs = new sal_uInt32[4];
676 : 0 : pCodePairs[0] = 0x0020; // aliased symbols
677 : 0 : pCodePairs[1] = 0x0100;
678 : 0 : pCodePairs[2] = 0xF020; // original symbols
679 : 0 : pCodePairs[3] = 0xF100;
680 : 0 : rResult.mpRangeCodes = pCodePairs;
681 : 0 : rResult.mnRangeCount = 2;
682 : 0 : return true;
683 : : }
684 : :
685 : 0 : return false;
686 : : }
687 : :
688 : : // recode the code ranges to their unicode encoded ranges if needed
689 : 264 : rtl_TextToUnicodeConverter aConverter = NULL;
690 : 264 : rtl_UnicodeToTextContext aCvtContext = NULL;
691 : :
692 : 264 : rResult.mbRecoded = ( eRecodeFrom != RTL_TEXTENCODING_UNICODE );
693 [ - + ]: 264 : if( rResult.mbRecoded )
694 : : {
695 [ # # ]: 0 : aConverter = rtl_createTextToUnicodeConverter( eRecodeFrom );
696 [ # # ]: 0 : aCvtContext = rtl_createTextToUnicodeContext( aConverter );
697 : : }
698 : :
699 [ - + ][ # # ]: 264 : if( aConverter && aCvtContext )
700 : : {
701 : : // determine the set of supported unicodes from encoded ranges
702 : : typedef std::set<sal_uInt32> IntSet;
703 [ # # ]: 0 : IntSet aSupportedUnicodes;
704 : :
705 : : static const int NINSIZE = 64;
706 : : static const int NOUTSIZE = 64;
707 : : sal_Char cCharsInp[ NINSIZE ];
708 : : sal_Unicode cCharsOut[ NOUTSIZE ];
709 : 0 : sal_uInt32* pCP = pCodePairs;
710 [ # # ]: 0 : for( int i = 0; i < nRangeCount; ++i )
711 : : {
712 : 0 : sal_uInt32 cMin = *(pCP++);
713 : 0 : sal_uInt32 cEnd = *(pCP++);
714 [ # # ]: 0 : while( cMin < cEnd )
715 : : {
716 : 0 : int j = 0;
717 [ # # ][ # # ]: 0 : for (; (cMin < cEnd) && (j < (NINSIZE-1)); ++cMin)
[ # # ]
718 : : {
719 [ # # ]: 0 : if( cMin >= 0x0100 )
720 : 0 : cCharsInp[ j++ ] = static_cast<sal_Char>(cMin >> 8);
721 [ # # ][ # # ]: 0 : if( (cMin >= 0x0100) || (cMin < 0x00A0) )
722 : 0 : cCharsInp[ j++ ] = static_cast<sal_Char>(cMin);
723 : : }
724 : :
725 : : sal_uInt32 nCvtInfo;
726 : : sal_Size nSrcCvtBytes;
727 : : int nOutLen = rtl_convertTextToUnicode(
728 : : aConverter, aCvtContext,
729 : : cCharsInp, j, cCharsOut, NOUTSIZE,
730 : : RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE
731 : : | RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE,
732 [ # # ]: 0 : &nCvtInfo, &nSrcCvtBytes );
733 : :
734 [ # # ]: 0 : for( j = 0; j < nOutLen; ++j )
735 [ # # ]: 0 : aSupportedUnicodes.insert( cCharsOut[j] );
736 : : }
737 : : }
738 : :
739 [ # # ]: 0 : rtl_destroyTextToUnicodeConverter( aCvtContext );
740 [ # # ]: 0 : rtl_destroyTextToUnicodeConverter( aConverter );
741 : :
742 : : // convert the set of supported unicodes to ranges
743 : : typedef std::vector<sal_uInt32> IntVector;
744 [ # # ]: 0 : IntVector aSupportedRanges;
745 : :
746 : 0 : IntSet::const_iterator itChar = aSupportedUnicodes.begin();
747 [ # # ][ # # ]: 0 : for(; itChar != aSupportedUnicodes.end(); ++itChar )
[ # # ]
748 : : {
749 [ # # ][ # # ]: 0 : if( aSupportedRanges.empty()
[ # # ]
750 [ # # ][ # # ]: 0 : || (aSupportedRanges.back() != *itChar) )
751 : : {
752 : : // add new range beginning with current unicode
753 [ # # ][ # # ]: 0 : aSupportedRanges.push_back( *itChar );
754 [ # # ]: 0 : aSupportedRanges.push_back( 0 );
755 : : }
756 : :
757 : : // extend existing range to include current unicode
758 [ # # ][ # # ]: 0 : aSupportedRanges.back() = *itChar + 1;
759 : : }
760 : :
761 : : // glyph mapping for non-unicode fonts not implemented
762 [ # # ]: 0 : delete[] pStartGlyphs;
763 : 0 : pStartGlyphs = NULL;
764 : 0 : aGlyphIdArray.clear();
765 : :
766 : : // make a pCodePairs array using the vector from above
767 [ # # ]: 0 : delete[] pCodePairs;
768 : 0 : nRangeCount = aSupportedRanges.size() / 2;
769 [ # # ]: 0 : if( nRangeCount <= 0 )
770 : 0 : return false;
771 [ # # ]: 0 : pCodePairs = new sal_uInt32[ nRangeCount * 2 ];
772 [ # # ]: 0 : IntVector::const_iterator itInt = aSupportedRanges.begin();
773 [ # # ][ # # ]: 0 : for( pCP = pCodePairs; itInt != aSupportedRanges.end(); ++itInt )
[ # # ]
774 [ # # ][ # # ]: 0 : *(pCP++) = *itInt;
[ # # ]
775 : : }
776 : :
777 : : // prepare the glyphid-array if needed
778 : : // TODO: merge ranges if they are close enough?
779 : 264 : sal_uInt16* pGlyphIds = NULL;
780 [ + - ]: 264 : if( !aGlyphIdArray.empty())
781 : : {
782 [ + - ]: 264 : pGlyphIds = new sal_uInt16[ aGlyphIdArray.size() ];
783 : 264 : sal_uInt16* pOut = pGlyphIds;
784 [ + - ]: 264 : U16Vector::const_iterator it = aGlyphIdArray.begin();
785 [ + - ][ + + ]: 13286 : while( it != aGlyphIdArray.end() )
786 [ + - ][ + - ]: 13022 : *(pOut++) = *(it++);
787 : : }
788 : :
789 : : // update the result struct
790 : 264 : rResult.mpRangeCodes = pCodePairs;
791 : 264 : rResult.mpStartGlyphs = pStartGlyphs;
792 : 264 : rResult.mnRangeCount = nRangeCount;
793 : 264 : rResult.mpGlyphIds = pGlyphIds;
794 : 264 : return true;
795 : : }
796 : :
797 : : // =======================================================================
798 : :
799 : 10716 : FontCharMap::FontCharMap()
800 : 10716 : : mpImpl( ImplFontCharMap::GetDefaultMap() )
801 : : {
802 : 10716 : mpImpl->AddReference();
803 : 10716 : }
804 : :
805 : : // -----------------------------------------------------------------------
806 : :
807 : 10716 : FontCharMap::~FontCharMap()
808 : : {
809 : 10716 : mpImpl->DeReference();
810 : 10716 : mpImpl = NULL;
811 : 10716 : }
812 : :
813 : : // -----------------------------------------------------------------------
814 : :
815 : 0 : int FontCharMap::GetCharCount() const
816 : : {
817 : 0 : return mpImpl->GetCharCount();
818 : : }
819 : :
820 : : // -----------------------------------------------------------------------
821 : :
822 : 0 : int FontCharMap::CountCharsInRange( sal_uInt32 cMin, sal_uInt32 cMax ) const
823 : : {
824 : 0 : return mpImpl->CountCharsInRange( cMin, cMax );
825 : : }
826 : :
827 : : // -----------------------------------------------------------------------
828 : :
829 : 21432 : void FontCharMap::Reset( const ImplFontCharMap* pNewMap )
830 : : {
831 : 21432 : mpImpl->DeReference();
832 [ + + ]: 21432 : if( pNewMap == NULL )
833 : 10716 : mpImpl = ImplFontCharMap::GetDefaultMap();
834 [ + - ]: 10716 : else if( pNewMap != mpImpl )
835 : 10716 : mpImpl = pNewMap;
836 : 21432 : mpImpl->AddReference();
837 : 21432 : }
838 : :
839 : : // -----------------------------------------------------------------------
840 : :
841 : 10716 : sal_Bool FontCharMap::IsDefaultMap() const
842 : : {
843 : 10716 : return mpImpl->IsDefaultMap();
844 : : }
845 : :
846 : : // -----------------------------------------------------------------------
847 : :
848 : 44603 : sal_Bool FontCharMap::HasChar( sal_uInt32 cChar ) const
849 : : {
850 : 44603 : return mpImpl->HasChar( cChar );
851 : : }
852 : :
853 : : // -----------------------------------------------------------------------
854 : :
855 : 1655 : sal_uInt32 FontCharMap::GetFirstChar() const
856 : : {
857 : 1655 : return mpImpl->GetFirstChar();
858 : : }
859 : :
860 : : // -----------------------------------------------------------------------
861 : :
862 : 0 : sal_uInt32 FontCharMap::GetNextChar( sal_uInt32 cChar ) const
863 : : {
864 : 0 : return mpImpl->GetNextChar( cChar );
865 : : }
866 : :
867 : : // -----------------------------------------------------------------------
868 : :
869 : 0 : sal_uInt32 FontCharMap::GetPrevChar( sal_uInt32 cChar ) const
870 : : {
871 : 0 : return mpImpl->GetPrevChar( cChar );
872 : : }
873 : :
874 : : // -----------------------------------------------------------------------
875 : :
876 : 0 : int FontCharMap::GetIndexFromChar( sal_uInt32 cChar ) const
877 : : {
878 : 0 : return mpImpl->GetIndexFromChar( cChar );
879 : : }
880 : :
881 : : // -----------------------------------------------------------------------
882 : :
883 : 0 : sal_uInt32 FontCharMap::GetCharFromIndex( int nIndex ) const
884 : : {
885 : 0 : return mpImpl->GetCharFromIndex( nIndex );
886 : : }
887 : :
888 : : // =======================================================================
889 : :
890 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|