summaryrefslogtreecommitdiff
path: root/vcl/source/font/PhysicalFontFamily.cxx
diff options
context:
space:
mode:
authorNorbert Thiebaud <nthiebaud@gmail.com>2014-03-20 00:22:26 -0500
committerNorbert Thiebaud <nthiebaud@gmail.com>2014-03-20 16:11:58 -0500
commit7260bcd68726739b5fe26b4d29a1de47e7b0f5a7 (patch)
tree360f470874da345bf0723cfd90684942824df739 /vcl/source/font/PhysicalFontFamily.cxx
parent7154b092a716d4d0041a8a563294511ec9e5dbc6 (diff)
cosmetic: split PhysicalFontFamily/Collection out of outdev3.cxx
Change-Id: Iae8eb15413c0c069c14edd92c94ecb0113d9d371
Diffstat (limited to 'vcl/source/font/PhysicalFontFamily.cxx')
-rw-r--r--vcl/source/font/PhysicalFontFamily.cxx298
1 files changed, 298 insertions, 0 deletions
diff --git a/vcl/source/font/PhysicalFontFamily.cxx b/vcl/source/font/PhysicalFontFamily.cxx
new file mode 100644
index 000000000000..f0f33071b1b3
--- /dev/null
+++ b/vcl/source/font/PhysicalFontFamily.cxx
@@ -0,0 +1,298 @@
+/* -*- 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/types.h>
+
+#include <rtl/ustring.hxx>
+
+#include "outdev.h"
+#include "PhysicalFontFace.hxx"
+#include "PhysicalFontCollection.hxx"
+
+#include "PhysicalFontFamily.hxx"
+
+void PhysicalFontFamily::CalcType( sal_uLong& rType, FontWeight& rWeight, FontWidth& rWidth,
+ FontFamily eFamily, const utl::FontNameAttr* pFontAttr )
+{
+ if ( eFamily != FAMILY_DONTKNOW )
+ {
+ if ( eFamily == FAMILY_SWISS )
+ rType |= IMPL_FONT_ATTR_SANSSERIF;
+ else if ( eFamily == FAMILY_ROMAN )
+ rType |= IMPL_FONT_ATTR_SERIF;
+ else if ( eFamily == FAMILY_SCRIPT )
+ rType |= IMPL_FONT_ATTR_SCRIPT;
+ else if ( eFamily == FAMILY_MODERN )
+ rType |= IMPL_FONT_ATTR_FIXED;
+ else if ( eFamily == FAMILY_DECORATIVE )
+ rType |= IMPL_FONT_ATTR_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 unsigned 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 IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_JP;
+
+ // korean
+ if ( ((ch >= 0xAC00) && (ch <= 0xD7AF)) ||
+ ((ch >= 0x3130) && (ch <= 0x318F)) ||
+ ((ch >= 0x1100) && (ch <= 0x11FF)) )
+ return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_KR;
+
+ // chinese
+ if ( ((ch >= 0x3400) && (ch <= 0x9FFF)) )
+ return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_TC|IMPL_FONT_ATTR_CJK_SC;
+
+ // cjk
+ if ( ((ch >= 0x3000) && (ch <= 0xD7AF)) ||
+ ((ch >= 0xFF00) && (ch <= 0xFFEE)) )
+ return IMPL_FONT_ATTR_CJK;
+
+ }
+
+ return 0;
+}
+
+
+PhysicalFontFamily::PhysicalFontFamily( const OUString& rSearchName )
+: mpFirst( NULL ),
+ maSearchName( rSearchName ),
+ mnTypeFaces( 0 ),
+ mnMatchType( 0 ),
+ meMatchWeight( WEIGHT_DONTKNOW ),
+ meMatchWidth( WIDTH_DONTKNOW ),
+ meFamily( FAMILY_DONTKNOW ),
+ mePitch( PITCH_DONTKNOW ),
+ mnMinQuality( -1 )
+{}
+
+PhysicalFontFamily::~PhysicalFontFamily()
+{
+ // release all physical font faces
+ while( mpFirst )
+ {
+ PhysicalFontFace* pFace = mpFirst;
+ mpFirst = pFace->GetNextFace();
+ delete pFace;
+ }
+}
+
+bool PhysicalFontFamily::AddFontFace( PhysicalFontFace* pNewData )
+{
+ pNewData->mpNext = NULL;
+
+ if( !mpFirst )
+ {
+ maName = pNewData->GetFamilyName();
+ maMapNames = pNewData->maMapNames;
+ meFamily = pNewData->GetFamilyType();
+ mePitch = pNewData->GetPitch();
+ mnMinQuality = pNewData->mnQuality;
+ }
+ else
+ {
+ if( meFamily == FAMILY_DONTKNOW )
+ meFamily = pNewData->GetFamilyType();
+ if( mePitch == PITCH_DONTKNOW )
+ mePitch = pNewData->GetPitch();
+ if( mnMinQuality > pNewData->mnQuality )
+ mnMinQuality = pNewData->mnQuality;
+ }
+
+ // set attributes for attribute based font matching
+ if( pNewData->IsScalable() )
+ mnTypeFaces |= FONT_FAMILY_SCALABLE;
+
+ if( pNewData->IsSymbolFont() )
+ mnTypeFaces |= FONT_FAMILY_SYMBOL;
+ else
+ mnTypeFaces |= FONT_FAMILY_NONESYMBOL;
+
+ if( pNewData->GetWeight() != WEIGHT_DONTKNOW )
+ {
+ if( pNewData->GetWeight() >= WEIGHT_SEMIBOLD )
+ mnTypeFaces |= FONT_FAMILY_BOLD;
+ else if( pNewData->GetWeight() <= WEIGHT_SEMILIGHT )
+ mnTypeFaces |= FONT_FAMILY_LIGHT;
+ else
+ mnTypeFaces |= FONT_FAMILY_NORMAL;
+ }
+
+ if( pNewData->GetSlant() == ITALIC_NONE )
+ mnTypeFaces |= FONT_FAMILY_NONEITALIC;
+ else if( (pNewData->GetSlant() == ITALIC_NORMAL)
+ || (pNewData->GetSlant() == ITALIC_OBLIQUE) )
+ mnTypeFaces |= FONT_FAMILY_ITALIC;
+
+ if( (meMatchWeight == WEIGHT_DONTKNOW)
+ || (meMatchWidth == WIDTH_DONTKNOW)
+ || (mnMatchType == 0) )
+ {
+ // TODO: is it cheaper to calc matching attributes now or on demand?
+ // calc matching attributes if other entries are already initialized
+
+ // Do lazy, quite expensive, not needed in start-up!
+ // const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
+ // InitMatchData( rFontSubst, maSearchName );
+ // mbMatchData=true; // Somewhere else???
+ }
+
+ // reassign name (sharing saves memory)
+ if( pNewData->GetFamilyName() == GetFamilyName() )
+ pNewData->SetFamilyName( GetFamilyName() );
+
+ // insert new physical font face into linked list
+ // TODO: get rid of linear search?
+ PhysicalFontFace* pData;
+ PhysicalFontFace** ppHere = &mpFirst;
+ for(; (pData=*ppHere) != NULL; ppHere=&pData->mpNext )
+ {
+ sal_Int32 eComp = pNewData->CompareWithSize( *pData );
+ if( eComp > 0 )
+ continue;
+ if( eComp < 0 )
+ break;
+
+ // ignore duplicate if its quality is worse
+ if( pNewData->mnQuality < pData->mnQuality )
+ return false;
+
+ // keep the device font if its quality is good enough
+ if( (pNewData->mnQuality == pData->mnQuality)
+ && (pData->mbDevice || !pNewData->mbDevice) )
+ return false;
+
+ // replace existing font face with a better one
+ pNewData->mpNext = pData->mpNext;
+ *ppHere = pNewData;
+ delete pData;
+ return true;
+ }
+
+ // insert into or append to list of physical font faces
+ pNewData->mpNext = pData;
+ *ppHere = pNewData;
+ return true;
+}
+
+// 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
+ rFontSubst.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( maName );
+}
+
+PhysicalFontFace* PhysicalFontFamily::FindBestFontFace( const FontSelectPattern& rFSD ) const
+{
+ if( !mpFirst )
+ return NULL;
+ if( !mpFirst->GetNextFace() )
+ return mpFirst;
+
+ // FontName+StyleName should map to FamilyName+StyleName
+ const OUString& rSearchName = rFSD.maTargetName;
+ OUString aTargetStyleName;
+ const OUString* pTargetStyleName = NULL;
+ if( (rSearchName.getLength() > maSearchName.getLength())
+ && rSearchName.startsWith( maSearchName ) )
+ {
+ aTargetStyleName = rSearchName.copy(maSearchName.getLength() + 1);
+ pTargetStyleName = &aTargetStyleName;
+ }
+
+ // TODO: linear search improve!
+ PhysicalFontFace* pFontFace = mpFirst;
+ PhysicalFontFace* pBestFontFace = pFontFace;
+ FontMatchStatus aFontMatchStatus = {0,0,0, pTargetStyleName};
+ for(; pFontFace; pFontFace = pFontFace->GetNextFace() )
+ if( pFontFace->IsBetterMatch( rFSD, aFontMatchStatus ) )
+ pBestFontFace = pFontFace;
+
+ return pBestFontFace;
+}
+
+// update device font list with unique font faces, with uniqueness
+// meaning different font attributes, but not different fonts sizes
+void PhysicalFontFamily::UpdateDevFontList( ImplGetDevFontList& rDevFontList ) const
+{
+ PhysicalFontFace* pPrevFace = NULL;
+ for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
+ {
+ if( !pPrevFace || pFace->CompareIgnoreSize( *pPrevFace ) )
+ rDevFontList.Add( pFace );
+ pPrevFace = pFace;
+ }
+}
+
+void PhysicalFontFamily::GetFontHeights( std::set<int>& rHeights ) const
+{
+ // add all available font heights
+ for( const PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
+ rHeights.insert( pFace->GetHeight() );
+}
+
+void PhysicalFontFamily::UpdateCloneFontList( PhysicalFontCollection& rFontCollection,
+ bool bScalable, bool bEmbeddable ) const
+{
+ for( PhysicalFontFace* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
+ {
+ if( bScalable && !pFace->IsScalable() )
+ continue;
+ if( bEmbeddable && !pFace->IsEmbeddable() && !pFace->IsSubsettable() )
+ continue;
+
+ PhysicalFontFace* pClonedFace = pFace->Clone();
+ rFontCollection.Add( pClonedFace );
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */