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