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