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