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