aa53ccd834
Change-Id: Ide306f0656230460f976daef0ed213f734136030 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155167 Tested-by: Jenkins Reviewed-by: خالد حسني <khaled@libreoffice.org>
269 lines
9.3 KiB
C++
269 lines
9.3 KiB
C++
/* -*- 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>
|
|
#include <utility>
|
|
|
|
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( std::u16string_view rFontName )
|
|
{
|
|
// Test, if Fontname includes CJK characters --> In this case we
|
|
// mention that it is a CJK font
|
|
for(size_t i = 0; i < rFontName.size(); 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( OUString aSearchName )
|
|
: maSearchName(std::move( aSearchName )),
|
|
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();
|
|
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->IsMicrosoftSymbolEncoded() )
|
|
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: */
|