nss: upgrade to release 3.73
[LibreOffice.git] / vcl / source / font / fontcharmap.cxx
blobe68939d3885ec67bdc1dffde9dbc91f32fa9493c
1 /*
2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 #include <vcl/fontcharmap.hxx>
19 #include <impfontcharmap.hxx>
20 #include <rtl/textcvt.h>
21 #include <rtl/textenc.h>
22 #include <sal/log.hxx>
24 #include <algorithm>
25 #include <vector>
26 #include <o3tl/sorted_vector.hxx>
28 CmapResult::CmapResult( bool bSymbolic,
29 const sal_UCS4* pRangeCodes, int nRangeCount )
30 : mpRangeCodes( pRangeCodes)
31 , mpStartGlyphs( nullptr)
32 , mpGlyphIds( nullptr)
33 , mnRangeCount( nRangeCount)
34 , mbSymbolic( bSymbolic)
35 , mbRecoded( false)
38 static ImplFontCharMapRef g_pDefaultImplFontCharMap;
39 const sal_UCS4 aDefaultUnicodeRanges[] = {0x0020,0xD800, 0xE000,0xFFF0};
40 const sal_UCS4 aDefaultSymbolRanges[] = {0x0020,0x0100, 0xF020,0xF100};
42 ImplFontCharMap::~ImplFontCharMap()
44 if( !isDefaultMap() )
46 delete[] mpRangeCodes;
47 delete[] mpStartGlyphs;
48 delete[] mpGlyphIds;
52 ImplFontCharMap::ImplFontCharMap( const CmapResult& rCR )
53 : mpRangeCodes( rCR.mpRangeCodes )
54 , mpStartGlyphs( rCR.mpStartGlyphs )
55 , mpGlyphIds( rCR.mpGlyphIds )
56 , mnRangeCount( rCR.mnRangeCount )
57 , mnCharCount( 0 )
58 , m_bSymbolic(rCR.mbSymbolic)
60 const sal_UCS4* pRangePtr = mpRangeCodes;
61 for( int i = mnRangeCount; --i >= 0; pRangePtr += 2 )
63 sal_UCS4 cFirst = pRangePtr[0];
64 sal_UCS4 cLast = pRangePtr[1];
65 mnCharCount += cLast - cFirst;
69 ImplFontCharMapRef const & ImplFontCharMap::getDefaultMap( bool bSymbols )
71 const sal_UCS4* pRangeCodes = aDefaultUnicodeRanges;
72 int nCodesCount = SAL_N_ELEMENTS(aDefaultUnicodeRanges);
73 if( bSymbols )
75 pRangeCodes = aDefaultSymbolRanges;
76 nCodesCount = SAL_N_ELEMENTS(aDefaultSymbolRanges);
79 CmapResult aDefaultCR( bSymbols, pRangeCodes, nCodesCount/2 );
80 g_pDefaultImplFontCharMap = ImplFontCharMapRef(new ImplFontCharMap(aDefaultCR));
82 return g_pDefaultImplFontCharMap;
85 bool ImplFontCharMap::isDefaultMap() const
87 const bool bIsDefault = (mpRangeCodes == aDefaultUnicodeRanges) || (mpRangeCodes == aDefaultSymbolRanges);
88 return bIsDefault;
91 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
92 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8) | p[1]);}
93 static int GetSShort( const unsigned char* p ){ return static_cast<sal_Int16>((p[0]<<8)|p[1]);}
95 // TODO: move CMAP parsing directly into the ImplFontCharMap class
96 bool ParseCMAP( const unsigned char* pCmap, int nLength, CmapResult& rResult )
98 rResult.mpRangeCodes = nullptr;
99 rResult.mpStartGlyphs= nullptr;
100 rResult.mpGlyphIds = nullptr;
101 rResult.mnRangeCount = 0;
102 rResult.mbRecoded = false;
103 rResult.mbSymbolic = false;
105 // parse the table header and check for validity
106 if( !pCmap || (nLength < 24) )
107 return false;
109 if( GetUShort( pCmap ) != 0x0000 ) // simple check for CMAP corruption
110 return false;
112 int nSubTables = GetUShort( pCmap + 2 );
113 if( (nSubTables <= 0) || (nLength < (24 + 8*nSubTables)) )
114 return false;
116 const unsigned char* pEndValidArea = pCmap + nLength;
118 // find the most interesting subtable in the CMAP
119 rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE;
120 int nOffset = 0;
121 int nFormat = -1;
122 int nBestVal = 0;
123 for( const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8 )
125 int nPlatform = GetUShort( p );
126 int nEncoding = GetUShort( p+2 );
127 int nPlatformEncoding = (nPlatform << 8) + nEncoding;
129 int nValue;
130 rtl_TextEncoding eTmpEncoding = RTL_TEXTENCODING_UNICODE;
131 switch( nPlatformEncoding )
133 case 0x000: nValue = 20; break; // Unicode 1.0
134 case 0x001: nValue = 21; break; // Unicode 1.1
135 case 0x002: nValue = 22; break; // iso10646_1993
136 case 0x003: nValue = 23; break; // UCS-2
137 case 0x004: nValue = 24; break; // UCS-4
138 case 0x100: nValue = 22; break; // Mac Unicode<2.0
139 case 0x103: nValue = 23; break; // Mac Unicode>2.0
140 case 0x300: nValue = 5; rResult.mbSymbolic = true; break; // Win Symbol
141 case 0x301: nValue = 28; break; // Win UCS-2
142 case 0x30A: nValue = 29; break; // Win-UCS-4
143 case 0x302: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_SHIFT_JIS; break;
144 case 0x303: nValue = 12; eTmpEncoding = RTL_TEXTENCODING_GB_18030; break;
145 case 0x304: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_BIG5; break;
146 case 0x305: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_949; break;
147 case 0x306: nValue = 11; eTmpEncoding = RTL_TEXTENCODING_MS_1361; break;
148 default: nValue = 0; break;
151 if( nValue <= 0 ) // ignore unknown encodings
152 continue;
154 int nTmpOffset = GetUInt( p+4 );
156 if (nTmpOffset > nLength - 2 || nTmpOffset < 0)
157 continue;
159 int nTmpFormat = GetUShort( pCmap + nTmpOffset );
160 if( nTmpFormat == 12 ) // 32bit code -> glyph map format
161 nValue += 3;
162 else if( nTmpFormat != 4 ) // 16bit code -> glyph map format
163 continue; // ignore other formats
165 if( nBestVal < nValue )
167 nBestVal = nValue;
168 nOffset = nTmpOffset;
169 nFormat = nTmpFormat;
170 eRecodeFrom = eTmpEncoding;
174 // parse the best CMAP subtable
175 int nRangeCount = 0;
176 sal_UCS4* pCodePairs = nullptr;
177 int* pStartGlyphs = nullptr;
179 std::vector<sal_uInt16> aGlyphIdArray;
180 aGlyphIdArray.reserve( 0x1000 );
181 aGlyphIdArray.push_back( 0 );
183 // format 4, the most common 16bit char mapping table
184 if( (nFormat == 4) && ((nOffset+16) < nLength) )
186 int nSegCountX2 = GetUShort( pCmap + nOffset + 6 );
187 nRangeCount = nSegCountX2/2 - 1;
188 if (nRangeCount < 0)
190 SAL_WARN("vcl.gdi", "negative RangeCount");
191 nRangeCount = 0;
194 const unsigned char* pLimitBase = pCmap + nOffset + 14;
195 const unsigned char* pBeginBase = pLimitBase + nSegCountX2 + 2;
196 const unsigned char* pDeltaBase = pBeginBase + nSegCountX2;
197 const unsigned char* pOffsetBase = pDeltaBase + nSegCountX2;
199 const int nOffsetBaseStart = pOffsetBase - pCmap;
200 const int nRemainingLen = nLength - nOffsetBaseStart;
201 const int nMaxPossibleRangeOffsets = nRemainingLen / 2;
202 if (nRangeCount > nMaxPossibleRangeOffsets)
204 SAL_WARN("vcl.gdi", "more range offsets requested then space available");
205 nRangeCount = std::max(0, nMaxPossibleRangeOffsets);
208 pCodePairs = new sal_UCS4[ nRangeCount * 2 ];
209 pStartGlyphs = new int[ nRangeCount ];
211 sal_UCS4* pCP = pCodePairs;
212 for( int i = 0; i < nRangeCount; ++i )
214 const sal_UCS4 cMinChar = GetUShort( pBeginBase + 2*i );
215 const sal_UCS4 cMaxChar = GetUShort( pLimitBase + 2*i );
216 const int nGlyphDelta = GetSShort( pDeltaBase + 2*i );
217 const int nRangeOffset = GetUShort( pOffsetBase + 2*i );
218 if( cMinChar > cMaxChar ) { // no sane font should trigger this
219 SAL_WARN("vcl.gdi", "Min char should never be more than the max char!");
220 break;
222 if( cMaxChar == 0xFFFF ) {
223 SAL_WARN("vcl.gdi", "Format 4 char should not be 0xFFFF");
224 break;
226 if( !nRangeOffset ) {
227 // glyphid can be calculated directly
228 pStartGlyphs[i] = (cMinChar + nGlyphDelta) & 0xFFFF;
229 } else {
230 // update the glyphid-array with the glyphs in this range
231 pStartGlyphs[i] = -static_cast<int>(aGlyphIdArray.size());
232 const unsigned char* pGlyphIdPtr = pOffsetBase + 2*i + nRangeOffset;
233 const size_t nRemainingSize = pEndValidArea >= pGlyphIdPtr ? pEndValidArea - pGlyphIdPtr : 0;
234 const size_t nMaxPossibleRecords = nRemainingSize/2;
235 if (nMaxPossibleRecords == 0) { // no sane font should trigger this
236 SAL_WARN("vcl.gdi", "More indexes claimed that space available in font!");
237 break;
239 const size_t nMaxLegalChar = cMinChar + nMaxPossibleRecords-1;
240 if (cMaxChar > nMaxLegalChar) { // no sane font should trigger this
241 SAL_WARN("vcl.gdi", "More indexes claimed that space available in font!");
242 break;
244 for( sal_UCS4 c = cMinChar; c <= cMaxChar; ++c, pGlyphIdPtr+=2 ) {
245 const int nGlyphIndex = GetUShort( pGlyphIdPtr ) + nGlyphDelta;
246 aGlyphIdArray.push_back( static_cast<sal_uInt16>(nGlyphIndex) );
249 *(pCP++) = cMinChar;
250 *(pCP++) = cMaxChar + 1;
252 nRangeCount = (pCP - pCodePairs) / 2;
254 // format 12, the most common 32bit char mapping table
255 else if( (nFormat == 12) && ((nOffset+16) < nLength) )
257 nRangeCount = GetUInt( pCmap + nOffset + 12 );
258 if (nRangeCount < 0)
260 SAL_WARN("vcl.gdi", "negative RangeCount");
261 nRangeCount = 0;
264 const int nGroupOffset = nOffset + 16;
265 const int nRemainingLen = nLength - nGroupOffset;
266 const int nMaxPossiblePairs = nRemainingLen / 12;
267 if (nRangeCount > nMaxPossiblePairs)
269 SAL_WARN("vcl.gdi", "more code pairs requested then space available");
270 nRangeCount = std::max(0, nMaxPossiblePairs);
273 pCodePairs = new sal_UCS4[ nRangeCount * 2 ];
274 pStartGlyphs = new int[ nRangeCount ];
276 const unsigned char* pGroup = pCmap + nGroupOffset;
277 sal_UCS4* pCP = pCodePairs;
278 for( int i = 0; i < nRangeCount; ++i )
280 sal_UCS4 cMinChar = GetUInt( pGroup + 0 );
281 sal_UCS4 cMaxChar = GetUInt( pGroup + 4 );
282 int nGlyphId = GetUInt( pGroup + 8 );
283 pGroup += 12;
285 if( cMinChar > cMaxChar ) { // no sane font should trigger this
286 SAL_WARN("vcl.gdi", "Min char should never be more than the max char!");
287 break;
290 *(pCP++) = cMinChar;
291 *(pCP++) = cMaxChar + 1;
292 pStartGlyphs[i] = nGlyphId;
294 nRangeCount = (pCP - pCodePairs) / 2;
297 // check if any subtable resulted in something usable
298 if( nRangeCount <= 0 )
300 delete[] pCodePairs;
301 delete[] pStartGlyphs;
303 // even when no CMAP is available we know it for symbol fonts
304 if( rResult.mbSymbolic )
306 pCodePairs = new sal_UCS4[4];
307 pCodePairs[0] = 0x0020; // aliased symbols
308 pCodePairs[1] = 0x0100;
309 pCodePairs[2] = 0xF020; // original symbols
310 pCodePairs[3] = 0xF100;
311 rResult.mpRangeCodes = pCodePairs;
312 rResult.mnRangeCount = 2;
313 return true;
316 return false;
319 // recode the code ranges to their unicode encoded ranges if needed
320 rtl_TextToUnicodeConverter aConverter = nullptr;
321 rtl_UnicodeToTextContext aCvtContext = nullptr;
323 rResult.mbRecoded = ( eRecodeFrom != RTL_TEXTENCODING_UNICODE );
324 if( rResult.mbRecoded )
326 aConverter = rtl_createTextToUnicodeConverter( eRecodeFrom );
327 aCvtContext = rtl_createTextToUnicodeContext( aConverter );
330 if( aConverter && aCvtContext )
332 // determine the set of supported code points from encoded ranges
333 o3tl::sorted_vector<sal_UCS4> aSupportedCodePoints;
334 aSupportedCodePoints.reserve(256);
336 static const int NINSIZE = 64;
337 static const int NOUTSIZE = 64;
338 std::vector<char> cCharsInp;
339 cCharsInp.reserve(NINSIZE);
340 sal_Unicode cCharsOut[ NOUTSIZE ];
341 sal_UCS4* pCP = pCodePairs;
342 for( int i = 0; i < nRangeCount; ++i )
344 sal_UCS4 cMin = *(pCP++);
345 sal_UCS4 cEnd = *(pCP++);
346 // ofz#25868 the conversion only makes sense with
347 // input codepoints in 0..SAL_MAX_UINT16 range
348 while (cMin < cEnd && cMin <= SAL_MAX_UINT16)
350 for (int j = 0; (cMin < cEnd) && (j < NINSIZE); ++cMin, ++j)
352 if( cMin >= 0x0100 )
353 cCharsInp.push_back(static_cast<char>(cMin >> 8));
354 if( (cMin >= 0x0100) || (cMin < 0x00A0) )
355 cCharsInp.push_back(static_cast<char>(cMin));
358 sal_uInt32 nCvtInfo;
359 sal_Size nSrcCvtBytes;
360 int nOutLen = rtl_convertTextToUnicode(
361 aConverter, aCvtContext,
362 cCharsInp.data(), cCharsInp.size(), cCharsOut, NOUTSIZE,
363 RTL_TEXTTOUNICODE_FLAGS_INVALID_IGNORE
364 | RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_IGNORE,
365 &nCvtInfo, &nSrcCvtBytes );
367 cCharsInp.clear();
369 for (int j = 0; j < nOutLen; ++j)
370 aSupportedCodePoints.insert( cCharsOut[j] );
374 rtl_destroyTextToUnicodeConverter( aCvtContext );
375 rtl_destroyTextToUnicodeConverter( aConverter );
377 // convert the set of supported code points to ranges
378 std::vector<sal_UCS4> aSupportedRanges;
380 for (auto const& supportedPoint : aSupportedCodePoints)
382 if( aSupportedRanges.empty()
383 || (aSupportedRanges.back() != supportedPoint) )
385 // add new range beginning with current unicode
386 aSupportedRanges.push_back(supportedPoint);
387 aSupportedRanges.push_back( 0 );
390 // extend existing range to include current unicode
391 aSupportedRanges.back() = supportedPoint + 1;
394 // glyph mapping for non-unicode fonts not implemented
395 delete[] pStartGlyphs;
396 pStartGlyphs = nullptr;
397 aGlyphIdArray.clear();
399 // make a pCodePairs array using the vector from above
400 delete[] pCodePairs;
401 nRangeCount = aSupportedRanges.size() / 2;
402 if( nRangeCount <= 0 )
403 return false;
404 pCodePairs = new sal_UCS4[ nRangeCount * 2 ];
405 pCP = pCodePairs;
406 for (auto const& supportedRange : aSupportedRanges)
407 *(pCP++) = supportedRange;
410 // prepare the glyphid-array if needed
411 // TODO: merge ranges if they are close enough?
412 sal_uInt16* pGlyphIds = nullptr;
413 if( !aGlyphIdArray.empty())
415 pGlyphIds = new sal_uInt16[ aGlyphIdArray.size() ];
416 sal_uInt16* pOut = pGlyphIds;
417 for (auto const& glyphId : aGlyphIdArray)
418 *(pOut++) = glyphId;
421 // update the result struct
422 rResult.mpRangeCodes = pCodePairs;
423 rResult.mpStartGlyphs = pStartGlyphs;
424 rResult.mnRangeCount = nRangeCount;
425 rResult.mpGlyphIds = pGlyphIds;
426 return true;
429 FontCharMap::FontCharMap()
430 : mpImplFontCharMap( ImplFontCharMap::getDefaultMap() )
434 FontCharMap::FontCharMap( ImplFontCharMapRef const & pIFCMap )
435 : mpImplFontCharMap( pIFCMap )
439 FontCharMap::FontCharMap( const CmapResult& rCR )
440 : mpImplFontCharMap(new ImplFontCharMap(rCR))
444 FontCharMap::~FontCharMap()
446 mpImplFontCharMap = nullptr;
449 FontCharMapRef FontCharMap::GetDefaultMap( bool bSymbol )
451 FontCharMapRef xFontCharMap( new FontCharMap( ImplFontCharMap::getDefaultMap( bSymbol ) ) );
452 return xFontCharMap;
455 bool FontCharMap::IsDefaultMap() const
457 return mpImplFontCharMap->isDefaultMap();
460 bool FontCharMap::isSymbolic() const { return mpImplFontCharMap->m_bSymbolic; }
462 int FontCharMap::GetCharCount() const
464 return mpImplFontCharMap->mnCharCount;
467 int FontCharMap::CountCharsInRange( sal_UCS4 cMin, sal_UCS4 cMax ) const
469 int nCount = 0;
471 // find and adjust range and char count for cMin
472 int nRangeMin = findRangeIndex( cMin );
473 if( nRangeMin & 1 )
474 ++nRangeMin;
475 else if( cMin > mpImplFontCharMap->mpRangeCodes[ nRangeMin ] )
476 nCount -= cMin - mpImplFontCharMap->mpRangeCodes[ nRangeMin ];
478 // find and adjust range and char count for cMax
479 int nRangeMax = findRangeIndex( cMax );
480 if( nRangeMax & 1 )
481 --nRangeMax;
482 else
483 nCount -= mpImplFontCharMap->mpRangeCodes[ nRangeMax+1 ] - cMax - 1;
485 // count chars in complete ranges between cMin and cMax
486 for( int i = nRangeMin; i <= nRangeMax; i+=2 )
487 nCount += mpImplFontCharMap->mpRangeCodes[i+1] - mpImplFontCharMap->mpRangeCodes[i];
489 return nCount;
492 bool FontCharMap::HasChar( sal_UCS4 cChar ) const
494 bool bHasChar = false;
496 if( mpImplFontCharMap->mpStartGlyphs == nullptr ) { // only the char-ranges are known
497 const int nRange = findRangeIndex( cChar );
498 if( nRange==0 && cChar < mpImplFontCharMap->mpRangeCodes[0] )
499 return false;
500 bHasChar = ((nRange & 1) == 0); // inside a range
501 } else { // glyph mapping is available
502 const int nGlyphIndex = GetGlyphIndex( cChar );
503 bHasChar = (nGlyphIndex != 0); // not the notdef-glyph
506 return bHasChar;
509 sal_UCS4 FontCharMap::GetFirstChar() const
511 return mpImplFontCharMap->mpRangeCodes[0];
514 sal_UCS4 FontCharMap::GetLastChar() const
516 return (mpImplFontCharMap->mpRangeCodes[ 2*mpImplFontCharMap->mnRangeCount-1 ] - 1);
519 sal_UCS4 FontCharMap::GetNextChar( sal_UCS4 cChar ) const
521 if( cChar < GetFirstChar() )
522 return GetFirstChar();
523 if( cChar >= GetLastChar() )
524 return GetLastChar();
526 int nRange = findRangeIndex( cChar + 1 );
527 if( nRange & 1 ) // outside of range?
528 return mpImplFontCharMap->mpRangeCodes[ nRange + 1 ]; // => first in next range
529 return (cChar + 1);
532 sal_UCS4 FontCharMap::GetPrevChar( sal_UCS4 cChar ) const
534 if( cChar <= GetFirstChar() )
535 return GetFirstChar();
536 if( cChar > GetLastChar() )
537 return GetLastChar();
539 int nRange = findRangeIndex( cChar - 1 );
540 if( nRange & 1 ) // outside a range?
541 return (mpImplFontCharMap->mpRangeCodes[ nRange ] - 1); // => last in prev range
542 return (cChar - 1);
545 int FontCharMap::GetIndexFromChar( sal_UCS4 cChar ) const
547 // TODO: improve linear walk?
548 int nCharIndex = 0;
549 const sal_UCS4* pRange = &mpImplFontCharMap->mpRangeCodes[0];
550 for( int i = 0; i < mpImplFontCharMap->mnRangeCount; ++i )
552 sal_UCS4 cFirst = *(pRange++);
553 sal_UCS4 cLast = *(pRange++);
554 if( cChar >= cLast )
555 nCharIndex += cLast - cFirst;
556 else if( cChar >= cFirst )
557 return nCharIndex + (cChar - cFirst);
558 else
559 break;
562 return -1;
565 sal_UCS4 FontCharMap::GetCharFromIndex( int nIndex ) const
567 // TODO: improve linear walk?
568 const sal_UCS4* pRange = &mpImplFontCharMap->mpRangeCodes[0];
569 for( int i = 0; i < mpImplFontCharMap->mnRangeCount; ++i )
571 sal_UCS4 cFirst = *(pRange++);
572 sal_UCS4 cLast = *(pRange++);
573 nIndex -= cLast - cFirst;
574 if( nIndex < 0 )
575 return (cLast + nIndex);
578 // we can only get here with an out-of-bounds charindex
579 return mpImplFontCharMap->mpRangeCodes[0];
582 int FontCharMap::findRangeIndex( sal_UCS4 cChar ) const
584 int nLower = 0;
585 int nMid = mpImplFontCharMap->mnRangeCount;
586 int nUpper = 2 * mpImplFontCharMap->mnRangeCount - 1;
587 while( nLower < nUpper )
589 if( cChar >= mpImplFontCharMap->mpRangeCodes[ nMid ] )
590 nLower = nMid;
591 else
592 nUpper = nMid - 1;
593 nMid = (nLower + nUpper + 1) / 2;
596 return nMid;
599 int FontCharMap::GetGlyphIndex( sal_UCS4 cChar ) const
601 // return -1 if the object doesn't know the glyph ids
602 if( !mpImplFontCharMap->mpStartGlyphs )
603 return -1;
605 // return 0 if the unicode doesn't have a matching glyph
606 int nRange = findRangeIndex( cChar );
607 // check that we are inside any range
608 if( (nRange == 0) && (cChar < mpImplFontCharMap->mpRangeCodes[0]) ) {
609 // symbol aliasing gives symbol fonts a second chance
610 const bool bSymbolic = cChar <= 0xFF && (mpImplFontCharMap->mpRangeCodes[0]>=0xF000) &&
611 (mpImplFontCharMap->mpRangeCodes[1]<=0xF0FF);
612 if( !bSymbolic )
613 return 0;
614 // check for symbol aliasing (U+F0xx -> U+00xx)
615 cChar |= 0xF000;
616 nRange = findRangeIndex( cChar );
617 if( (nRange == 0) && (cChar < mpImplFontCharMap->mpRangeCodes[0]) ) {
618 return 0;
621 // check that we are inside a range
622 if( (nRange & 1) != 0 )
623 return 0;
625 // get glyph index directly or indirectly
626 int nGlyphIndex = cChar - mpImplFontCharMap->mpRangeCodes[ nRange ];
627 const int nStartIndex = mpImplFontCharMap->mpStartGlyphs[ nRange/2 ];
628 if( nStartIndex >= 0 ) {
629 // the glyph index can be calculated
630 nGlyphIndex += nStartIndex;
631 } else {
632 // the glyphid array has the glyph index
633 nGlyphIndex = mpImplFontCharMap->mpGlyphIds[ nGlyphIndex - nStartIndex];
636 return nGlyphIndex;
639 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */