2014-03-20 00:22:26 -05:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
|
|
/*
|
|
|
|
* This file is part of the LibreOffice project.
|
|
|
|
*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*
|
|
|
|
* This file incorporates work covered by the following license notice:
|
|
|
|
*
|
|
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
|
|
* with this work for additional information regarding copyright
|
|
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
|
|
*/
|
|
|
|
|
2016-01-25 23:58:27 +11:00
|
|
|
#include <i18nlangtag/mslangid.hxx>
|
|
|
|
#include <unotools/configmgr.hxx>
|
2016-01-29 13:23:58 +11:00
|
|
|
#include <unotools/fontdefs.hxx>
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
#include "outdev.h"
|
|
|
|
#include "PhysicalFontCollection.hxx"
|
|
|
|
|
2015-05-04 14:05:14 +02:00
|
|
|
static ImplFontAttrs lcl_IsCJKFont( const OUString& rFontName )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
// Test, if Fontname includes CJK characters --> In this case we
|
|
|
|
// mention that it is a CJK font
|
|
|
|
for(int i = 0; i < rFontName.getLength(); i++)
|
|
|
|
{
|
|
|
|
const sal_Unicode ch = rFontName[i];
|
|
|
|
// japanese
|
|
|
|
if ( ((ch >= 0x3040) && (ch <= 0x30FF)) ||
|
|
|
|
((ch >= 0x3190) && (ch <= 0x319F)) )
|
2015-05-04 14:05:14 +02:00
|
|
|
return ImplFontAttrs::CJK|ImplFontAttrs::CJK_JP;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// korean
|
|
|
|
if ( ((ch >= 0xAC00) && (ch <= 0xD7AF)) ||
|
|
|
|
((ch >= 0x3130) && (ch <= 0x318F)) ||
|
|
|
|
((ch >= 0x1100) && (ch <= 0x11FF)) )
|
2015-05-04 14:05:14 +02:00
|
|
|
return ImplFontAttrs::CJK|ImplFontAttrs::CJK_KR;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// chinese
|
|
|
|
if ( ((ch >= 0x3400) && (ch <= 0x9FFF)) )
|
2015-05-04 14:05:14 +02:00
|
|
|
return ImplFontAttrs::CJK|ImplFontAttrs::CJK_TC|ImplFontAttrs::CJK_SC;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// cjk
|
|
|
|
if ( ((ch >= 0x3000) && (ch <= 0xD7AF)) ||
|
|
|
|
((ch >= 0xFF00) && (ch <= 0xFFEE)) )
|
2015-05-04 14:05:14 +02:00
|
|
|
return ImplFontAttrs::CJK;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-05-04 14:05:14 +02:00
|
|
|
return ImplFontAttrs::None;
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
PhysicalFontCollection::PhysicalFontCollection()
|
|
|
|
: mbMatchData( false )
|
|
|
|
, mbMapNames( false )
|
2015-11-10 10:28:29 +01:00
|
|
|
, mpPreMatchHook( nullptr )
|
|
|
|
, mpFallbackHook( nullptr )
|
|
|
|
, mpFallbackList( nullptr )
|
2014-03-20 00:22:26 -05:00
|
|
|
, mnFallbackCount( -1 )
|
|
|
|
{}
|
|
|
|
|
|
|
|
PhysicalFontCollection::~PhysicalFontCollection()
|
|
|
|
{
|
|
|
|
Clear();
|
|
|
|
}
|
|
|
|
|
2015-10-07 12:55:17 +01:00
|
|
|
void PhysicalFontCollection::SetPreMatchHook( ImplPreMatchFontSubstitution* pHook )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
mpPreMatchHook = pHook;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicalFontCollection::SetFallbackHook( ImplGlyphFallbackFontSubstitution* pHook )
|
|
|
|
{
|
|
|
|
mpFallbackHook = pHook;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicalFontCollection::Clear()
|
|
|
|
{
|
|
|
|
// remove fallback lists
|
|
|
|
delete[] mpFallbackList;
|
2015-11-10 10:28:29 +01:00
|
|
|
mpFallbackList = nullptr;
|
2014-03-20 00:22:26 -05:00
|
|
|
mnFallbackCount = -1;
|
|
|
|
|
|
|
|
// clear all entries in the device font list
|
|
|
|
PhysicalFontFamilies::iterator it = maPhysicalFontFamilies.begin();
|
|
|
|
for(; it != maPhysicalFontFamilies.end(); ++it )
|
|
|
|
{
|
|
|
|
PhysicalFontFamily* pEntry = (*it).second;
|
|
|
|
delete pEntry;
|
|
|
|
}
|
|
|
|
|
|
|
|
maPhysicalFontFamilies.clear();
|
|
|
|
|
|
|
|
// match data must be recalculated too
|
|
|
|
mbMatchData = false;
|
|
|
|
}
|
|
|
|
|
2015-12-23 11:03:02 +11:00
|
|
|
void PhysicalFontCollection::ImplInitGenericGlyphFallback() const
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
// normalized family names of fonts suited for glyph fallback
|
|
|
|
// if a font is available related fonts can be ignored
|
|
|
|
// TODO: implement dynamic lists
|
|
|
|
static const char* aGlyphFallbackList[] = {
|
|
|
|
// empty strings separate the names of unrelated fonts
|
|
|
|
"eudc", "",
|
|
|
|
"arialunicodems", "cyberbit", "code2000", "",
|
|
|
|
"andalesansui", "",
|
|
|
|
"starsymbol", "opensymbol", "",
|
|
|
|
"msmincho", "fzmingti", "fzheiti", "ipamincho", "sazanamimincho", "kochimincho", "",
|
|
|
|
"sunbatang", "sundotum", "baekmukdotum", "gulim", "batang", "dotum", "",
|
|
|
|
"hgmincholightj", "msunglightsc", "msunglighttc", "hymyeongjolightk", "",
|
|
|
|
"tahoma", "dejavusans", "timesnewroman", "liberationsans", "",
|
|
|
|
"shree", "mangal", "",
|
|
|
|
"raavi", "shruti", "tunga", "",
|
|
|
|
"latha", "gautami", "kartika", "vrinda", "",
|
|
|
|
"shayyalmt", "naskmt", "scheherazade", "",
|
|
|
|
"david", "nachlieli", "lucidagrande", "",
|
|
|
|
"norasi", "angsanaupc", "",
|
|
|
|
"khmerossystem", "",
|
|
|
|
"muktinarrow", "",
|
|
|
|
"phetsarathot", "",
|
|
|
|
"padauk", "pinlonmyanmar", "",
|
|
|
|
"iskoolapota", "lklug", "",
|
2015-11-10 10:28:29 +01:00
|
|
|
nullptr
|
2014-03-20 00:22:26 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
bool bHasEudc = false;
|
|
|
|
int nMaxLevel = 0;
|
|
|
|
int nBestQuality = 0;
|
2015-11-10 10:28:29 +01:00
|
|
|
PhysicalFontFamily** pFallbackList = nullptr;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
for( const char** ppNames = &aGlyphFallbackList[0];; ++ppNames )
|
|
|
|
{
|
|
|
|
// advance to next sub-list when end-of-sublist marker
|
|
|
|
if( !**ppNames ) // #i46456# check for empty string, i.e., deref string itself not only ptr to it
|
|
|
|
{
|
|
|
|
if( nBestQuality > 0 )
|
2016-01-25 22:03:45 +11:00
|
|
|
if( ++nMaxLevel >= MAX_GLYPHFALLBACK )
|
2014-03-20 00:22:26 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
if( !ppNames[1] )
|
|
|
|
break;
|
|
|
|
|
|
|
|
nBestQuality = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test if the glyph fallback candidate font is available and scalable
|
|
|
|
OUString aTokenName( *ppNames, strlen(*ppNames), RTL_TEXTENCODING_UTF8 );
|
|
|
|
PhysicalFontFamily* pFallbackFont = FindFontFamily( aTokenName );
|
|
|
|
|
|
|
|
if( !pFallbackFont )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( !pFallbackFont->IsScalable() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// keep the best font of the glyph fallback sub-list
|
|
|
|
if( nBestQuality < pFallbackFont->GetMinQuality() )
|
|
|
|
{
|
|
|
|
nBestQuality = pFallbackFont->GetMinQuality();
|
|
|
|
// store available glyph fallback fonts
|
|
|
|
if( !pFallbackList )
|
2016-01-25 22:03:45 +11:00
|
|
|
pFallbackList = new PhysicalFontFamily*[ MAX_GLYPHFALLBACK ];
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
pFallbackList[ nMaxLevel ] = pFallbackFont;
|
|
|
|
if( !bHasEudc && !nMaxLevel )
|
|
|
|
bHasEudc = !strncmp( *ppNames, "eudc", 5 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mnFallbackCount = nMaxLevel;
|
|
|
|
mpFallbackList = pFallbackList;
|
|
|
|
}
|
|
|
|
|
|
|
|
PhysicalFontFamily* PhysicalFontCollection::GetGlyphFallbackFont( FontSelectPattern& rFontSelData,
|
|
|
|
OUString& rMissingCodes,
|
|
|
|
int nFallbackLevel ) const
|
|
|
|
{
|
2015-11-10 10:28:29 +01:00
|
|
|
PhysicalFontFamily* pFallbackData = nullptr;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// find a matching font candidate for platform specific glyph fallback
|
|
|
|
if( mpFallbackHook )
|
|
|
|
{
|
|
|
|
// check cache for the first matching entry
|
|
|
|
// to avoid calling the expensive fallback hook (#i83491#)
|
|
|
|
sal_UCS4 cChar = 0;
|
|
|
|
bool bCached = true;
|
|
|
|
sal_Int32 nStrIndex = 0;
|
|
|
|
while( nStrIndex < rMissingCodes.getLength() )
|
|
|
|
{
|
|
|
|
cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
|
2016-01-08 21:04:23 +11:00
|
|
|
bCached = rFontSelData.mpFontInstance->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// ignore entries which don't have a fallback
|
|
|
|
if( !bCached || !rFontSelData.maSearchName.isEmpty() )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( bCached )
|
|
|
|
{
|
|
|
|
// there is a matching fallback in the cache
|
|
|
|
// so update rMissingCodes with codepoints not yet resolved by this fallback
|
|
|
|
int nRemainingLength = 0;
|
2015-09-29 14:25:23 +02:00
|
|
|
std::unique_ptr<sal_UCS4[]> const pRemainingCodes(new sal_UCS4[rMissingCodes.getLength()]);
|
2014-03-20 00:22:26 -05:00
|
|
|
OUString aFontName;
|
|
|
|
|
|
|
|
while( nStrIndex < rMissingCodes.getLength() )
|
|
|
|
{
|
|
|
|
cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
|
2016-01-08 21:04:23 +11:00
|
|
|
bCached = rFontSelData.mpFontInstance->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &aFontName );
|
2014-03-20 00:22:26 -05:00
|
|
|
if( !bCached || (rFontSelData.maSearchName != aFontName) )
|
|
|
|
pRemainingCodes[ nRemainingLength++ ] = cChar;
|
|
|
|
}
|
2015-09-29 14:25:23 +02:00
|
|
|
rMissingCodes = OUString( pRemainingCodes.get(), nRemainingLength );
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
OUString aOldMissingCodes = rMissingCodes;
|
|
|
|
|
|
|
|
// call the hook to query the best matching glyph fallback font
|
|
|
|
if( mpFallbackHook->FindFontSubstitute( rFontSelData, rMissingCodes ) )
|
|
|
|
// apply outdev3.cxx specific fontname normalization
|
2014-08-22 00:08:04 +01:00
|
|
|
rFontSelData.maSearchName = GetEnglishSearchFontName( rFontSelData.maSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
else
|
2014-12-18 13:39:25 +01:00
|
|
|
rFontSelData.maSearchName.clear();
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// See fdo#32665 for an example. FreeSerif that has glyphs in normal
|
|
|
|
// font, but not in the italic or bold version
|
|
|
|
bool bSubSetOfFontRequiresPropertyFaking = rFontSelData.mbEmbolden || rFontSelData.maItalicMatrix != ItalicMatrix();
|
|
|
|
|
|
|
|
// Cache the result even if there was no match, unless its from part of a font for which the properties need
|
|
|
|
// to be faked. We need to rework this cache to take into account that fontconfig can return different fonts
|
|
|
|
// for different input sizes, weights, etc. Basically the cache is way to naive
|
|
|
|
if (!bSubSetOfFontRequiresPropertyFaking)
|
|
|
|
{
|
|
|
|
for(;;)
|
|
|
|
{
|
2016-01-08 21:04:23 +11:00
|
|
|
if( !rFontSelData.mpFontInstance->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
|
|
|
|
rFontSelData.mpFontInstance->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
if( nStrIndex >= aOldMissingCodes.getLength() )
|
|
|
|
break;
|
|
|
|
cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
|
|
|
|
}
|
|
|
|
if( !rFontSelData.maSearchName.isEmpty() )
|
|
|
|
{
|
|
|
|
// remove cache entries that were still not resolved
|
|
|
|
for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
|
|
|
|
{
|
|
|
|
cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
|
2016-01-08 21:04:23 +11:00
|
|
|
rFontSelData.mpFontInstance->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the matching device font
|
|
|
|
if( !rFontSelData.maSearchName.isEmpty() )
|
|
|
|
pFallbackData = FindFontFamily( rFontSelData.maSearchName );
|
|
|
|
}
|
|
|
|
|
|
|
|
// else find a matching font candidate for generic glyph fallback
|
|
|
|
if( !pFallbackData )
|
|
|
|
{
|
|
|
|
// initialize font candidates for generic glyph fallback if needed
|
|
|
|
if( mnFallbackCount < 0 )
|
2015-12-23 11:03:02 +11:00
|
|
|
ImplInitGenericGlyphFallback();
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// TODO: adjust nFallbackLevel by number of levels resolved by the fallback hook
|
|
|
|
if( nFallbackLevel < mnFallbackCount )
|
|
|
|
pFallbackData = mpFallbackList[ nFallbackLevel ];
|
|
|
|
}
|
|
|
|
|
|
|
|
return pFallbackData;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicalFontCollection::Add( PhysicalFontFace* pNewData )
|
|
|
|
{
|
2014-08-22 00:08:04 +01:00
|
|
|
OUString aSearchName = GetEnglishSearchFontName( pNewData->GetFamilyName() );
|
2014-03-20 00:22:26 -05:00
|
|
|
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* pFoundData = FindOrCreateFontFamily( aSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
bool bKeepNewData = pFoundData->AddFontFace( pNewData );
|
|
|
|
|
|
|
|
if( !bKeepNewData )
|
|
|
|
delete pNewData;
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the font from the normalized font family name
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* PhysicalFontCollection::ImplFindFontFamilyBySearchName( const OUString& rSearchName ) const
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2014-08-22 00:08:04 +01:00
|
|
|
// must be called with a normalized name.
|
|
|
|
assert( GetEnglishSearchFontName( rSearchName ) == rSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.find( rSearchName );
|
|
|
|
if( it == maPhysicalFontFamilies.end() )
|
2015-11-10 10:28:29 +01:00
|
|
|
return nullptr;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
PhysicalFontFamily* pFoundData = (*it).second;
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* PhysicalFontCollection::ImplFindFontFamilyByAliasName(const OUString& rSearchName,
|
2014-03-20 00:22:26 -05:00
|
|
|
const OUString& rShortName) const
|
|
|
|
{
|
|
|
|
// short circuit for impossible font name alias
|
|
|
|
if (rSearchName.isEmpty())
|
2015-11-10 10:28:29 +01:00
|
|
|
return nullptr;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// short circuit if no alias names are available
|
|
|
|
if (!mbMapNames)
|
2015-11-10 10:28:29 +01:00
|
|
|
return nullptr;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// use the font's alias names to find the font
|
|
|
|
// TODO: get rid of linear search
|
|
|
|
PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
|
|
|
|
while( it != maPhysicalFontFamilies.end() )
|
|
|
|
{
|
|
|
|
PhysicalFontFamily* pData = (*it).second;
|
|
|
|
if( pData->GetAliasNames().isEmpty() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// if one alias name matches we found a matching font
|
|
|
|
OUString aTempName;
|
|
|
|
sal_Int32 nIndex = 0;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
aTempName = GetNextFontToken( pData->GetAliasNames(), nIndex );
|
|
|
|
// Test, if the Font name match with one of the mapping names
|
|
|
|
if ( (aTempName == rSearchName) || (aTempName == rShortName) )
|
|
|
|
return pData;
|
|
|
|
}
|
|
|
|
while ( nIndex != -1 );
|
|
|
|
}
|
|
|
|
|
2015-11-10 10:28:29 +01:00
|
|
|
return nullptr;
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
PhysicalFontFamily* PhysicalFontCollection::FindFontFamily( const OUString& rFontName ) const
|
|
|
|
{
|
2015-12-24 11:49:14 +11:00
|
|
|
return ImplFindFontFamilyBySearchName( GetEnglishSearchFontName( rFontName ) );
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily *PhysicalFontCollection::FindOrCreateFontFamily( const OUString &rFamilyName )
|
2014-08-21 23:37:44 +01:00
|
|
|
{
|
|
|
|
PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.find( rFamilyName );
|
2015-11-10 10:28:29 +01:00
|
|
|
PhysicalFontFamily* pFoundData = nullptr;
|
2014-08-21 23:37:44 +01:00
|
|
|
|
|
|
|
if( it != maPhysicalFontFamilies.end() )
|
|
|
|
pFoundData = (*it).second;
|
|
|
|
|
|
|
|
if( !pFoundData )
|
|
|
|
{
|
|
|
|
pFoundData = new PhysicalFontFamily( rFamilyName );
|
|
|
|
maPhysicalFontFamilies[ rFamilyName ] = pFoundData;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* PhysicalFontCollection::FindFontFamilyByTokenNames(const OUString& rTokenStr) const
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-11-10 10:28:29 +01:00
|
|
|
PhysicalFontFamily* pFoundData = nullptr;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// use normalized font name tokens to find the font
|
|
|
|
for( sal_Int32 nTokenPos = 0; nTokenPos != -1; )
|
|
|
|
{
|
2014-08-22 00:08:04 +01:00
|
|
|
OUString aFamilyName = GetNextFontToken( rTokenStr, nTokenPos );
|
|
|
|
if( aFamilyName.isEmpty() )
|
2014-03-20 00:22:26 -05:00
|
|
|
continue;
|
|
|
|
|
2014-08-22 00:08:04 +01:00
|
|
|
pFoundData = FindFontFamily( aFamilyName );
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
if( pFoundData )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* PhysicalFontCollection::ImplFindFontFamilyBySubstFontAttr( const utl::FontNameAttr& rFontAttr ) const
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-11-10 10:28:29 +01:00
|
|
|
PhysicalFontFamily* pFoundData = nullptr;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// use the font substitutions suggested by the FontNameAttr to find the font
|
|
|
|
::std::vector< OUString >::const_iterator it = rFontAttr.Substitutions.begin();
|
|
|
|
for(; it != rFontAttr.Substitutions.end(); ++it )
|
|
|
|
{
|
2014-08-22 00:08:04 +01:00
|
|
|
pFoundData = FindFontFamily( *it );
|
2014-03-20 00:22:26 -05:00
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
|
|
|
|
// use known attributes from the configuration to find a matching substitute
|
2015-05-04 14:05:14 +02:00
|
|
|
const ImplFontAttrs nSearchType = rFontAttr.Type;
|
|
|
|
if( nSearchType != ImplFontAttrs::None )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
const FontWeight eSearchWeight = rFontAttr.Weight;
|
|
|
|
const FontWidth eSearchWidth = rFontAttr.Width;
|
|
|
|
const FontItalic eSearchSlant = ITALIC_DONTKNOW;
|
|
|
|
const OUString aSearchName;
|
|
|
|
|
2015-12-24 11:49:14 +11:00
|
|
|
pFoundData = FindFontFamilyByAttributes( nSearchType,
|
2014-03-20 00:22:26 -05:00
|
|
|
eSearchWeight, eSearchWidth, eSearchSlant, aSearchName );
|
|
|
|
|
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
|
2015-11-10 10:28:29 +01:00
|
|
|
return nullptr;
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
|
2015-12-23 11:03:02 +11:00
|
|
|
void PhysicalFontCollection::ImplInitMatchData() const
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
// short circuit if already done
|
|
|
|
if( mbMatchData )
|
|
|
|
return;
|
|
|
|
mbMatchData = true;
|
|
|
|
|
2015-08-19 15:27:07 +01:00
|
|
|
if (utl::ConfigManager::IsAvoidConfig())
|
|
|
|
return;
|
|
|
|
|
2014-03-20 00:22:26 -05:00
|
|
|
// calculate MatchData for all entries
|
|
|
|
const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
|
|
|
|
|
|
|
|
PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
|
|
|
|
for(; it != maPhysicalFontFamilies.end(); ++it )
|
|
|
|
{
|
|
|
|
const OUString& rSearchName = (*it).first;
|
|
|
|
PhysicalFontFamily* pEntry = (*it).second;
|
|
|
|
|
|
|
|
pEntry->InitMatchData( rFontSubst, rSearchName );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* PhysicalFontCollection::FindFontFamilyByAttributes( ImplFontAttrs nSearchType,
|
|
|
|
FontWeight eSearchWeight,
|
|
|
|
FontWidth eSearchWidth,
|
|
|
|
FontItalic eSearchItalic,
|
|
|
|
const OUString& rSearchFamilyName ) const
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
if( (eSearchItalic != ITALIC_NONE) && (eSearchItalic != ITALIC_DONTKNOW) )
|
2015-05-04 14:05:14 +02:00
|
|
|
nSearchType |= ImplFontAttrs::Italic;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// don't bother to match attributes if the attributes aren't worth matching
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType == ImplFontAttrs::None
|
2014-03-20 00:22:26 -05:00
|
|
|
&& ((eSearchWeight == WEIGHT_DONTKNOW) || (eSearchWeight == WEIGHT_NORMAL))
|
|
|
|
&& ((eSearchWidth == WIDTH_DONTKNOW) || (eSearchWidth == WIDTH_NORMAL)) )
|
2015-11-10 10:28:29 +01:00
|
|
|
return nullptr;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
2015-12-23 11:03:02 +11:00
|
|
|
ImplInitMatchData();
|
2015-11-10 10:28:29 +01:00
|
|
|
PhysicalFontFamily* pFoundData = nullptr;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
long nBestMatch = 40000;
|
2015-05-04 14:05:14 +02:00
|
|
|
ImplFontAttrs nBestType = ImplFontAttrs::None;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
|
|
|
|
for(; it != maPhysicalFontFamilies.end(); ++it )
|
|
|
|
{
|
|
|
|
PhysicalFontFamily* pData = (*it).second;
|
|
|
|
|
|
|
|
// Get all information about the matching font
|
2015-05-04 14:05:14 +02:00
|
|
|
ImplFontAttrs nMatchType = pData->GetMatchType();
|
|
|
|
FontWeight eMatchWeight= pData->GetMatchWeight();
|
|
|
|
FontWidth eMatchWidth = pData->GetMatchWidth();
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// Calculate Match Value
|
|
|
|
// 1000000000
|
|
|
|
// 100000000
|
|
|
|
// 10000000 CJK, CTL, None-Latin, Symbol
|
|
|
|
// 1000000 FamilyName, Script, Fixed, -Special, -Decorative,
|
|
|
|
// Titling, Capitals, Outline, Shadow
|
|
|
|
// 100000 Match FamilyName, Serif, SansSerif, Italic,
|
|
|
|
// Width, Weight
|
|
|
|
// 10000 Scalable, Standard, Default,
|
|
|
|
// full, Normal, Knownfont,
|
|
|
|
// Otherstyle, +Special, +Decorative,
|
|
|
|
// 1000 Typewriter, Rounded, Gothic, Schollbook
|
|
|
|
// 100
|
2015-01-17 01:18:38 +01:00
|
|
|
long nTestMatch = 0;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// test CJK script attributes
|
2015-05-04 14:05:14 +02:00
|
|
|
if ( nSearchType & ImplFontAttrs::CJK )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
// Matching language
|
2015-05-04 14:05:14 +02:00
|
|
|
if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::CJK_AllLang) )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000000*3;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::CJK )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000000*2;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Full )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000000;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if ( nMatchType & ImplFontAttrs::CJK )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch -= 10000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test CTL script attributes
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & ImplFontAttrs::CTL )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::CTL )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000000*2;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Full )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000000;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if ( nMatchType & ImplFontAttrs::CTL )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch -= 10000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test LATIN script attributes
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & ImplFontAttrs::NoneLatin )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::NoneLatin )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000000*2;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Full )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test SYMBOL attributes
|
2015-05-04 14:05:14 +02:00
|
|
|
if ( nSearchType & ImplFontAttrs::Symbol )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
const OUString& rSearchName = it->first;
|
|
|
|
// prefer some special known symbol fonts
|
|
|
|
if ( rSearchName == "starsymbol" )
|
|
|
|
{
|
|
|
|
nTestMatch += 10000000*6+(10000*3);
|
|
|
|
}
|
|
|
|
else if ( rSearchName == "opensymbol" )
|
|
|
|
{
|
|
|
|
nTestMatch += 10000000*6;
|
|
|
|
}
|
|
|
|
else if ( rSearchName == "starbats" ||
|
|
|
|
rSearchName == "wingdings" ||
|
|
|
|
rSearchName == "monotypesorts" ||
|
|
|
|
rSearchName == "dingbats" ||
|
|
|
|
rSearchName == "zapfdingbats" )
|
|
|
|
{
|
|
|
|
nTestMatch += 10000000*5;
|
|
|
|
}
|
2016-05-10 13:34:46 +02:00
|
|
|
else if ( pData->GetTypeFaces() & FontTypeFaces::Symbol )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch += 10000000*4;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Symbol )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000000*2;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Full )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000000;
|
|
|
|
}
|
|
|
|
}
|
2016-05-10 13:34:46 +02:00
|
|
|
else if ( (pData->GetTypeFaces() & (FontTypeFaces::Symbol | FontTypeFaces::NoneSymbol)) == FontTypeFaces::Symbol )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch -= 10000000;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if ( nMatchType & ImplFontAttrs::Symbol )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch -= 10000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// match stripped family name
|
|
|
|
if( !rSearchFamilyName.isEmpty() && (rSearchFamilyName == pData->GetMatchFamilyName()) )
|
|
|
|
{
|
|
|
|
nTestMatch += 1000000*3;
|
|
|
|
}
|
|
|
|
|
|
|
|
// match ALLSCRIPT? attribute
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & ImplFontAttrs::AllScript )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::AllScript )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch += 1000000*2;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & ImplFontAttrs::AllSubscript )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::AllSubscript) )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000000*2;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( ImplFontAttrs::None != ((nSearchType ^ nMatchType) & ImplFontAttrs::BrushScript) )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch -= 1000000;
|
|
|
|
}
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if( nMatchType & ImplFontAttrs::AllScript )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch -= 1000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test MONOSPACE+TYPEWRITER attributes
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & ImplFontAttrs::Fixed )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Fixed )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000000*2;
|
|
|
|
// a typewriter attribute is even better
|
2015-05-04 14:05:14 +02:00
|
|
|
if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::Typewriter) )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000*2;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if( nMatchType & ImplFontAttrs::Fixed )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch -= 1000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test SPECIAL attribute
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & ImplFontAttrs::Special )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Special )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch += 10000;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if( !(nSearchType & ImplFontAttrs::AllSerifStyle) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Serif )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch += 1000*2;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if( nMatchType & ImplFontAttrs::SansSerif )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch += 1000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if( (nMatchType & ImplFontAttrs::Special) && !(nSearchType & ImplFontAttrs::Symbol) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch -= 1000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test DECORATIVE attribute
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & ImplFontAttrs::Decorative )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Decorative )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch += 10000;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if( !(nSearchType & ImplFontAttrs::AllSerifStyle) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Serif )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000*2;
|
2015-05-04 14:05:14 +02:00
|
|
|
else if ( nMatchType & ImplFontAttrs::SansSerif )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000;
|
|
|
|
}
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if( nMatchType & ImplFontAttrs::Decorative )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch -= 1000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test TITLE+CAPITALS attributes
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch += 1000000*2;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
if( ImplFontAttrs::None == ((nSearchType^nMatchType) & ImplFontAttrs(ImplFontAttrs::Titling | ImplFontAttrs::Capitals)))
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch += 1000000;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if( (nMatchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals)) &&
|
|
|
|
(nMatchType & (ImplFontAttrs::Standard | ImplFontAttrs::Default)) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch += 1000000;
|
|
|
|
}
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if( nMatchType & (ImplFontAttrs::Titling | ImplFontAttrs::Capitals) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch -= 1000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test OUTLINE+SHADOW attributes
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch += 1000000*2;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs(ImplFontAttrs::Outline | ImplFontAttrs::Shadow)) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch += 1000000;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if( (nMatchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow)) &&
|
|
|
|
(nMatchType & (ImplFontAttrs::Standard | ImplFontAttrs::Default)) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch += 1000000;
|
|
|
|
}
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if ( nMatchType & (ImplFontAttrs::Outline | ImplFontAttrs::Shadow) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch -= 1000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test font name substrings
|
|
|
|
// TODO: calculate name matching score using e.g. Levenstein distance
|
|
|
|
if( (rSearchFamilyName.getLength() >= 4) &&
|
|
|
|
(pData->GetMatchFamilyName().getLength() >= 4) &&
|
|
|
|
((rSearchFamilyName.indexOf( pData->GetMatchFamilyName() ) != -1) ||
|
|
|
|
(pData->GetMatchFamilyName().indexOf( rSearchFamilyName ) != -1)) )
|
|
|
|
{
|
|
|
|
nTestMatch += 5000;
|
|
|
|
}
|
|
|
|
// test SERIF attribute
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & ImplFontAttrs::Serif )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Serif )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000000*2;
|
2015-05-04 14:05:14 +02:00
|
|
|
else if( nMatchType & ImplFontAttrs::SansSerif )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch -= 1000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test SANSERIF attribute
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & ImplFontAttrs::SansSerif )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::SansSerif )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000000;
|
2015-05-04 14:05:14 +02:00
|
|
|
else if ( nMatchType & ImplFontAttrs::Serif )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch -= 1000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test ITALIC attribute
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & ImplFontAttrs::Italic )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2016-05-10 13:34:46 +02:00
|
|
|
if( pData->GetTypeFaces() & FontTypeFaces::Italic )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000000*3;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Italic )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000000;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if( !(nSearchType & ImplFontAttrs::AllScript) &&
|
|
|
|
((nMatchType & ImplFontAttrs::Italic) ||
|
2016-05-10 13:34:46 +02:00
|
|
|
!(pData->GetTypeFaces() & FontTypeFaces::NoneItalic)) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch -= 1000000*2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test WIDTH attribute
|
|
|
|
if( (eSearchWidth != WIDTH_DONTKNOW) && (eSearchWidth != WIDTH_NORMAL) )
|
|
|
|
{
|
|
|
|
if( eSearchWidth < WIDTH_NORMAL )
|
|
|
|
{
|
|
|
|
if( eSearchWidth == eMatchWidth )
|
|
|
|
nTestMatch += 1000000*3;
|
|
|
|
else if( (eMatchWidth < WIDTH_NORMAL) && (eMatchWidth != WIDTH_DONTKNOW) )
|
|
|
|
nTestMatch += 1000000;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( eSearchWidth == eMatchWidth )
|
|
|
|
nTestMatch += 1000000*3;
|
|
|
|
else if( eMatchWidth > WIDTH_NORMAL )
|
|
|
|
nTestMatch += 1000000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( (eMatchWidth != WIDTH_DONTKNOW) && (eMatchWidth != WIDTH_NORMAL) )
|
|
|
|
{
|
|
|
|
nTestMatch -= 1000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test WEIGHT attribute
|
|
|
|
if( (eSearchWeight != WEIGHT_DONTKNOW) &&
|
|
|
|
(eSearchWeight != WEIGHT_NORMAL) &&
|
|
|
|
(eSearchWeight != WEIGHT_MEDIUM) )
|
|
|
|
{
|
|
|
|
if( eSearchWeight < WEIGHT_NORMAL )
|
|
|
|
{
|
2016-05-10 13:34:46 +02:00
|
|
|
if( pData->GetTypeFaces() & FontTypeFaces::Light )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000000;
|
|
|
|
if( (eMatchWeight < WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_DONTKNOW) )
|
|
|
|
nTestMatch += 1000000;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-05-10 13:34:46 +02:00
|
|
|
if( pData->GetTypeFaces() & FontTypeFaces::Bold )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000000;
|
|
|
|
if( eMatchWeight > WEIGHT_BOLD )
|
|
|
|
nTestMatch += 1000000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( ((eMatchWeight != WEIGHT_DONTKNOW) &&
|
|
|
|
(eMatchWeight != WEIGHT_NORMAL) &&
|
|
|
|
(eMatchWeight != WEIGHT_MEDIUM)) ||
|
2016-05-10 13:34:46 +02:00
|
|
|
!(pData->GetTypeFaces() & FontTypeFaces::Normal) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch -= 1000000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// prefer scalable fonts
|
2016-05-10 13:34:46 +02:00
|
|
|
if( pData->GetTypeFaces() & FontTypeFaces::Scalable )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000*4;
|
|
|
|
else
|
|
|
|
nTestMatch -= 10000*4;
|
|
|
|
|
|
|
|
// test STANDARD+DEFAULT+FULL+NORMAL attributes
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Standard )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000*2;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Default )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Full )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Normal )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 10000;
|
|
|
|
|
|
|
|
// test OTHERSTYLE attribute
|
2015-05-04 14:05:14 +02:00
|
|
|
if( ((nSearchType ^ nMatchType) & ImplFontAttrs::OtherStyle) != ImplFontAttrs::None )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
nTestMatch -= 10000;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test ROUNDED attribute
|
2015-05-04 14:05:14 +02:00
|
|
|
if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::Rounded) )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000;
|
|
|
|
|
|
|
|
// test TYPEWRITER attribute
|
2015-05-04 14:05:14 +02:00
|
|
|
if( ImplFontAttrs::None == ((nSearchType ^ nMatchType) & ImplFontAttrs::Typewriter) )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000;
|
|
|
|
|
|
|
|
// test GOTHIC attribute
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & ImplFontAttrs::Gothic )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Gothic )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000*3;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::SansSerif )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000*2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// test SCHOOLBOOK attribute
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nSearchType & ImplFontAttrs::Schoolbook )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Schoolbook )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000*3;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Serif )
|
2014-03-20 00:22:26 -05:00
|
|
|
nTestMatch += 1000*2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// compare with best matching font yet
|
|
|
|
if ( nTestMatch > nBestMatch )
|
|
|
|
{
|
|
|
|
pFoundData = pData;
|
|
|
|
nBestMatch = nTestMatch;
|
|
|
|
nBestType = nMatchType;
|
|
|
|
}
|
|
|
|
else if( nTestMatch == nBestMatch )
|
|
|
|
{
|
|
|
|
// some fonts are more suitable defaults
|
2015-05-04 14:05:14 +02:00
|
|
|
if( nMatchType & ImplFontAttrs::Default )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
pFoundData = pData;
|
|
|
|
nBestType = nMatchType;
|
|
|
|
}
|
2015-05-04 14:05:14 +02:00
|
|
|
else if( (nMatchType & ImplFontAttrs::Standard) &&
|
|
|
|
!(nBestType & ImplFontAttrs::Default) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
pFoundData = pData;
|
|
|
|
nBestType = nMatchType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
|
2015-12-24 12:04:15 +11:00
|
|
|
PhysicalFontFamily* PhysicalFontCollection::ImplFindFontFamilyOfDefaultFont() const
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
// try to find one of the default fonts of the
|
|
|
|
// UNICODE, SANSSERIF, SERIF or FIXED default font lists
|
2015-08-21 09:00:15 +01:00
|
|
|
PhysicalFontFamily* pFoundData = nullptr;
|
|
|
|
if (!utl::ConfigManager::IsAvoidConfig())
|
|
|
|
{
|
|
|
|
const utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get();
|
|
|
|
LanguageTag aLanguageTag( OUString( "en"));
|
|
|
|
OUString aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::SANS_UNICODE );
|
2015-12-24 11:49:14 +11:00
|
|
|
pFoundData = FindFontFamilyByTokenNames( aFontname );
|
2015-08-21 09:00:15 +01:00
|
|
|
|
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
|
|
|
|
aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::SANS );
|
2015-12-24 11:49:14 +11:00
|
|
|
pFoundData = FindFontFamilyByTokenNames( aFontname );
|
2015-08-21 09:00:15 +01:00
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
|
|
|
|
aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::SERIF );
|
2015-12-24 11:49:14 +11:00
|
|
|
pFoundData = FindFontFamilyByTokenNames( aFontname );
|
2015-08-21 09:00:15 +01:00
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
|
|
|
|
aFontname = rDefaults.getDefaultFont( aLanguageTag, DefaultFontType::FIXED );
|
2015-12-24 11:49:14 +11:00
|
|
|
pFoundData = FindFontFamilyByTokenNames( aFontname );
|
2015-08-21 09:00:15 +01:00
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
}
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// now try to find a reasonable non-symbol font
|
|
|
|
|
2015-12-23 11:03:02 +11:00
|
|
|
ImplInitMatchData();
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
|
|
|
|
for(; it != maPhysicalFontFamilies.end(); ++it )
|
|
|
|
{
|
|
|
|
PhysicalFontFamily* pData = (*it).second;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( pData->GetMatchType() & ImplFontAttrs::Symbol )
|
2014-03-20 00:22:26 -05:00
|
|
|
continue;
|
|
|
|
|
|
|
|
pFoundData = pData;
|
2015-05-04 14:05:14 +02:00
|
|
|
if( pData->GetMatchType() & (ImplFontAttrs::Default|ImplFontAttrs::Standard) )
|
2014-03-20 00:22:26 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
|
|
|
|
// finding any font is better than finding no font at all
|
|
|
|
it = maPhysicalFontFamilies.begin();
|
|
|
|
if( it != maPhysicalFontFamilies.end() )
|
|
|
|
pFoundData = (*it).second;
|
|
|
|
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
|
2016-03-08 10:51:28 +02:00
|
|
|
PhysicalFontCollection* PhysicalFontCollection::Clone( bool bEmbeddable ) const
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
PhysicalFontCollection* pClonedCollection = new PhysicalFontCollection;
|
|
|
|
pClonedCollection->mbMapNames = mbMapNames;
|
|
|
|
pClonedCollection->mpPreMatchHook = mpPreMatchHook;
|
|
|
|
pClonedCollection->mpFallbackHook = mpFallbackHook;
|
|
|
|
|
|
|
|
// TODO: clone the config-font attributes too?
|
|
|
|
pClonedCollection->mbMatchData = false;
|
|
|
|
|
|
|
|
PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
|
|
|
|
for(; it != maPhysicalFontFamilies.end(); ++it )
|
|
|
|
{
|
|
|
|
const PhysicalFontFamily* pFontFace = (*it).second;
|
2016-03-16 08:49:35 +02:00
|
|
|
pFontFace->UpdateCloneFontList( *pClonedCollection, bEmbeddable );
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return pClonedCollection;
|
|
|
|
}
|
|
|
|
|
2015-12-25 17:57:19 +11:00
|
|
|
ImplDeviceFontList* PhysicalFontCollection::GetDeviceFontList() const
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-12-24 14:14:43 +11:00
|
|
|
ImplDeviceFontList* pDeviceFontList = new ImplDeviceFontList;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
PhysicalFontFamilies::const_iterator it = maPhysicalFontFamilies.begin();
|
|
|
|
for(; it != maPhysicalFontFamilies.end(); ++it )
|
|
|
|
{
|
|
|
|
const PhysicalFontFamily* pFontFamily = (*it).second;
|
2015-12-24 14:14:43 +11:00
|
|
|
pFontFamily->UpdateDevFontList( *pDeviceFontList );
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
|
2015-12-24 14:14:43 +11:00
|
|
|
return pDeviceFontList;
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
|
2015-12-26 07:18:20 +11:00
|
|
|
ImplDeviceFontSizeList* PhysicalFontCollection::GetDeviceFontSizeList( const OUString& rFontName ) const
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
2015-12-26 07:18:20 +11:00
|
|
|
ImplDeviceFontSizeList* pDeviceFontSizeList = new ImplDeviceFontSizeList;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
PhysicalFontFamily* pFontFamily = FindFontFamily( rFontName );
|
2015-11-10 10:28:29 +01:00
|
|
|
if( pFontFamily != nullptr )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
std::set<int> rHeights;
|
|
|
|
pFontFamily->GetFontHeights( rHeights );
|
|
|
|
|
|
|
|
std::set<int>::const_iterator it = rHeights.begin();
|
|
|
|
for(; it != rHeights.begin(); ++it )
|
2015-12-26 07:18:20 +11:00
|
|
|
pDeviceFontSizeList->Add( *it );
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
|
2015-12-26 07:18:20 +11:00
|
|
|
return pDeviceFontSizeList;
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
|
2016-01-09 04:03:26 +11:00
|
|
|
PhysicalFontFamily* PhysicalFontCollection::FindFontFamily( FontSelectPattern& rFSD ) const
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
// give up if no fonts are available
|
|
|
|
if( !Count() )
|
2015-11-10 10:28:29 +01:00
|
|
|
return nullptr;
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
bool bMultiToken = false;
|
|
|
|
sal_Int32 nTokenPos = 0;
|
|
|
|
OUString& aSearchName = rFSD.maSearchName; // TODO: get rid of reference
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
|
|
|
|
aSearchName = rFSD.maTargetName;
|
|
|
|
|
|
|
|
// Until features are properly supported, they are appended to the
|
|
|
|
// font name, so we need to strip them off so the font is found.
|
2016-11-04 05:06:54 +02:00
|
|
|
sal_Int32 nFeat = aSearchName.indexOf(FontSelectPatternAttributes::FEAT_PREFIX);
|
2014-03-20 00:22:26 -05:00
|
|
|
OUString aOrigName = rFSD.maTargetName;
|
|
|
|
OUString aBaseFontName = aSearchName.copy( 0, (nFeat != -1) ? nFeat : aSearchName.getLength() );
|
|
|
|
|
2016-11-04 05:06:54 +02:00
|
|
|
if (nFeat != -1)
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
aSearchName = aBaseFontName;
|
|
|
|
rFSD.maTargetName = aBaseFontName;
|
|
|
|
}
|
|
|
|
|
2014-08-22 00:08:04 +01:00
|
|
|
aSearchName = GetEnglishSearchFontName( aSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
ImplFontSubstitute( aSearchName );
|
|
|
|
// #114999# special emboldening for Ricoh fonts
|
|
|
|
// TODO: smarter check for special cases by using PreMatch infrastructure?
|
|
|
|
if( (rFSD.GetWeight() > WEIGHT_MEDIUM) &&
|
|
|
|
aSearchName.startsWithIgnoreAsciiCase( "hg" ) )
|
|
|
|
{
|
|
|
|
OUString aBoldName;
|
|
|
|
if( aSearchName.startsWithIgnoreAsciiCase( "hggothicb" ) )
|
|
|
|
aBoldName = "hggothice";
|
|
|
|
else if( aSearchName.startsWithIgnoreAsciiCase( "hgpgothicb" ) )
|
|
|
|
aBoldName = "hgpgothice";
|
|
|
|
else if( aSearchName.startsWithIgnoreAsciiCase( "hgminchol" ) )
|
|
|
|
aBoldName = "hgminchob";
|
|
|
|
else if( aSearchName.startsWithIgnoreAsciiCase( "hgpminchol" ) )
|
|
|
|
aBoldName = "hgpminchob";
|
|
|
|
else if( aSearchName.equalsIgnoreAsciiCase( "hgminchob" ) )
|
|
|
|
aBoldName = "hgminchoe";
|
|
|
|
else if( aSearchName.equalsIgnoreAsciiCase( "hgpminchob" ) )
|
|
|
|
aBoldName = "hgpminchoe";
|
|
|
|
|
2015-12-24 11:49:14 +11:00
|
|
|
if( !aBoldName.isEmpty() && ImplFindFontFamilyBySearchName( aBoldName ) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
// the other font is available => use it
|
|
|
|
aSearchName = aBoldName;
|
|
|
|
// prevent synthetic emboldening of bold version
|
|
|
|
rFSD.SetWeight(WEIGHT_DONTKNOW);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// restore the features to make the font selection data unique
|
|
|
|
rFSD.maTargetName = aOrigName;
|
2016-11-04 05:06:54 +02:00
|
|
|
|
2014-03-20 00:22:26 -05:00
|
|
|
// check if the current font name token or its substitute is valid
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
|
|
|
|
// some systems provide special customization
|
|
|
|
// e.g. they suggest "serif" as UI-font, but this name cannot be used directly
|
|
|
|
// because the system wants to map it to another font first, e.g. "Helvetica"
|
2016-11-04 05:06:54 +02:00
|
|
|
|
2014-03-20 00:22:26 -05:00
|
|
|
// use the target name to search in the prematch hook
|
|
|
|
rFSD.maTargetName = aBaseFontName;
|
|
|
|
|
|
|
|
// Related: fdo#49271 RTF files often contain weird-ass
|
|
|
|
// Win 3.1/Win95 style fontnames which attempt to put the
|
|
|
|
// charset encoding into the filename
|
|
|
|
// http://www.webcenter.ru/~kazarn/eng/fonts_ttf.htm
|
2014-10-20 11:17:56 +01:00
|
|
|
OUString sStrippedName = StripScriptFromName(rFSD.maTargetName);
|
2014-03-20 00:22:26 -05:00
|
|
|
if (sStrippedName != rFSD.maTargetName)
|
|
|
|
{
|
|
|
|
rFSD.maTargetName = sStrippedName;
|
2014-08-22 00:08:04 +01:00
|
|
|
aSearchName = GetEnglishSearchFontName(rFSD.maTargetName);
|
2015-12-24 11:49:14 +11:00
|
|
|
pFoundData = ImplFindFontFamilyBySearchName(aSearchName);
|
2014-03-20 00:22:26 -05:00
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( mpPreMatchHook )
|
|
|
|
{
|
|
|
|
if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
|
2014-08-22 00:08:04 +01:00
|
|
|
aSearchName = GetEnglishSearchFontName( aSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
2016-11-04 05:06:54 +02:00
|
|
|
|
2014-03-20 00:22:26 -05:00
|
|
|
// the prematch hook uses the target name to search, but we now need
|
|
|
|
// to restore the features to make the font selection data unique
|
|
|
|
rFSD.maTargetName = aOrigName;
|
2016-11-04 05:06:54 +02:00
|
|
|
|
2015-12-24 11:49:14 +11:00
|
|
|
pFoundData = ImplFindFontFamilyBySearchName( aSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
|
|
|
|
// break after last font name token was checked unsuccessfully
|
|
|
|
if( nTokenPos == -1)
|
|
|
|
break;
|
|
|
|
bMultiToken = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the first font was not available find the next available font in
|
|
|
|
// the semicolon separated list of font names. A font is also considered
|
|
|
|
// available when there is a matching entry in the Tools->Options->Fonts
|
2015-07-02 18:25:58 +02:00
|
|
|
// dialog with neither ALWAYS nor SCREENONLY flags set and the substitution
|
2014-03-20 00:22:26 -05:00
|
|
|
// font is available
|
|
|
|
for( nTokenPos = 0; nTokenPos != -1; )
|
|
|
|
{
|
|
|
|
if( bMultiToken )
|
|
|
|
{
|
|
|
|
rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
|
2014-08-22 00:08:04 +01:00
|
|
|
aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
nTokenPos = -1;
|
|
|
|
if( mpPreMatchHook )
|
|
|
|
if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
|
2014-08-22 00:08:04 +01:00
|
|
|
aSearchName = GetEnglishSearchFontName( aSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
ImplFontSubstitute( aSearchName );
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if no font with a directly matching name is available use the
|
|
|
|
// first font name token and get its attributes to find a replacement
|
|
|
|
if ( bMultiToken )
|
|
|
|
{
|
|
|
|
nTokenPos = 0;
|
|
|
|
rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
|
2014-08-22 00:08:04 +01:00
|
|
|
aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
OUString aSearchShortName;
|
|
|
|
OUString aSearchFamilyName;
|
2015-05-04 14:05:14 +02:00
|
|
|
FontWeight eSearchWeight = rFSD.GetWeight();
|
|
|
|
FontWidth eSearchWidth = rFSD.GetWidthType();
|
|
|
|
ImplFontAttrs nSearchType = ImplFontAttrs::None;
|
2014-03-20 00:22:26 -05:00
|
|
|
utl::FontSubstConfiguration::getMapName( aSearchName, aSearchShortName, aSearchFamilyName,
|
|
|
|
eSearchWeight, eSearchWidth, nSearchType );
|
|
|
|
|
|
|
|
// note: the search name was already translated to english (if possible)
|
|
|
|
// use the font's shortened name if needed
|
|
|
|
if ( aSearchShortName != aSearchName )
|
|
|
|
{
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aSearchShortName );
|
2014-03-20 00:22:26 -05:00
|
|
|
if( pFoundData )
|
|
|
|
{
|
|
|
|
#ifdef UNX
|
|
|
|
/* #96738# don't use mincho as an replacement for "MS Mincho" on X11: Mincho is
|
|
|
|
a korean bitmap font that is not suitable here. Use the font replacement table,
|
|
|
|
that automatically leads to the desired "HG Mincho Light J". Same story for
|
|
|
|
MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */
|
2016-10-31 10:28:18 +02:00
|
|
|
if ((aSearchName != "msmincho") && (aSearchName != "msgothic"))
|
2014-03-20 00:22:26 -05:00
|
|
|
// TODO: add heuristic to only throw out the fake ms* fonts
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// use font fallback
|
2015-11-10 10:28:29 +01:00
|
|
|
const utl::FontNameAttr* pFontAttr = nullptr;
|
2015-08-19 15:27:07 +01:00
|
|
|
if (!aSearchName.isEmpty() && !utl::ConfigManager::IsAvoidConfig())
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
// get fallback info using FontSubstConfiguration and
|
|
|
|
// the target name, it's shortened name and family name in that order
|
|
|
|
const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
|
|
|
|
pFontAttr = rFontSubst.getSubstInfo( aSearchName );
|
|
|
|
if ( !pFontAttr && (aSearchShortName != aSearchName) )
|
|
|
|
pFontAttr = rFontSubst.getSubstInfo( aSearchShortName );
|
|
|
|
if ( !pFontAttr && (aSearchFamilyName != aSearchShortName) )
|
|
|
|
pFontAttr = rFontSubst.getSubstInfo( aSearchFamilyName );
|
|
|
|
|
|
|
|
// try the font substitutions suggested by the fallback info
|
|
|
|
if( pFontAttr )
|
|
|
|
{
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySubstFontAttr( *pFontAttr );
|
2014-03-20 00:22:26 -05:00
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if a target symbol font is not available use a default symbol font
|
|
|
|
if( rFSD.IsSymbolFont() )
|
|
|
|
{
|
|
|
|
LanguageTag aDefaultLanguageTag( OUString( "en"));
|
2015-08-19 15:27:07 +01:00
|
|
|
if (utl::ConfigManager::IsAvoidConfig())
|
|
|
|
aSearchName = "OpenSymbol";
|
|
|
|
else
|
|
|
|
aSearchName = utl::DefaultFontConfiguration::get().getDefaultFont( aDefaultLanguageTag, DefaultFontType::SYMBOL );
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* pFoundData = FindFontFamilyByTokenNames( aSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
|
|
|
|
// now try the other font name tokens
|
|
|
|
while( nTokenPos != -1 )
|
|
|
|
{
|
|
|
|
rFSD.maTargetName = GetNextFontToken( rFSD.GetFamilyName(), nTokenPos );
|
|
|
|
if( rFSD.maTargetName.isEmpty() )
|
|
|
|
continue;
|
|
|
|
|
2014-08-22 00:08:04 +01:00
|
|
|
aSearchName = GetEnglishSearchFontName( rFSD.maTargetName );
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
OUString aTempShortName;
|
|
|
|
OUString aTempFamilyName;
|
2015-05-04 14:05:14 +02:00
|
|
|
ImplFontAttrs nTempType = ImplFontAttrs::None;
|
|
|
|
FontWeight eTempWeight = rFSD.GetWeight();
|
|
|
|
FontWidth eTempWidth = WIDTH_DONTKNOW;
|
2014-03-20 00:22:26 -05:00
|
|
|
utl::FontSubstConfiguration::getMapName( aSearchName, aTempShortName, aTempFamilyName,
|
|
|
|
eTempWeight, eTempWidth, nTempType );
|
|
|
|
|
|
|
|
// use a shortend token name if available
|
|
|
|
if( aTempShortName != aSearchName )
|
|
|
|
{
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySearchName( aTempShortName );
|
2014-03-20 00:22:26 -05:00
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
|
2015-11-10 10:28:29 +01:00
|
|
|
const utl::FontNameAttr* pTempFontAttr = nullptr;
|
2015-08-21 08:36:36 +01:00
|
|
|
if (!utl::ConfigManager::IsAvoidConfig())
|
|
|
|
{
|
|
|
|
// use a font name from font fallback list to determine font attributes
|
|
|
|
// get fallback info using FontSubstConfiguration and
|
|
|
|
// the target name, it's shortened name and family name in that order
|
|
|
|
const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
|
|
|
|
pTempFontAttr = rFontSubst.getSubstInfo( aSearchName );
|
2014-03-20 00:22:26 -05:00
|
|
|
|
2015-08-21 08:36:36 +01:00
|
|
|
if ( !pTempFontAttr && (aTempShortName != aSearchName) )
|
|
|
|
pTempFontAttr = rFontSubst.getSubstInfo( aTempShortName );
|
2014-03-20 00:22:26 -05:00
|
|
|
|
2015-08-21 08:36:36 +01:00
|
|
|
if ( !pTempFontAttr && (aTempFamilyName != aTempShortName) )
|
|
|
|
pTempFontAttr = rFontSubst.getSubstInfo( aTempFamilyName );
|
|
|
|
}
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
// try the font substitutions suggested by the fallback info
|
|
|
|
if( pTempFontAttr )
|
|
|
|
{
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* pFoundData = ImplFindFontFamilyBySubstFontAttr( *pTempFontAttr );
|
2014-03-20 00:22:26 -05:00
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
if( !pFontAttr )
|
|
|
|
pFontAttr = pTempFontAttr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if still needed use the alias names of the installed fonts
|
|
|
|
if( mbMapNames )
|
|
|
|
{
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* pFoundData = ImplFindFontFamilyByAliasName( rFSD.maTargetName, aSearchShortName );
|
2014-03-20 00:22:26 -05:00
|
|
|
if( pFoundData )
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if still needed use the font request's attributes to find a good match
|
|
|
|
if (MsLangId::isSimplifiedChinese(rFSD.meLanguage))
|
2015-05-04 14:05:14 +02:00
|
|
|
nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_SC;
|
2014-03-20 00:22:26 -05:00
|
|
|
else if (MsLangId::isTraditionalChinese(rFSD.meLanguage))
|
2015-05-04 14:05:14 +02:00
|
|
|
nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_TC;
|
2014-03-20 00:22:26 -05:00
|
|
|
else if (MsLangId::isKorean(rFSD.meLanguage))
|
2015-05-04 14:05:14 +02:00
|
|
|
nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_KR;
|
2014-03-20 00:22:26 -05:00
|
|
|
else if (rFSD.meLanguage == LANGUAGE_JAPANESE)
|
2015-05-04 14:05:14 +02:00
|
|
|
nSearchType |= ImplFontAttrs::CJK | ImplFontAttrs::CJK_JP;
|
2014-03-20 00:22:26 -05:00
|
|
|
else
|
|
|
|
{
|
|
|
|
nSearchType |= lcl_IsCJKFont( rFSD.GetFamilyName() );
|
|
|
|
if( rFSD.IsSymbolFont() )
|
2015-05-04 14:05:14 +02:00
|
|
|
nSearchType |= ImplFontAttrs::Symbol;
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
PhysicalFontFamily::CalcType( nSearchType, eSearchWeight, eSearchWidth, rFSD.GetFamilyType(), pFontAttr );
|
2015-12-24 11:49:14 +11:00
|
|
|
PhysicalFontFamily* pFoundData = FindFontFamilyByAttributes( nSearchType,
|
2016-01-17 01:00:00 +11:00
|
|
|
eSearchWeight, eSearchWidth, rFSD.GetItalic(), aSearchFamilyName );
|
2014-03-20 00:22:26 -05:00
|
|
|
|
|
|
|
if( pFoundData )
|
|
|
|
{
|
|
|
|
// overwrite font selection attributes using info from the typeface flags
|
|
|
|
if( (eSearchWeight >= WEIGHT_BOLD) &&
|
|
|
|
(eSearchWeight > rFSD.GetWeight()) &&
|
2016-05-10 13:34:46 +02:00
|
|
|
(pFoundData->GetTypeFaces() & FontTypeFaces::Bold) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
rFSD.SetWeight( eSearchWeight );
|
|
|
|
}
|
|
|
|
else if( (eSearchWeight < WEIGHT_NORMAL) &&
|
|
|
|
(eSearchWeight < rFSD.GetWeight()) &&
|
|
|
|
(eSearchWeight != WEIGHT_DONTKNOW) &&
|
2016-05-10 13:34:46 +02:00
|
|
|
(pFoundData->GetTypeFaces() & FontTypeFaces::Light) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
rFSD.SetWeight( eSearchWeight );
|
|
|
|
}
|
|
|
|
|
2015-05-04 14:05:14 +02:00
|
|
|
if( (nSearchType & ImplFontAttrs::Italic) &&
|
2016-01-17 01:00:00 +11:00
|
|
|
((rFSD.GetItalic() == ITALIC_DONTKNOW) ||
|
|
|
|
(rFSD.GetItalic() == ITALIC_NONE)) &&
|
2016-05-10 13:34:46 +02:00
|
|
|
(pFoundData->GetTypeFaces() & FontTypeFaces::Italic) )
|
2014-03-20 00:22:26 -05:00
|
|
|
{
|
|
|
|
rFSD.SetItalic( ITALIC_NORMAL );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// if still needed fall back to default fonts
|
2015-12-24 12:04:15 +11:00
|
|
|
pFoundData = ImplFindFontFamilyOfDefaultFont();
|
2014-03-20 00:22:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return pFoundData;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
|
|
|
|