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