merge the formfield patch from ooo-build
[ooovba.git] / vcl / source / gdi / metric.cxx
blob24ef812b33cab5ccb25a4131ccc2ca0d770eee30
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
31 #include <vcl/impfont.hxx>
32 #include <vcl/metric.hxx>
34 #include <vector>
35 #include <set>
37 // =======================================================================
39 ImplFontMetric::ImplFontMetric()
40 : mnAscent( 0 ),
41 mnDescent( 0 ),
42 mnIntLeading( 0 ),
43 mnExtLeading( 0 ),
44 mnLineHeight( 0 ),
45 mnSlant( 0 ),
46 mnMiscFlags( 0 ),
47 mnRefCount( 1 )
50 // -----------------------------------------------------------------------
52 inline void ImplFontMetric::AddReference()
54 ++mnRefCount;
57 // -----------------------------------------------------------------------
59 inline void ImplFontMetric::DeReference()
61 if( --mnRefCount <= 0 )
62 delete this;
65 // -----------------------------------------------------------------------
67 bool ImplFontMetric::operator==( const ImplFontMetric& r ) const
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;
82 return true;
85 // =======================================================================
87 FontInfo::FontInfo()
88 : mpImplMetric( new ImplFontMetric )
91 // -----------------------------------------------------------------------
93 FontInfo::FontInfo( const FontInfo& rInfo )
94 : Font( rInfo )
96 mpImplMetric = rInfo.mpImplMetric;
97 mpImplMetric->AddReference();
100 // -----------------------------------------------------------------------
102 FontInfo::~FontInfo()
104 mpImplMetric->DeReference();
107 // -----------------------------------------------------------------------
109 FontInfo& FontInfo::operator=( const FontInfo& rInfo )
111 Font::operator=( rInfo );
113 if( mpImplMetric != rInfo.mpImplMetric )
115 mpImplMetric->DeReference();
116 mpImplMetric = rInfo.mpImplMetric;
117 mpImplMetric->AddReference();
120 return *this;
123 // -----------------------------------------------------------------------
125 BOOL FontInfo::operator==( const FontInfo& rInfo ) const
127 if( !Font::operator==( rInfo ) )
128 return FALSE;
129 if( mpImplMetric == rInfo.mpImplMetric )
130 return TRUE;
131 if( *mpImplMetric == *rInfo.mpImplMetric )
132 return TRUE;
133 return FALSE;
136 // -----------------------------------------------------------------------
138 FontType FontInfo::GetType() const
140 return (mpImplMetric->IsScalable() ? TYPE_SCALABLE : TYPE_RASTER);
143 // -----------------------------------------------------------------------
145 BOOL FontInfo::IsDeviceFont() const
147 return mpImplMetric->IsDeviceFont();
150 // -----------------------------------------------------------------------
152 BOOL FontInfo::SupportsLatin() const
154 return mpImplMetric->SupportsLatin();
157 // -----------------------------------------------------------------------
159 BOOL FontInfo::SupportsCJK() const
161 return mpImplMetric->SupportsCJK();
164 // -----------------------------------------------------------------------
166 BOOL FontInfo::SupportsCTL() const
168 return mpImplMetric->SupportsCTL();
171 // =======================================================================
173 FontMetric::FontMetric( const FontMetric& rMetric )
174 : FontInfo( rMetric )
177 // -----------------------------------------------------------------------
179 long FontMetric::GetAscent() const
181 return mpImplMetric->GetAscent();
184 // -----------------------------------------------------------------------
186 long FontMetric::GetDescent() const
188 return mpImplMetric->GetDescent();
191 // -----------------------------------------------------------------------
193 long FontMetric::GetIntLeading() const
195 return mpImplMetric->GetIntLeading();
198 // -----------------------------------------------------------------------
200 long FontMetric::GetExtLeading() const
202 return mpImplMetric->GetExtLeading();
205 // -----------------------------------------------------------------------
207 long FontMetric::GetLineHeight() const
209 return mpImplMetric->GetLineHeight();
212 // -----------------------------------------------------------------------
214 long FontMetric::GetSlant() const
216 return mpImplMetric->GetSlant();
219 // -----------------------------------------------------------------------
221 FontMetric& FontMetric::operator =( const FontMetric& rMetric )
223 FontInfo::operator=( rMetric );
224 return *this;
227 // -----------------------------------------------------------------------
229 BOOL FontMetric::operator==( const FontMetric& rMetric ) const
231 return FontInfo::operator==( rMetric );
234 // =======================================================================
236 CmapResult::CmapResult( bool bSymbolic,
237 const sal_uInt32* pRangeCodes, int nRangeCount,
238 const int* pStartGlyphs, const USHORT* pExtraGlyphIds )
239 : mpRangeCodes( pRangeCodes)
240 , mpStartGlyphs( pStartGlyphs)
241 , mpGlyphIds( pExtraGlyphIds)
242 , mnRangeCount( nRangeCount)
243 , mbSymbolic( bSymbolic)
244 , mbRecoded( false)
247 // =======================================================================
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( 1 )
257 const sal_uInt32* pRangePtr = mpRangeCodes;
258 for( int i = mnRangeCount; --i >= 0; pRangePtr += 2 )
260 sal_uInt32 cFirst = pRangePtr[0];
261 sal_uInt32 cLast = pRangePtr[1];
262 mnCharCount += cLast - cFirst;
266 static ImplFontCharMap* pDefaultImplFontCharMap = NULL;
267 static const sal_uInt32 aDefaultUnicodeRanges[] = {0x0020,0xD800, 0xE000,0xFFF0};
268 static const sal_uInt32 aDefaultSymbolRanges[] = {0x0020,0x0100, 0xF020,0xF100};
270 // -----------------------------------------------------------------------
272 bool ImplFontCharMap::IsDefaultMap() const
274 const bool bIsDefault = (mpRangeCodes == aDefaultUnicodeRanges) || (mpRangeCodes == aDefaultSymbolRanges);
275 return bIsDefault;
278 // -----------------------------------------------------------------------
280 ImplFontCharMap::~ImplFontCharMap()
282 if( IsDefaultMap() )
283 return;
284 delete[] mpRangeCodes;
285 delete[] mpStartGlyphs;
286 delete[] mpGlyphIds;
289 // -----------------------------------------------------------------------
291 ImplFontCharMap* ImplFontCharMap::GetDefaultMap( bool bSymbols)
293 if( pDefaultImplFontCharMap )
294 pDefaultImplFontCharMap->AddReference();
295 else
297 const sal_uInt32* pRangeCodes = aDefaultUnicodeRanges;
298 int nCodesCount = sizeof(aDefaultUnicodeRanges) / sizeof(*pRangeCodes);
299 if( bSymbols )
301 pRangeCodes = aDefaultSymbolRanges;
302 nCodesCount = sizeof(aDefaultSymbolRanges) / sizeof(*pRangeCodes);
305 CmapResult aDefaultCR( bSymbols, pRangeCodes, nCodesCount/2 );
306 pDefaultImplFontCharMap = new ImplFontCharMap( aDefaultCR );
309 return pDefaultImplFontCharMap;
312 // -----------------------------------------------------------------------
314 void ImplFontCharMap::AddReference()
316 ++mnRefCount;
319 // -----------------------------------------------------------------------
321 void ImplFontCharMap::DeReference()
323 if( --mnRefCount <= 0 )
324 if( this != pDefaultImplFontCharMap )
325 delete this;
328 // -----------------------------------------------------------------------
330 int ImplFontCharMap::GetCharCount() const
332 return mnCharCount;
335 // -----------------------------------------------------------------------
337 int ImplFontCharMap::ImplFindRangeIndex( sal_uInt32 cChar ) const
339 int nLower = 0;
340 int nMid = mnRangeCount;
341 int nUpper = 2 * mnRangeCount - 1;
342 while( nLower < nUpper )
344 if( cChar >= mpRangeCodes[ nMid ] )
345 nLower = nMid;
346 else
347 nUpper = nMid - 1;
348 nMid = (nLower + nUpper + 1) / 2;
351 return nMid;
354 // -----------------------------------------------------------------------
356 bool ImplFontCharMap::HasChar( sal_uInt32 cChar ) const
358 bool bHasChar = false;
360 if( mpStartGlyphs == NULL ) { // only the char-ranges are known
361 const int nRange = ImplFindRangeIndex( cChar );
362 if( nRange==0 && cChar<mpRangeCodes[0] )
363 return false;
364 bHasChar = ((nRange & 1) == 0); // inside a range
365 } else { // glyph mapping is available
366 const int nGlyphIndex = GetGlyphIndex( cChar );
367 bHasChar = (nGlyphIndex != 0); // not the notdef-glyph
370 return bHasChar;
373 // -----------------------------------------------------------------------
375 int ImplFontCharMap::GetGlyphIndex( sal_uInt32 cChar ) const
377 // return -1 if the object doesn't know the glyph ids
378 if( !mpStartGlyphs )
379 return -1;
381 // return 0 if the unicode doesn't have a matching glyph
382 int nRange = ImplFindRangeIndex( cChar );
383 // check that we are inside any range
384 if( (nRange == 0) && (cChar < mpRangeCodes[0]) ) {
385 // symbol aliasing gives symbol fonts a second chance
386 const bool bSymbolic = (mpRangeCodes[0]>=0xF000) & (mpRangeCodes[1]<=0xF0FF);
387 if( !bSymbolic )
388 return 0;
389 // check for symbol aliasing (U+F0xx -> U+00xx)
390 nRange = ImplFindRangeIndex( cChar | 0xF000 );
392 // check that we are inside a range
393 if( (nRange & 1) != 0 )
394 return 0;
396 // get glyph index directly or indirectly
397 int nGlyphIndex = cChar - mpRangeCodes[ nRange ];
398 const int nStartIndex = mpStartGlyphs[ nRange/2 ];
399 if( nStartIndex >= 0 ) {
400 // the glyph index can be calculated
401 nGlyphIndex += nStartIndex;
402 } else {
403 // the glyphid array has the glyph index
404 nGlyphIndex = mpGlyphIds[ nGlyphIndex - nStartIndex];
407 return nGlyphIndex;
410 // -----------------------------------------------------------------------
412 // returns the number of chars supported by the font, which
413 // are inside the unicode range from cMin to cMax (inclusive)
414 int ImplFontCharMap::CountCharsInRange( sal_uInt32 cMin, sal_uInt32 cMax ) const
416 int nCount = 0;
418 // find and adjust range and char count for cMin
419 int nRangeMin = ImplFindRangeIndex( cMin );
420 if( nRangeMin & 1 )
421 ++nRangeMin;
422 else if( cMin > mpRangeCodes[ nRangeMin ] )
423 nCount -= cMin - mpRangeCodes[ nRangeMin ];
425 // find and adjust range and char count for cMax
426 int nRangeMax = ImplFindRangeIndex( cMax );
427 if( nRangeMax & 1 )
428 --nRangeMax;
429 else
430 nCount -= mpRangeCodes[ nRangeMax+1 ] - cMax - 1;
432 // count chars in complete ranges between cMin and cMax
433 for( int i = nRangeMin; i <= nRangeMax; i+=2 )
434 nCount += mpRangeCodes[i+1] - mpRangeCodes[i];
436 return nCount;
439 // -----------------------------------------------------------------------
441 sal_uInt32 ImplFontCharMap::GetFirstChar() const
443 return mpRangeCodes[0];
446 // -----------------------------------------------------------------------
448 sal_uInt32 ImplFontCharMap::GetLastChar() const
450 return (mpRangeCodes[ 2*mnRangeCount-1 ] - 1);
453 // -----------------------------------------------------------------------
455 sal_uInt32 ImplFontCharMap::GetNextChar( sal_uInt32 cChar ) const
457 if( cChar < GetFirstChar() )
458 return GetFirstChar();
459 if( cChar >= GetLastChar() )
460 return GetLastChar();
462 int nRange = ImplFindRangeIndex( cChar + 1 );
463 if( nRange & 1 ) // outside of range?
464 return mpRangeCodes[ nRange + 1 ]; // => first in next range
465 return (cChar + 1);
468 // -----------------------------------------------------------------------
470 sal_uInt32 ImplFontCharMap::GetPrevChar( sal_uInt32 cChar ) const
472 if( cChar <= GetFirstChar() )
473 return GetFirstChar();
474 if( cChar > GetLastChar() )
475 return GetLastChar();
477 int nRange = ImplFindRangeIndex( cChar - 1 );
478 if( nRange & 1 ) // outside a range?
479 return (mpRangeCodes[ nRange ] - 1); // => last in prev range
480 return (cChar - 1);
483 // -----------------------------------------------------------------------
485 int ImplFontCharMap::GetIndexFromChar( sal_uInt32 cChar ) const
487 // TODO: improve linear walk?
488 int nCharIndex = 0;
489 const sal_uInt32* pRange = &mpRangeCodes[0];
490 for( int i = 0; i < mnRangeCount; ++i )
492 sal_uInt32 cFirst = *(pRange++);
493 sal_uInt32 cLast = *(pRange++);
494 if( cChar >= cLast )
495 nCharIndex += cLast - cFirst;
496 else if( cChar >= cFirst )
497 return nCharIndex + (cChar - cFirst);
498 else
499 break;
502 return -1;
505 // -----------------------------------------------------------------------
507 sal_uInt32 ImplFontCharMap::GetCharFromIndex( int nCharIndex ) const
509 // TODO: improve linear walk?
510 const sal_uInt32* pRange = &mpRangeCodes[0];
511 for( int i = 0; i < mnRangeCount; ++i )
513 sal_uInt32 cFirst = *(pRange++);
514 sal_uInt32 cLast = *(pRange++);
515 nCharIndex -= cLast - cFirst;
516 if( nCharIndex < 0 )
517 return (cLast + nCharIndex);
520 // we can only get here with an out-of-bounds charindex
521 return mpRangeCodes[0];
524 // =======================================================================
526 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
527 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8) | p[1]);}
528 static int GetSShort( const unsigned char* p ){ return((static_cast<signed char>(p[0])<<8)|p[1]);}
530 // TODO: move CMAP parsing directly into the ImplFontCharMap class
531 bool ParseCMAP( const unsigned char* pCmap, int nLength, CmapResult& rResult )
533 rResult.mpRangeCodes = NULL;
534 rResult.mpStartGlyphs= NULL;
535 rResult.mpGlyphIds = NULL;
536 rResult.mnRangeCount = 0;
537 rResult.mbRecoded = false;
538 rResult.mbSymbolic = false;
540 // parse the table header and check for validity
541 if( !pCmap || (nLength < 24) )
542 return false;
544 if( GetUShort( pCmap ) != 0x0000 ) // simple check for CMAP corruption
545 return false;
547 int nSubTables = GetUShort( pCmap + 2 );
548 if( (nSubTables <= 0) || (nLength < (24 + 8*nSubTables)) )
549 return false;
551 // find the most interesting subtable in the CMAP
552 rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE;
553 int nOffset = 0;
554 int nFormat = -1;
555 int nBestVal = 0;
556 for( const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8 )
558 int nPlatform = GetUShort( p );
559 int nEncoding = GetUShort( p+2 );
560 int nPlatformEncoding = (nPlatform << 8) + nEncoding;
562 int nValue;
563 rtl_TextEncoding eTmpEncoding = RTL_TEXTENCODING_UNICODE;
564 switch( nPlatformEncoding )
566 case 0x000: nValue = 20; break; // Unicode 1.0
567 case 0x001: nValue = 21; break; // Unicode 1.1
568 case 0x002: nValue = 22; break; // iso10646_1993
569 case 0x003: nValue = 23; break; // UCS-2
570 case 0x004: nValue = 24; break; // UCS-4
571 case 0x100: nValue = 22; break; // Mac Unicode<2.0
572 case 0x103: nValue = 23; break; // Mac Unicode>2.0
573 case 0x300: nValue = 5; rResult.mbSymbolic = true; break; // Win Symbol
574 case 0x301: nValue = 28; break; // Win UCS-2
575 case 0x30A: nValue = 29; break; // Win-UCS-4
576 case 0x302: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_SHIFT_JIS; break;
577 case 0x303: nValue = 12; eTmpEncoding = RTL_TEXTENCODING_GB_18030; break;
578 case 0x304: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_BIG5; break;
579 case 0x305: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_949; break;
580 case 0x306: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_1361; break;
581 default: nValue = 0; break;
584 if( nValue <= 0 ) // ignore unknown encodings
585 continue;
587 int nTmpOffset = GetUInt( p+4 );
588 int nTmpFormat = GetUShort( pCmap + nTmpOffset );
589 if( nTmpFormat == 12 ) // 32bit code -> glyph map format
590 nValue += 3;
591 else if( nTmpFormat != 4 ) // 16bit code -> glyph map format
592 continue; // ignore other formats
594 if( nBestVal < nValue )
596 nBestVal = nValue;
597 nOffset = nTmpOffset;
598 nFormat = nTmpFormat;
599 eRecodeFrom = eTmpEncoding;
603 // parse the best CMAP subtable
604 int nRangeCount = 0;
605 sal_uInt32* pCodePairs = NULL;
606 int* pStartGlyphs = NULL;
608 typedef std::vector<USHORT> U16Vector;
609 U16Vector aGlyphIdArray;
610 aGlyphIdArray.reserve( 0x1000 );
611 aGlyphIdArray.push_back( 0 );
613 // format 4, the most common 16bit char mapping table
614 if( (nFormat == 4) && ((nOffset+16) < nLength) )
616 int nSegCountX2 = GetUShort( pCmap + nOffset + 6 );
617 nRangeCount = nSegCountX2/2 - 1;
618 pCodePairs = new sal_uInt32[ nRangeCount * 2 ];
619 pStartGlyphs = new int[ nRangeCount ];
620 const unsigned char* pLimitBase = pCmap + nOffset + 14;
621 const unsigned char* pBeginBase = pLimitBase + nSegCountX2 + 2;
622 const unsigned char* pDeltaBase = pBeginBase + nSegCountX2;
623 const unsigned char* pOffsetBase = pDeltaBase + nSegCountX2;
624 sal_uInt32* pCP = pCodePairs;
625 for( int i = 0; i < nRangeCount; ++i )
627 const sal_uInt32 cMinChar = GetUShort( pBeginBase + 2*i );
628 const sal_uInt32 cMaxChar = GetUShort( pLimitBase + 2*i );
629 const int nGlyphDelta = GetSShort( pDeltaBase + 2*i );
630 const int nRangeOffset = GetUShort( pOffsetBase + 2*i );
631 if( cMinChar > cMaxChar ) // no sane font should trigger this
632 break;
633 if( cMaxChar == 0xFFFF )
634 break;
635 *(pCP++) = cMinChar;
636 *(pCP++) = cMaxChar + 1;
637 if( !nRangeOffset ) {
638 // glyphid can be calculated directly
639 pStartGlyphs[i] = (cMinChar + nGlyphDelta) & 0xFFFF;
640 } else {
641 // update the glyphid-array with the glyphs in this range
642 pStartGlyphs[i] = -(int)aGlyphIdArray.size();
643 const unsigned char* pGlyphIdPtr = pOffsetBase + 2*i + nRangeOffset;
644 for( sal_uInt32 c = cMinChar; c <= cMaxChar; ++c, pGlyphIdPtr+=2 ) {
645 const int nGlyphIndex = GetUShort( pGlyphIdPtr ) + nGlyphDelta;
646 aGlyphIdArray.push_back( static_cast<USHORT>(nGlyphIndex) );
650 nRangeCount = (pCP - pCodePairs) / 2;
652 // format 12, the most common 32bit char mapping table
653 else if( (nFormat == 12) && ((nOffset+16) < nLength) )
655 nRangeCount = GetUInt( pCmap + nOffset + 12 );
656 pCodePairs = new sal_uInt32[ nRangeCount * 2 ];
657 pStartGlyphs = new int[ nRangeCount ];
658 const unsigned char* pGroup = pCmap + nOffset + 16;
659 sal_uInt32* pCP = pCodePairs;
660 for( int i = 0; i < nRangeCount; ++i )
662 sal_uInt32 cMinChar = GetUInt( pGroup + 0 );
663 sal_uInt32 cMaxChar = GetUInt( pGroup + 4 );
664 int nGlyphId = GetUInt( pGroup + 8 );
665 pGroup += 12;
666 #if 0 // TODO: remove unicode baseplane clipping for UCS-4 support
667 if( cMinChar > 0xFFFF )
668 continue;
669 if( cMaxChar > 0xFFFF )
670 cMaxChar = 0xFFFF;
671 #else
672 if( cMinChar > cMaxChar ) // no sane font should trigger this
673 break;
674 #endif
675 *(pCP++) = cMinChar;
676 *(pCP++) = cMaxChar + 1;
677 pStartGlyphs[i] = nGlyphId;
679 nRangeCount = (pCP - pCodePairs) / 2;
682 // check if any subtable resulted in something usable
683 if( nRangeCount <= 0 )
685 delete[] pCodePairs;
686 delete[] pStartGlyphs;
688 // even when no CMAP is available we know it for symbol fonts
689 if( rResult.mbSymbolic )
691 pCodePairs = new sal_uInt32[4];
692 pCodePairs[0] = 0x0020; // aliased symbols
693 pCodePairs[1] = 0x0100;
694 pCodePairs[2] = 0xF020; // original symbols
695 pCodePairs[3] = 0xF100;
696 rResult.mpRangeCodes = pCodePairs;
697 rResult.mnRangeCount = 2;
698 return true;
701 return false;
704 // recode the code ranges to their unicode encoded ranges if needed
705 rtl_TextToUnicodeConverter aConverter = NULL;
706 rtl_UnicodeToTextContext aCvtContext = NULL;
708 rResult.mbRecoded = ( eRecodeFrom != RTL_TEXTENCODING_UNICODE );
709 if( rResult.mbRecoded )
711 aConverter = rtl_createTextToUnicodeConverter( eRecodeFrom );
712 aCvtContext = rtl_createTextToUnicodeContext( aConverter );
715 if( aConverter && aCvtContext )
717 // determine the set of supported unicodes from encoded ranges
718 typedef std::set<sal_uInt32> IntSet;
719 IntSet aSupportedUnicodes;
721 static const int NINSIZE = 64;
722 static const int NOUTSIZE = 64;
723 sal_Char cCharsInp[ NINSIZE ];
724 sal_Unicode cCharsOut[ NOUTSIZE ];
725 sal_uInt32* pCP = pCodePairs;
726 for( int i = 0; i < nRangeCount; ++i )
728 sal_uInt32 cMin = *(pCP++);
729 sal_uInt32 cEnd = *(pCP++);
730 while( cMin < cEnd )
732 int j = 0;
733 for(; (cMin < cEnd) && (j < NINSIZE); ++cMin )
735 if( cMin >= 0x0100 )
736 cCharsInp[ j++ ] = static_cast<sal_Char>(cMin >> 8);
737 if( (cMin >= 0x0100) || (cMin < 0x00A0) )
738 cCharsInp[ j++ ] = static_cast<sal_Char>(cMin);
741 sal_uInt32 nCvtInfo;
742 sal_Size nSrcCvtBytes;
743 int nOutLen = rtl_convertTextToUnicode(
744 aConverter, aCvtContext,
745 cCharsInp, j, cCharsOut, NOUTSIZE,
746 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE
747 | RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE,
748 &nCvtInfo, &nSrcCvtBytes );
750 for( j = 0; j < nOutLen; ++j )
751 aSupportedUnicodes.insert( cCharsOut[j] );
755 rtl_destroyTextToUnicodeConverter( aCvtContext );
756 rtl_destroyTextToUnicodeConverter( aConverter );
758 // convert the set of supported unicodes to ranges
759 typedef std::vector<sal_uInt32> IntVector;
760 IntVector aSupportedRanges;
762 IntSet::const_iterator itChar = aSupportedUnicodes.begin();
763 for(; itChar != aSupportedUnicodes.end(); ++itChar )
765 if( aSupportedRanges.empty()
766 || (aSupportedRanges.back() != *itChar) )
768 // add new range beginning with current unicode
769 aSupportedRanges.push_back( *itChar );
770 aSupportedRanges.push_back( 0 );
773 // extend existing range to include current unicode
774 aSupportedRanges.back() = *itChar + 1;
777 // glyph mapping for non-unicode fonts not implemented
778 delete[] pStartGlyphs;
779 pStartGlyphs = NULL;
780 aGlyphIdArray.clear();
782 // make a pCodePairs array using the vector from above
783 delete[] pCodePairs;
784 nRangeCount = aSupportedRanges.size() / 2;
785 if( nRangeCount <= 0 )
786 return false;
787 pCodePairs = new sal_uInt32[ nRangeCount * 2 ];
788 IntVector::const_iterator itInt = aSupportedRanges.begin();
789 for( pCP = pCodePairs; itInt != aSupportedRanges.end(); ++itInt )
790 *(pCP++) = *itInt;
793 // prepare the glyphid-array if needed
794 // TODO: merge ranges if they are close enough?
795 USHORT* pGlyphIds = NULL;
796 if( !aGlyphIdArray.empty())
798 pGlyphIds = new USHORT[ aGlyphIdArray.size() ];
799 USHORT* pOut = pGlyphIds;
800 U16Vector::const_iterator it = aGlyphIdArray.begin();
801 while( it != aGlyphIdArray.end() )
802 *(pOut++) = *(it++);
805 // update the result struct
806 rResult.mpRangeCodes = pCodePairs;
807 rResult.mpStartGlyphs = pStartGlyphs;
808 rResult.mnRangeCount = nRangeCount;
809 rResult.mpGlyphIds = pGlyphIds;
810 return true;
813 // =======================================================================
815 FontCharMap::FontCharMap()
816 : mpImpl( ImplFontCharMap::GetDefaultMap() )
819 // -----------------------------------------------------------------------
821 FontCharMap::~FontCharMap()
823 mpImpl->DeReference();
824 mpImpl = NULL;
827 // -----------------------------------------------------------------------
829 int FontCharMap::GetCharCount() const
831 return mpImpl->GetCharCount();
834 // -----------------------------------------------------------------------
836 int FontCharMap::CountCharsInRange( sal_uInt32 cMin, sal_uInt32 cMax ) const
838 return mpImpl->CountCharsInRange( cMin, cMax );
841 // -----------------------------------------------------------------------
843 void FontCharMap::Reset( ImplFontCharMap* pNewMap )
845 if( pNewMap == NULL )
847 mpImpl->DeReference();
848 mpImpl = ImplFontCharMap::GetDefaultMap();
850 else if( pNewMap != mpImpl )
852 mpImpl->DeReference();
853 mpImpl = pNewMap;
854 mpImpl->AddReference();
858 // -----------------------------------------------------------------------
860 BOOL FontCharMap::IsDefaultMap() const
862 return mpImpl->IsDefaultMap();
865 // -----------------------------------------------------------------------
867 BOOL FontCharMap::HasChar( sal_uInt32 cChar ) const
869 return mpImpl->HasChar( cChar );
872 // -----------------------------------------------------------------------
874 sal_uInt32 FontCharMap::GetFirstChar() const
876 return mpImpl->GetFirstChar();
879 // -----------------------------------------------------------------------
881 sal_uInt32 FontCharMap::GetLastChar() const
883 return mpImpl->GetLastChar();
886 // -----------------------------------------------------------------------
888 sal_uInt32 FontCharMap::GetNextChar( sal_uInt32 cChar ) const
890 return mpImpl->GetNextChar( cChar );
893 // -----------------------------------------------------------------------
895 sal_uInt32 FontCharMap::GetPrevChar( sal_uInt32 cChar ) const
897 return mpImpl->GetPrevChar( cChar );
900 // -----------------------------------------------------------------------
902 int FontCharMap::GetIndexFromChar( sal_uInt32 cChar ) const
904 return mpImpl->GetIndexFromChar( cChar );
907 // -----------------------------------------------------------------------
909 sal_uInt32 FontCharMap::GetCharFromIndex( int nIndex ) const
911 return mpImpl->GetCharFromIndex( nIndex );
914 // =======================================================================