1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <memory> 21 #include <string.h> 22 23 #include <tools/debug.hxx> 24 #include <tools/fract.hxx> 25 #include <i18nlangtag/languagetag.hxx> 26 #include <i18nlangtag/mslangid.hxx> 27 #include <vcl/outdev.hxx> 28 #include <vcl/svapp.hxx> 29 #include <vcl/settings.hxx> 30 #include <sal/macros.h> 31 #include <svtools/strings.hrc> 32 #include <svtools/svtresid.hxx> 33 #include <svtools/ctrltool.hxx> 34 #include <o3tl/typed_flags_set.hxx> 35 #include <comphelper/lok.hxx> 36 37 // Standard fontsizes for scalable Fonts 38 const sal_IntPtr FontList::aStdSizeAry[] = 39 { 40 60, 41 70, 42 80, 43 90, 44 100, 45 105, 46 110, 47 120, 48 130, 49 140, 50 150, 51 160, 52 180, 53 200, 54 220, 55 240, 56 260, 57 280, 58 320, 59 360, 60 400, 61 440, 62 480, 63 540, 64 600, 65 660, 66 720, 67 800, 68 880, 69 960, 70 0 71 }; 72 73 namespace { 74 75 class ImplFontListFontMetric : public FontMetric 76 { 77 friend FontList; 78 79 private: 80 VclPtr<OutputDevice> mpDevice; 81 ImplFontListFontMetric* mpNext; 82 83 public: 84 ImplFontListFontMetric( const FontMetric& rInfo, 85 OutputDevice* pDev ) : 86 FontMetric( rInfo ), mpDevice(pDev), mpNext(nullptr) 87 { 88 } 89 90 OutputDevice* GetDevice() const { return mpDevice; } 91 }; 92 93 enum class FontListFontNameType 94 { 95 NONE = 0x00, 96 PRINTER = 0x01, 97 SCREEN = 0x02, 98 }; 99 100 } 101 102 namespace o3tl 103 { 104 template<> struct typed_flags<FontListFontNameType> : is_typed_flags<FontListFontNameType, 0x3> {}; 105 } 106 107 class ImplFontListNameInfo 108 { 109 friend class FontList; 110 111 private: 112 OUString maSearchName; 113 ImplFontListFontMetric* mpFirst; 114 FontListFontNameType mnType; 115 116 explicit ImplFontListNameInfo(const OUString& rSearchName) 117 : maSearchName(rSearchName) 118 , mpFirst(nullptr) 119 , mnType(FontListFontNameType::NONE) 120 { 121 } 122 }; 123 124 //sort normal to the start 125 static int sortWeightValue(FontWeight eWeight) 126 { 127 if (eWeight < WEIGHT_NORMAL) 128 return eWeight + 1; 129 if (eWeight > WEIGHT_NORMAL) 130 return eWeight - 1; 131 return 0; // eWeight == WEIGHT_NORMAL 132 } 133 134 static sal_Int32 ImplCompareFontMetric( ImplFontListFontMetric* pInfo1, 135 ImplFontListFontMetric* pInfo2 ) 136 { 137 //Sort non italic before italics 138 if ( pInfo1->GetItalic() < pInfo2->GetItalic() ) 139 return -1; 140 else if ( pInfo1->GetItalic() > pInfo2->GetItalic() ) 141 return 1; 142 143 //Sort normal weight to the start, followed by lightest to heaviest weights 144 int nWeight1 = sortWeightValue(pInfo1->GetWeight()); 145 int nWeight2 = sortWeightValue(pInfo2->GetWeight()); 146 147 if ( nWeight1 < nWeight2 ) 148 return -1; 149 else if ( nWeight1 > nWeight2 ) 150 return 1; 151 152 return pInfo1->GetStyleName().compareTo( pInfo2->GetStyleName() ); 153 } 154 155 static OUString ImplMakeSearchString(const OUString& rStr) 156 { 157 return rStr.toAsciiLowerCase(); 158 } 159 160 static OUString ImplMakeSearchStringFromName(const OUString& rStr) 161 { 162 // check for features before alternate font separator 163 sal_Int32 nColon = rStr.indexOf(':'); 164 sal_Int32 nSemiColon = rStr.indexOf(';'); 165 if (nColon != -1 && (nSemiColon == -1 || nColon < nSemiColon)) 166 return ImplMakeSearchString(rStr.getToken( 0, ':' )); 167 return ImplMakeSearchString(rStr.getToken( 0, ';' )); 168 } 169 170 ImplFontListNameInfo* FontList::ImplFind(const OUString& rSearchName, sal_uInt32* pIndex) const 171 { 172 // Append if there is no entry in the list or if the entry is larger 173 // then the last one. We only compare to the last entry as the list of VCL 174 // is returned sorted, which increases the probability that appending 175 // is more likely 176 if (m_Entries.empty()) 177 { 178 if ( pIndex ) 179 *pIndex = SAL_MAX_UINT32; 180 return nullptr; 181 } 182 else 183 { 184 const ImplFontListNameInfo* pCmpData = m_Entries.back().get(); 185 sal_Int32 nComp = rSearchName.compareTo( pCmpData->maSearchName ); 186 if (nComp > 0) 187 { 188 if ( pIndex ) 189 *pIndex = SAL_MAX_UINT32; 190 return nullptr; 191 } 192 else if (nComp == 0) 193 return const_cast<ImplFontListNameInfo*>(pCmpData); 194 } 195 196 // search fonts in the list 197 const ImplFontListNameInfo* pCompareData; 198 const ImplFontListNameInfo* pFoundData = nullptr; 199 size_t nLow = 0; 200 size_t nHigh = m_Entries.size() - 1; 201 size_t nMid; 202 203 do 204 { 205 nMid = (nLow + nHigh) / 2; 206 pCompareData = m_Entries[nMid].get(); 207 sal_Int32 nComp = rSearchName.compareTo(pCompareData->maSearchName); 208 if (nComp < 0) 209 { 210 if ( !nMid ) 211 break; 212 nHigh = nMid-1; 213 } 214 else 215 { 216 if (nComp > 0) 217 nLow = nMid + 1; 218 else 219 { 220 pFoundData = pCompareData; 221 break; 222 } 223 } 224 } 225 while ( nLow <= nHigh ); 226 227 if ( pIndex ) 228 { 229 sal_Int32 nComp = rSearchName.compareTo(pCompareData->maSearchName); 230 if (nComp > 0) 231 *pIndex = (nMid+1); 232 else 233 *pIndex = nMid; 234 } 235 236 return const_cast<ImplFontListNameInfo*>(pFoundData); 237 } 238 239 ImplFontListNameInfo* FontList::ImplFindByName(const OUString& rStr) const 240 { 241 OUString aSearchName = ImplMakeSearchStringFromName(rStr); 242 return ImplFind( aSearchName, nullptr ); 243 } 244 245 void FontList::ImplInsertFonts(OutputDevice* pDevice, bool bInsertData) 246 { 247 rtl_TextEncoding eSystemEncoding = osl_getThreadTextEncoding(); 248 249 FontListFontNameType nType; 250 if ( pDevice->GetOutDevType() != OUTDEV_PRINTER ) 251 nType = FontListFontNameType::SCREEN; 252 else 253 nType = FontListFontNameType::PRINTER; 254 255 // inquire all fonts from the device 256 int n = pDevice->GetDevFontCount(); 257 if (n == 0 && comphelper::LibreOfficeKit::isActive()) 258 { 259 pDevice->RefreshFontData(true); 260 n = pDevice->GetDevFontCount(); 261 } 262 263 for (int i = 0; i < n; ++i) 264 { 265 FontMetric aFontMetric = pDevice->GetDevFont( i ); 266 OUString aSearchName(aFontMetric.GetFamilyName()); 267 ImplFontListNameInfo* pData; 268 sal_uInt32 nIndex; 269 aSearchName = ImplMakeSearchString(aSearchName); 270 pData = ImplFind( aSearchName, &nIndex ); 271 272 if ( !pData ) 273 { 274 if ( bInsertData ) 275 { 276 ImplFontListFontMetric* pNewInfo = new ImplFontListFontMetric( aFontMetric, pDevice ); 277 pData = new ImplFontListNameInfo( aSearchName ); 278 pData->mpFirst = pNewInfo; 279 pNewInfo->mpNext = nullptr; 280 281 if (nIndex < static_cast<sal_uInt32>(m_Entries.size())) 282 m_Entries.insert(m_Entries.begin()+nIndex, 283 std::unique_ptr<ImplFontListNameInfo>(pData)); 284 else 285 m_Entries.push_back(std::unique_ptr<ImplFontListNameInfo>(pData)); 286 } 287 } 288 else 289 { 290 if ( bInsertData ) 291 { 292 bool bInsert = true; 293 ImplFontListFontMetric* pPrev = nullptr; 294 ImplFontListFontMetric* pTemp = pData->mpFirst; 295 ImplFontListFontMetric* pNewInfo = new ImplFontListFontMetric( aFontMetric, pDevice ); 296 while ( pTemp ) 297 { 298 sal_Int32 eComp = ImplCompareFontMetric( pNewInfo, pTemp ); 299 if ( eComp <= 0 ) 300 { 301 if ( eComp == 0 ) 302 { 303 // Overwrite charset, because charset should match 304 // with the system charset 305 if ( (pTemp->GetCharSet() != eSystemEncoding) && 306 (pNewInfo->GetCharSet() == eSystemEncoding) ) 307 { 308 ImplFontListFontMetric* pTemp2 = pTemp->mpNext; 309 *static_cast<FontMetric*>(pTemp) = *static_cast<FontMetric*>(pNewInfo); 310 pTemp->mpNext = pTemp2; 311 } 312 delete pNewInfo; 313 bInsert = false; 314 } 315 316 break; 317 } 318 319 pPrev = pTemp; 320 pTemp = pTemp->mpNext; 321 } 322 323 if ( bInsert ) 324 { 325 pNewInfo->mpNext = pTemp; 326 if ( pPrev ) 327 pPrev->mpNext = pNewInfo; 328 else 329 pData->mpFirst = pNewInfo; 330 } 331 } 332 } 333 334 if ( pData ) 335 pData->mnType |= nType; 336 } 337 } 338 339 FontList::FontList(OutputDevice* pDevice, OutputDevice* pDevice2) 340 { 341 // initialise variables 342 mpDev = pDevice; 343 mpDev2 = pDevice2; 344 345 // store style names 346 maLight = SvtResId(STR_SVT_STYLE_LIGHT); 347 maLightItalic = SvtResId(STR_SVT_STYLE_LIGHT_ITALIC); 348 maNormal = SvtResId(STR_SVT_STYLE_NORMAL); 349 maNormalItalic = SvtResId(STR_SVT_STYLE_NORMAL_ITALIC); 350 maBold = SvtResId(STR_SVT_STYLE_BOLD); 351 maBoldItalic = SvtResId(STR_SVT_STYLE_BOLD_ITALIC); 352 maBlack = SvtResId(STR_SVT_STYLE_BLACK); 353 maBlackItalic = SvtResId(STR_SVT_STYLE_BLACK_ITALIC); 354 355 ImplInsertFonts(pDevice, true); 356 357 // if required compare to the screen fonts 358 // in order to map the duplicates to Equal 359 bool bCompareWindow = false; 360 if ( !pDevice2 && (pDevice->GetOutDevType() == OUTDEV_PRINTER) ) 361 { 362 bCompareWindow = true; 363 pDevice2 = Application::GetDefaultDevice(); 364 } 365 366 if ( pDevice2 && 367 (pDevice2->GetOutDevType() != pDevice->GetOutDevType()) ) 368 ImplInsertFonts(pDevice2, !bCompareWindow); 369 } 370 371 FontList::~FontList() 372 { 373 // delete FontMetrics 374 ImplFontListFontMetric *pTemp, *pInfo; 375 for (auto const& it : m_Entries) 376 { 377 pInfo = it->mpFirst; 378 while ( pInfo ) 379 { 380 pTemp = pInfo->mpNext; 381 delete pInfo; 382 pInfo = pTemp; 383 } 384 } 385 } 386 387 std::unique_ptr<FontList> FontList::Clone() const 388 { 389 return std::unique_ptr<FontList>(new FontList(mpDev, mpDev2)); 390 } 391 392 const OUString& FontList::GetStyleName(FontWeight eWeight, FontItalic eItalic) const 393 { 394 if ( eWeight > WEIGHT_BOLD ) 395 { 396 if ( eItalic > ITALIC_NONE ) 397 return maBlackItalic; 398 else 399 return maBlack; 400 } 401 else if ( eWeight > WEIGHT_MEDIUM ) 402 { 403 if ( eItalic > ITALIC_NONE ) 404 return maBoldItalic; 405 else 406 return maBold; 407 } 408 else if ( eWeight > WEIGHT_LIGHT ) 409 { 410 if ( eItalic > ITALIC_NONE ) 411 return maNormalItalic; 412 else 413 return maNormal; 414 } 415 else if ( eWeight != WEIGHT_DONTKNOW ) 416 { 417 if ( eItalic > ITALIC_NONE ) 418 return maLightItalic; 419 else 420 return maLight; 421 } 422 else 423 { 424 if ( eItalic > ITALIC_NONE ) 425 return maNormalItalic; 426 else 427 return maNormal; 428 } 429 } 430 431 OUString FontList::GetStyleName(const FontMetric& rInfo) const 432 { 433 OUString aStyleName = rInfo.GetStyleName(); 434 FontWeight eWeight = rInfo.GetWeight(); 435 FontItalic eItalic = rInfo.GetItalic(); 436 437 // return synthetic Name if no StyleName was set 438 if (aStyleName.isEmpty()) 439 aStyleName = GetStyleName(eWeight, eItalic); 440 else 441 { 442 // Translate StyleName to localized name 443 OUString aCompareStyleName = aStyleName.toAsciiLowerCase().replaceAll(" ", ""); 444 if (aCompareStyleName == "bold") 445 aStyleName = maBold; 446 else if (aCompareStyleName == "bolditalic") 447 aStyleName = maBoldItalic; 448 else if (aCompareStyleName == "italic") 449 aStyleName = maNormalItalic; 450 else if (aCompareStyleName == "standard") 451 aStyleName = maNormal; 452 else if (aCompareStyleName == "regular") 453 aStyleName = maNormal; 454 else if (aCompareStyleName == "medium") 455 aStyleName = maNormal; 456 else if (aCompareStyleName == "light") 457 aStyleName = maLight; 458 else if (aCompareStyleName == "lightitalic") 459 aStyleName = maLightItalic; 460 else if (aCompareStyleName == "black") 461 aStyleName = maBlack; 462 else if (aCompareStyleName == "blackitalic") 463 aStyleName = maBlackItalic; 464 /* tdf#107700 support some less common style names with localization */ 465 else if (aCompareStyleName == "book") 466 aStyleName = SvtResId(STR_SVT_STYLE_BOOK); 467 else if (aCompareStyleName == "boldoblique") 468 aStyleName = SvtResId(STR_SVT_STYLE_BOLD_OBLIQUE); 469 else if (aCompareStyleName == "condensed") 470 aStyleName = SvtResId(STR_SVT_STYLE_CONDENSED); 471 else if (aCompareStyleName == "condensedbold") 472 aStyleName = SvtResId(STR_SVT_STYLE_CONDENSED_BOLD); 473 else if (aCompareStyleName == "condensedbolditalic") 474 aStyleName = SvtResId(STR_SVT_STYLE_CONDENSED_BOLD_ITALIC); 475 else if (aCompareStyleName == "condensedboldoblique") 476 aStyleName = SvtResId(STR_SVT_STYLE_CONDENSED_BOLD_OBLIQUE); 477 else if (aCompareStyleName == "condenseditalic") 478 aStyleName = SvtResId(STR_SVT_STYLE_CONDENSED_ITALIC); 479 else if (aCompareStyleName == "condensedoblique") 480 aStyleName = SvtResId(STR_SVT_STYLE_CONDENSED_OBLIQUE); 481 else if (aCompareStyleName == "extralight") 482 aStyleName = SvtResId(STR_SVT_STYLE_EXTRALIGHT); 483 else if (aCompareStyleName == "extralightitalic") 484 aStyleName = SvtResId(STR_SVT_STYLE_EXTRALIGHT_ITALIC); 485 /* Medium is synonym with Normal */ 486 else if (aCompareStyleName == "mediumitalic") 487 aStyleName = maNormalItalic; 488 else if (aCompareStyleName == "oblique") 489 aStyleName = SvtResId(STR_SVT_STYLE_OBLIQUE); 490 else if (aCompareStyleName == "semibold") 491 aStyleName = SvtResId(STR_SVT_STYLE_SEMIBOLD); 492 else if (aCompareStyleName == "semibolditalic") 493 aStyleName = SvtResId(STR_SVT_STYLE_SEMIBOLD_ITALIC); 494 495 // fix up StyleName, because the PS Printer driver from 496 // W2000 returns wrong StyleNames (e.g. Bold instead of Bold Italic 497 // for Helvetica) 498 if ( eItalic > ITALIC_NONE ) 499 { 500 if ( (aStyleName == maNormal) || 501 (aStyleName == maBold) || 502 (aStyleName == maLight) || 503 (aStyleName == maBlack) ) 504 aStyleName = GetStyleName( eWeight, eItalic ); 505 } 506 } 507 508 return aStyleName; 509 } 510 511 OUString FontList::GetFontMapText( const FontMetric& rInfo ) const 512 { 513 if ( rInfo.GetFamilyName().isEmpty() ) 514 { 515 return OUString(); 516 } 517 518 // Search Fontname 519 ImplFontListNameInfo* pData = ImplFindByName( rInfo.GetFamilyName() ); 520 if ( !pData ) 521 { 522 if (maMapNotAvailable.isEmpty()) 523 maMapNotAvailable = SvtResId(STR_SVT_FONTMAP_NOTAVAILABLE); 524 return maMapNotAvailable; 525 } 526 527 // search for synthetic style 528 FontListFontNameType nType = pData->mnType; 529 const OUString& rStyleName = rInfo.GetStyleName(); 530 if (!rStyleName.isEmpty()) 531 { 532 bool bNotSynthetic = false; 533 FontWeight eWeight = rInfo.GetWeight(); 534 FontItalic eItalic = rInfo.GetItalic(); 535 ImplFontListFontMetric* pFontMetric = pData->mpFirst; 536 while ( pFontMetric ) 537 { 538 if ( (eWeight == pFontMetric->GetWeight()) && 539 (eItalic == pFontMetric->GetItalic()) ) 540 { 541 bNotSynthetic = true; 542 break; 543 } 544 545 pFontMetric = pFontMetric->mpNext; 546 } 547 548 if ( !bNotSynthetic ) 549 { 550 if (maMapStyleNotAvailable.isEmpty()) 551 const_cast<FontList*>(this)->maMapStyleNotAvailable = SvtResId(STR_SVT_FONTMAP_STYLENOTAVAILABLE); 552 return maMapStyleNotAvailable; 553 } 554 } 555 556 // Only Printer-Font? 557 if ( nType == FontListFontNameType::PRINTER ) 558 { 559 if (maMapPrinterOnly.isEmpty()) 560 const_cast<FontList*>(this)->maMapPrinterOnly = SvtResId(STR_SVT_FONTMAP_PRINTERONLY); 561 return maMapPrinterOnly; 562 } 563 else 564 { 565 if (maMapBoth.isEmpty()) 566 const_cast<FontList*>(this)->maMapBoth = SvtResId(STR_SVT_FONTMAP_BOTH); 567 return maMapBoth; 568 } 569 } 570 571 namespace 572 { 573 FontMetric makeMissing(ImplFontListFontMetric const * pFontNameInfo, const OUString &rName, 574 FontWeight eWeight, FontItalic eItalic) 575 { 576 FontMetric aInfo; 577 // if the fontname matches, we copy as much as possible 578 if (pFontNameInfo) 579 { 580 aInfo = *pFontNameInfo; 581 aInfo.SetStyleName(OUString()); 582 } 583 584 aInfo.SetWeight(eWeight); 585 aInfo.SetItalic(eItalic); 586 587 //If this is a known but uninstalled symbol font which we can remap to 588 //OpenSymbol then toggle its charset to be a symbol font 589 if (ConvertChar::GetRecodeData(rName, "OpenSymbol")) 590 aInfo.SetCharSet(RTL_TEXTENCODING_SYMBOL); 591 592 return aInfo; 593 } 594 } 595 596 FontMetric FontList::Get(const OUString& rName, const OUString& rStyleName) const 597 { 598 ImplFontListNameInfo* pData = ImplFindByName( rName ); 599 ImplFontListFontMetric* pFontMetric = nullptr; 600 ImplFontListFontMetric* pFontNameInfo = nullptr; 601 if ( pData ) 602 { 603 ImplFontListFontMetric* pSearchInfo = pData->mpFirst; 604 pFontNameInfo = pSearchInfo; 605 pSearchInfo = pData->mpFirst; 606 while ( pSearchInfo ) 607 { 608 if (rStyleName.equalsIgnoreAsciiCase(GetStyleName(*pSearchInfo))) 609 { 610 pFontMetric = pSearchInfo; 611 break; 612 } 613 614 pSearchInfo = pSearchInfo->mpNext; 615 } 616 } 617 618 // reproduce attributes if data could not be found 619 FontMetric aInfo; 620 if ( !pFontMetric ) 621 { 622 FontWeight eWeight = WEIGHT_DONTKNOW; 623 FontItalic eItalic = ITALIC_NONE; 624 625 if ( rStyleName == maNormal ) 626 { 627 eItalic = ITALIC_NONE; 628 eWeight = WEIGHT_NORMAL; 629 } 630 else if ( rStyleName == maNormalItalic ) 631 { 632 eItalic = ITALIC_NORMAL; 633 eWeight = WEIGHT_NORMAL; 634 } 635 else if ( rStyleName == maBold ) 636 { 637 eItalic = ITALIC_NONE; 638 eWeight = WEIGHT_BOLD; 639 } 640 else if ( rStyleName == maBoldItalic ) 641 { 642 eItalic = ITALIC_NORMAL; 643 eWeight = WEIGHT_BOLD; 644 } 645 else if ( rStyleName == maLight ) 646 { 647 eItalic = ITALIC_NONE; 648 eWeight = WEIGHT_LIGHT; 649 } 650 else if ( rStyleName == maLightItalic ) 651 { 652 eItalic = ITALIC_NORMAL; 653 eWeight = WEIGHT_LIGHT; 654 } 655 else if ( rStyleName == maBlack ) 656 { 657 eItalic = ITALIC_NONE; 658 eWeight = WEIGHT_BLACK; 659 } 660 else if ( rStyleName == maBlackItalic ) 661 { 662 eItalic = ITALIC_NORMAL; 663 eWeight = WEIGHT_BLACK; 664 } 665 aInfo = makeMissing(pFontNameInfo, rName, eWeight, eItalic); 666 } 667 else 668 aInfo = *pFontMetric; 669 670 // set Fontname to keep FontAlias 671 aInfo.SetFamilyName( rName ); 672 aInfo.SetStyleName( rStyleName ); 673 674 return aInfo; 675 } 676 677 FontMetric FontList::Get(const OUString& rName, 678 FontWeight eWeight, FontItalic eItalic) const 679 { 680 ImplFontListNameInfo* pData = ImplFindByName( rName ); 681 ImplFontListFontMetric* pFontMetric = nullptr; 682 ImplFontListFontMetric* pFontNameInfo = nullptr; 683 if ( pData ) 684 { 685 ImplFontListFontMetric* pSearchInfo = pData->mpFirst; 686 pFontNameInfo = pSearchInfo; 687 while ( pSearchInfo ) 688 { 689 if ( (eWeight == pSearchInfo->GetWeight()) && 690 (eItalic == pSearchInfo->GetItalic()) ) 691 { 692 pFontMetric = pSearchInfo; 693 break; 694 } 695 696 pSearchInfo = pSearchInfo->mpNext; 697 } 698 } 699 700 // reproduce attributes if data could not be found 701 FontMetric aInfo; 702 if ( !pFontMetric ) 703 aInfo = makeMissing(pFontNameInfo, rName, eWeight, eItalic); 704 else 705 aInfo = *pFontMetric; 706 707 // set Fontname to keep FontAlias 708 aInfo.SetFamilyName( rName ); 709 710 return aInfo; 711 } 712 713 bool FontList::IsAvailable(const OUString& rName) const 714 { 715 return (ImplFindByName( rName ) != nullptr); 716 } 717 718 const FontMetric& FontList::GetFontName(size_t const nFont) const 719 { 720 DBG_ASSERT( nFont < GetFontNameCount(), "FontList::GetFontName(): nFont >= Count" ); 721 722 return *(m_Entries[nFont]->mpFirst); 723 } 724 725 sal_Handle FontList::GetFirstFontMetric(const OUString& rName) const 726 { 727 ImplFontListNameInfo* pData = ImplFindByName( rName ); 728 if ( !pData ) 729 return nullptr; 730 else 731 return static_cast<sal_Handle>(pData->mpFirst); 732 } 733 734 sal_Handle FontList::GetNextFontMetric( sal_Handle hFontMetric ) 735 { 736 ImplFontListFontMetric* pInfo = static_cast<ImplFontListFontMetric*>(hFontMetric); 737 return static_cast<sal_Handle>(pInfo->mpNext); 738 } 739 740 const FontMetric& FontList::GetFontMetric( sal_Handle hFontMetric ) 741 { 742 ImplFontListFontMetric* pInfo = static_cast<ImplFontListFontMetric*>(hFontMetric); 743 return *pInfo; 744 } 745 746 const sal_IntPtr* FontList::GetSizeAry( const FontMetric& rInfo ) const 747 { 748 // first delete Size-Array 749 mpSizeAry.reset(); 750 751 // use standard sizes if no name 752 if ( rInfo.GetFamilyName().isEmpty() ) 753 return aStdSizeAry; 754 755 // first search fontname in order to use device from the matching font 756 OutputDevice* pDevice = mpDev; 757 ImplFontListNameInfo* pData = ImplFindByName( rInfo.GetFamilyName() ); 758 if ( pData ) 759 pDevice = pData->mpFirst->GetDevice(); 760 761 int nDevSizeCount = pDevice->GetDevFontSizeCount( rInfo ); 762 if ( !nDevSizeCount || 763 (pDevice->GetDevFontSize( rInfo, 0 ).Height() == 0) ) 764 return aStdSizeAry; 765 766 MapMode aOldMapMode = pDevice->GetMapMode(); 767 MapMode aMap( MapUnit::Map10thInch, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) ); 768 pDevice->SetMapMode( aMap ); 769 770 int nRealCount = 0; 771 long nOldHeight = 0; 772 mpSizeAry.reset(new sal_IntPtr[nDevSizeCount+1] ); 773 for (int i = 0; i < nDevSizeCount; ++i) 774 { 775 Size aSize = pDevice->GetDevFontSize( rInfo, i ); 776 if ( aSize.Height() != nOldHeight ) 777 { 778 nOldHeight = aSize.Height(); 779 mpSizeAry[nRealCount] = nOldHeight; 780 nRealCount++; 781 } 782 } 783 mpSizeAry[nRealCount] = 0; 784 785 pDevice->SetMapMode( aOldMapMode ); 786 return mpSizeAry.get(); 787 } 788 789 struct ImplFSNameItem 790 { 791 sal_Int32 mnSize; 792 const char* mszUtf8Name; 793 }; 794 795 static const ImplFSNameItem aImplSimplifiedChinese[] = 796 { 797 { 50, "\xe5\x85\xab\xe5\x8f\xb7" }, 798 { 55, "\xe4\xb8\x83\xe5\x8f\xb7" }, 799 { 65, "\xe5\xb0\x8f\xe5\x85\xad" }, 800 { 75, "\xe5\x85\xad\xe5\x8f\xb7" }, 801 { 90, "\xe5\xb0\x8f\xe4\xba\x94" }, 802 { 105, "\xe4\xba\x94\xe5\x8f\xb7" }, 803 { 120, "\xe5\xb0\x8f\xe5\x9b\x9b" }, 804 { 140, "\xe5\x9b\x9b\xe5\x8f\xb7" }, 805 { 150, "\xe5\xb0\x8f\xe4\xb8\x89" }, 806 { 160, "\xe4\xb8\x89\xe5\x8f\xb7" }, 807 { 180, "\xe5\xb0\x8f\xe4\xba\x8c" }, 808 { 220, "\xe4\xba\x8c\xe5\x8f\xb7" }, 809 { 240, "\xe5\xb0\x8f\xe4\xb8\x80" }, 810 { 260, "\xe4\xb8\x80\xe5\x8f\xb7" }, 811 { 360, "\xe5\xb0\x8f\xe5\x88\x9d" }, 812 { 420, "\xe5\x88\x9d\xe5\x8f\xb7" } 813 }; 814 815 FontSizeNames::FontSizeNames( LanguageType eLanguage ) 816 { 817 if ( eLanguage == LANGUAGE_DONTKNOW ) 818 eLanguage = Application::GetSettings().GetUILanguageTag().getLanguageType(); 819 if ( eLanguage == LANGUAGE_SYSTEM ) 820 eLanguage = MsLangId::getSystemUILanguage(); 821 822 if (MsLangId::isSimplifiedChinese(eLanguage)) 823 { 824 // equivalent for traditional chinese disabled by popular request, #i89077# 825 mpArray = aImplSimplifiedChinese; 826 mnElem = SAL_N_ELEMENTS(aImplSimplifiedChinese); 827 } 828 else 829 { 830 mpArray = nullptr; 831 mnElem = 0; 832 } 833 } 834 835 sal_Int32 FontSizeNames::Name2Size( const OUString& rName ) const 836 { 837 if ( mnElem ) 838 { 839 OString aName(OUStringToOString(rName, 840 RTL_TEXTENCODING_UTF8)); 841 842 // linear search is sufficient for this rare case 843 for( long i = mnElem; --i >= 0; ) 844 if ( aName == mpArray[i].mszUtf8Name ) 845 return mpArray[i].mnSize; 846 } 847 848 return 0; 849 } 850 851 OUString FontSizeNames::Size2Name( sal_Int32 nValue ) const 852 { 853 OUString aStr; 854 855 // binary search 856 for( long lower = 0, upper = mnElem - 1; lower <= upper; ) 857 { 858 long mid = (upper + lower) >> 1; 859 if ( nValue == mpArray[mid].mnSize ) 860 { 861 aStr = OUString( mpArray[mid].mszUtf8Name, strlen(mpArray[mid].mszUtf8Name), RTL_TEXTENCODING_UTF8 ); 862 break; 863 } 864 else if ( nValue < mpArray[mid].mnSize ) 865 upper = mid - 1; 866 else /* ( nValue > mpArray[mid].mnSize ) */ 867 lower = mid + 1; 868 } 869 870 return aStr; 871 } 872 873 OUString FontSizeNames::GetIndexName( sal_Int32 nIndex ) const 874 { 875 OUString aStr; 876 877 if ( nIndex < mnElem ) 878 aStr = OUString( mpArray[nIndex].mszUtf8Name, strlen(mpArray[nIndex].mszUtf8Name), RTL_TEXTENCODING_UTF8 ); 879 880 return aStr; 881 } 882 883 sal_Int32 FontSizeNames::GetIndexSize( sal_Int32 nIndex ) const 884 { 885 if ( nIndex >= mnElem ) 886 return 0; 887 return mpArray[nIndex].mnSize; 888 } 889 890 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 891
