diff options
Diffstat (limited to '')
-rw-r--r-- | vcl/source/font/PhysicalFontFamily.cxx | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/vcl/source/font/PhysicalFontFamily.cxx b/vcl/source/font/PhysicalFontFamily.cxx new file mode 100644 index 000000000..b402cd618 --- /dev/null +++ b/vcl/source/font/PhysicalFontFamily.cxx @@ -0,0 +1,269 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <rtl/ustring.hxx> +#include <unotools/fontdefs.hxx> + +#include <font/PhysicalFontFaceCollection.hxx> +#include <font/PhysicalFontCollection.hxx> + +namespace vcl::font +{ + +void PhysicalFontFamily::CalcType( ImplFontAttrs& rType, FontWeight& rWeight, FontWidth& rWidth, + FontFamily eFamily, const utl::FontNameAttr* pFontAttr ) +{ + if ( eFamily != FAMILY_DONTKNOW ) + { + if ( eFamily == FAMILY_SWISS ) + rType |= ImplFontAttrs::SansSerif; + else if ( eFamily == FAMILY_ROMAN ) + rType |= ImplFontAttrs::Serif; + else if ( eFamily == FAMILY_SCRIPT ) + rType |= ImplFontAttrs::Script; + else if ( eFamily == FAMILY_MODERN ) + rType |= ImplFontAttrs::Fixed; + else if ( eFamily == FAMILY_DECORATIVE ) + rType |= ImplFontAttrs::Decorative; + } + + if ( pFontAttr ) + { + rType |= pFontAttr->Type; + + if ( ((rWeight == WEIGHT_DONTKNOW) || (rWeight == WEIGHT_NORMAL)) && + (pFontAttr->Weight != WEIGHT_DONTKNOW) ) + rWeight = pFontAttr->Weight; + if ( ((rWidth == WIDTH_DONTKNOW) || (rWidth == WIDTH_NORMAL)) && + (pFontAttr->Width != WIDTH_DONTKNOW) ) + rWidth = pFontAttr->Width; + } +} + +static ImplFontAttrs lcl_IsCJKFont( const OUString& rFontName ) +{ + // 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)) ) + return ImplFontAttrs::CJK|ImplFontAttrs::CJK_JP; + + // korean + if ( ((ch >= 0xAC00) && (ch <= 0xD7AF)) || + ((ch >= 0xA960) && (ch <= 0xA97F)) || + ((ch >= 0xD7B0) && (ch <= 0xD7FF)) || + ((ch >= 0x3130) && (ch <= 0x318F)) || + ((ch >= 0x1100) && (ch <= 0x11FF)) ) + return ImplFontAttrs::CJK|ImplFontAttrs::CJK_KR; + + // chinese + if ( (ch >= 0x3400) && (ch <= 0x9FFF) ) + return ImplFontAttrs::CJK|ImplFontAttrs::CJK_TC|ImplFontAttrs::CJK_SC; + + // cjk + if ( ((ch >= 0x3000) && (ch <= 0xD7AF)) || + ((ch >= 0xFF00) && (ch <= 0xFFEE)) ) + return ImplFontAttrs::CJK; + + } + + return ImplFontAttrs::None; +} + +PhysicalFontFamily::PhysicalFontFamily( const OUString& rSearchName ) +: maSearchName( rSearchName ), + mnTypeFaces( FontTypeFaces::NONE ), + meFamily( FAMILY_DONTKNOW ), + mePitch( PITCH_DONTKNOW ), + mnMinQuality( -1 ), + mnMatchType( ImplFontAttrs::None ), + meMatchWeight( WEIGHT_DONTKNOW ), + meMatchWidth( WIDTH_DONTKNOW ) +{} + +PhysicalFontFamily::~PhysicalFontFamily() +{ +} + +void PhysicalFontFamily::AddFontFace( PhysicalFontFace* pNewFontFace ) +{ + if( maFontFaces.empty() ) + { + maFamilyName = pNewFontFace->GetFamilyName(); + maMapNames = pNewFontFace->GetMapNames(); + meFamily = pNewFontFace->GetFamilyType(); + mePitch = pNewFontFace->GetPitch(); + mnMinQuality = pNewFontFace->GetQuality(); + } + else + { + if( meFamily == FAMILY_DONTKNOW ) + meFamily = pNewFontFace->GetFamilyType(); + if( mePitch == PITCH_DONTKNOW ) + mePitch = pNewFontFace->GetPitch(); + if( mnMinQuality > pNewFontFace->GetQuality() ) + mnMinQuality = pNewFontFace->GetQuality(); + } + + // set attributes for attribute based font matching + mnTypeFaces |= FontTypeFaces::Scalable; + + if( pNewFontFace->IsSymbolFont() ) + mnTypeFaces |= FontTypeFaces::Symbol; + else + mnTypeFaces |= FontTypeFaces::NoneSymbol; + + if( pNewFontFace->GetWeight() != WEIGHT_DONTKNOW ) + { + if( pNewFontFace->GetWeight() >= WEIGHT_SEMIBOLD ) + mnTypeFaces |= FontTypeFaces::Bold; + else if( pNewFontFace->GetWeight() <= WEIGHT_SEMILIGHT ) + mnTypeFaces |= FontTypeFaces::Light; + else + mnTypeFaces |= FontTypeFaces::Normal; + } + + if( pNewFontFace->GetItalic() == ITALIC_NONE ) + mnTypeFaces |= FontTypeFaces::NoneItalic; + else if( (pNewFontFace->GetItalic() == ITALIC_NORMAL) + || (pNewFontFace->GetItalic() == ITALIC_OBLIQUE) ) + mnTypeFaces |= FontTypeFaces::Italic; + + // reassign name (sharing saves memory) + if( pNewFontFace->GetFamilyName() == GetFamilyName() ) + pNewFontFace->SetFamilyName( GetFamilyName() ); + + // add the new physical font face, replacing existing font face if necessary + // TODO: get rid of linear search? + auto it(maFontFaces.begin()); + for (; it != maFontFaces.end(); ++it) + { + PhysicalFontFace* pFoundFontFace = it->get(); + sal_Int32 eComp = pNewFontFace->CompareIgnoreSize( *pFoundFontFace ); + if( eComp > 0 ) + continue; + if( eComp < 0 ) + break; + + // ignore duplicate if its quality is worse + if( pNewFontFace->GetQuality() < pFoundFontFace->GetQuality() ) + return; + + // keep the device font if its quality is good enough + if( pNewFontFace->GetQuality() == pFoundFontFace->GetQuality() ) + return; + + // replace existing font face with a better one + *it = pNewFontFace; // insert at sort position + return; + } + + maFontFaces.emplace(it, pNewFontFace); // insert at sort position +} + +// get font attributes using the normalized font family name +void PhysicalFontFamily::InitMatchData( const utl::FontSubstConfiguration& rFontSubst, + const OUString& rSearchName ) +{ + OUString aShortName; + OUString aMatchFamilyName(maMatchFamilyName); + // get font attributes from the decorated font name + utl::FontSubstConfiguration::getMapName( rSearchName, aShortName, aMatchFamilyName, + meMatchWeight, meMatchWidth, mnMatchType ); + maMatchFamilyName = aMatchFamilyName; + const utl::FontNameAttr* pFontAttr = rFontSubst.getSubstInfo( rSearchName ); + // eventually use the stripped name + if( !pFontAttr ) + if( aShortName != rSearchName ) + pFontAttr = rFontSubst.getSubstInfo( aShortName ); + CalcType( mnMatchType, meMatchWeight, meMatchWidth, meFamily, pFontAttr ); + mnMatchType |= lcl_IsCJKFont( maFamilyName ); +} + +PhysicalFontFace* PhysicalFontFamily::FindBestFontFace( const vcl::font::FontSelectPattern& rFSD ) const +{ + if( maFontFaces.empty() ) + return nullptr; + if( maFontFaces.size() == 1) + return maFontFaces[0].get(); + + // FontName+StyleName should map to FamilyName+StyleName + const OUString& rSearchName = rFSD.maTargetName; + OUString aTargetStyleName; + const OUString* pTargetStyleName = nullptr; + if((rSearchName.getLength() > maSearchName.getLength()) + && rSearchName.startsWith( maSearchName ) ) + { + aTargetStyleName = rSearchName.copy(maSearchName.getLength() + 1); + pTargetStyleName = &aTargetStyleName; + } + + // TODO: linear search improve! + PhysicalFontFace* pBestFontFace = maFontFaces[0].get(); + FontMatchStatus aFontMatchStatus = {0, pTargetStyleName}; + for (auto const& font : maFontFaces) + { + PhysicalFontFace* pFoundFontFace = font.get(); + if( pFoundFontFace->IsBetterMatch( rFSD, aFontMatchStatus ) ) + pBestFontFace = pFoundFontFace; + } + + return pBestFontFace; +} + +// update device font list with unique font faces, with uniqueness +// meaning different font attributes, but not different fonts sizes +void PhysicalFontFamily::UpdateDevFontList( vcl::font::PhysicalFontFaceCollection& rDevFontList ) const +{ + PhysicalFontFace* pPrevFace = nullptr; + for (auto const& font : maFontFaces) + { + PhysicalFontFace* pFoundFontFace = font.get(); + if( !pPrevFace || pFoundFontFace->CompareIgnoreSize( *pPrevFace ) ) + rDevFontList.Add( pFoundFontFace ); + pPrevFace = pFoundFontFace; + } +} + +void PhysicalFontFamily::UpdateCloneFontList(vcl::font::PhysicalFontCollection& rFontCollection) const +{ + OUString aFamilyName = GetEnglishSearchFontName( GetFamilyName() ); + PhysicalFontFamily* pFamily(nullptr); + + for (auto const& font : maFontFaces) + { + PhysicalFontFace *pFoundFontFace = font.get(); + + if (!pFamily) + { // tdf#98989 lazy create as family without faces won't work + pFamily = rFontCollection.FindOrCreateFontFamily(aFamilyName); + } + assert(pFamily); + pFamily->AddFontFace( pFoundFontFace ); + } +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |