/* -*- 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 .
*/
if ( mpMetaFile )
{
mpMetaFile->AddAction( new MetaFontAction( aFont ) ); // the color and alignment actions don't belong here // TODO: get rid of them without breaking anything...
mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlignment() ) );
mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
}
if ( maFont.IsSameInstance( aFont ) ) return;
// Optimization MT/HDU: COL_TRANSPARENT means SetFont should ignore the font color, // because SetTextColor() is used for this. // #i28759# maTextColor might have been changed behind our back, commit then, too. if( aFont.GetColor() != COL_TRANSPARENT
&& (aFont.GetColor() != maFont.GetColor() || aFont.GetColor() != maTextColor ) )
{
maTextColor = aFont.GetColor();
mbInitTextColor = true; if( mpMetaFile )
mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) );
}
maFont = aFont;
mbNewFont = true;
if( !mpAlphaVDev ) return;
// #i30463# // Since SetFont might change the text color, apply that only // selectively to alpha vdev (which normally paints opaque text // with COL_BLACK) if( aFont.GetColor() != COL_TRANSPARENT )
{
mpAlphaVDev->SetTextColor( COL_ALPHA_OPAQUE );
aFont.SetColor( COL_TRANSPARENT );
}
if( !aDefault.isEmpty() )
aSearch = aDefault; else
aSearch = rDefaults.getUserInterfaceFont( aLanguageTag ); // use the UI font as a fallback
// during cppunit tests with SAL_NON_APPLICATION_FONT_USE set we don't have any bundled fonts // that support the default CTL and CJK languages of Hindi and Chinese, so just pick something // (unsuitable) that does exist, if they get used with SAL_NON_APPLICATION_FONT_USE=abort then // glyph fallback will trigger std::abort if (bAbortOnFontSubstitute)
{ if (eLang == LANGUAGE_HINDI || eLang == LANGUAGE_CHINESE_SIMPLIFIED)
aSearch = "DejaVu Sans";
}
} else
aSearch = "Liberation Serif";
switch ( nType )
{ case DefaultFontType::SANS_UNICODE: case DefaultFontType::UI_SANS: case DefaultFontType::SANS: case DefaultFontType::LATIN_HEADING: case DefaultFontType::LATIN_SPREADSHEET: case DefaultFontType::LATIN_DISPLAY:
aFont.SetFamily( FAMILY_SWISS ); break;
case DefaultFontType::SERIF: case DefaultFontType::LATIN_TEXT: case DefaultFontType::LATIN_PRESENTATION:
aFont.SetFamily( FAMILY_ROMAN ); break;
case DefaultFontType::FIXED: case DefaultFontType::LATIN_FIXED: case DefaultFontType::UI_FIXED:
aFont.SetPitch( PITCH_FIXED );
aFont.SetFamily( FAMILY_MODERN ); break;
case DefaultFontType::SYMBOL:
aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL ); break;
case DefaultFontType::CJK_TEXT: case DefaultFontType::CJK_PRESENTATION: case DefaultFontType::CJK_SPREADSHEET: case DefaultFontType::CJK_HEADING: case DefaultFontType::CJK_DISPLAY: case DefaultFontType::CTL_TEXT: case DefaultFontType::CTL_PRESENTATION: case DefaultFontType::CTL_SPREADSHEET: case DefaultFontType::CTL_HEADING: case DefaultFontType::CTL_DISPLAY:
aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later... break;
}
if ( !aSearch.isEmpty() )
{
aFont.SetFontHeight( 12 ); // corresponds to nDefaultHeight
aFont.SetWeight( WEIGHT_NORMAL );
aFont.SetLanguage( eLang );
if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW )
aFont.SetCharSet( osl_getThreadTextEncoding() );
// Should we only return available fonts on the given device if ( pOutDev )
{
pOutDev->ImplInitFontList();
// Search Font in the FontList
OUString aName;
sal_Int32 nIndex = 0; do
{
vcl::font::PhysicalFontFamily* pFontFamily = pOutDev->mxFontCollection->FindFontFamily( GetNextFontToken( aSearch, nIndex ) ); if( pFontFamily )
{
AddTokenFontName( aName, pFontFamily->GetFamilyName() ); if( nFlags & GetDefaultFontFlags::OnlyOne ) break;
}
} while ( nIndex != -1 );
aFont.SetFamilyName( aName );
}
// No Name, then set all names if ( aFont.GetFamilyName().isEmpty() )
{ if ( nFlags & GetDefaultFontFlags::OnlyOne )
{ if( !pOutDev )
{
SAL_WARN_IF(!comphelper::IsFuzzing(), "vcl.gdi", "No default window has been set for the application - we really shouldn't be able to get here");
aFont.SetFamilyName( aSearch.getToken( 0, ';' ) );
} else
{
pOutDev->ImplInitFontList();
aFont.SetFamilyName( aSearch );
// convert to pixel height
Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetFontSize() ); if ( !aSize.Height() )
{ // use default pixel height only when logical height is zero if ( aFont.GetFontHeight() )
aSize.setHeight( 1 ); else
aSize.setHeight( (12*pOutDev->mnDPIY)/72 );
}
// use default width only when logical width is zero if( (0 == aSize.Width()) && (0 != aFont.GetFontSize().Width()) )
aSize.setWidth( 1 );
// get the name of the first available font float fExactHeight = static_cast<float>(aSize.Height());
rtl::Reference<LogicalFontInstance> pFontInstance = pOutDev->mxFontCache->GetFontInstance( pOutDev->mxFontCollection.get(), aFont, aSize, fExactHeight ); if (pFontInstance)
{
assert(pFontInstance->GetFontFace());
aFont.SetFamilyName(pFontInstance->GetFontFace()->GetFamilyName());
}
}
} else
aFont.SetFamilyName( aSearch );
}
}
#if OSL_DEBUG_LEVEL > 2 constchar* s = "SANS_UNKNOWN"; switch ( nType )
{ case DefaultFontType::SANS_UNICODE: s = "SANS_UNICODE"; break; case DefaultFontType::UI_SANS: s = "UI_SANS"; break;
case DefaultFontType::SANS: s = "SANS"; break; case DefaultFontType::LATIN_HEADING: s = "LATIN_HEADING"; break; case DefaultFontType::LATIN_SPREADSHEET: s = "LATIN_SPREADSHEET"; break; case DefaultFontType::LATIN_DISPLAY: s = "LATIN_DISPLAY"; break;
case DefaultFontType::SERIF: s = "SERIF"; break; case DefaultFontType::LATIN_TEXT: s = "LATIN_TEXT"; break; case DefaultFontType::LATIN_PRESENTATION: s = "LATIN_PRESENTATION"; break;
case DefaultFontType::FIXED: s = "FIXED"; break; case DefaultFontType::LATIN_FIXED: s = "LATIN_FIXED"; break; case DefaultFontType::UI_FIXED: s = "UI_FIXED"; break;
case DefaultFontType::SYMBOL: s = "SYMBOL"; break;
case DefaultFontType::CJK_TEXT: s = "CJK_TEXT"; break; case DefaultFontType::CJK_PRESENTATION: s = "CJK_PRESENTATION"; break; case DefaultFontType::CJK_SPREADSHEET: s = "CJK_SPREADSHEET"; break; case DefaultFontType::CJK_HEADING: s = "CJK_HEADING"; break; case DefaultFontType::CJK_DISPLAY: s = "CJK_DISPLAY"; break;
case DefaultFontType::CTL_TEXT: s = "CTL_TEXT"; break; case DefaultFontType::CTL_PRESENTATION: s = "CTL_PRESENTATION"; break; case DefaultFontType::CTL_SPREADSHEET: s = "CTL_SPREADSHEET"; break; case DefaultFontType::CTL_HEADING: s = "CTL_HEADING"; break; case DefaultFontType::CTL_DISPLAY: s = "CTL_DISPLAY"; break;
}
SAL_INFO("vcl.gdi", "OutputDevice::GetDefaultFont() Type=" << s
<< " lang=" << eLang
<< " flags=" << static_cast<int>(nFlags)
<< " family=\"" << aFont.GetFamilyName() << "\""); #endif
// There is absolutely no way there should be no fonts available on the device if( !mxFontCollection->Count() )
{
OUString aError( u"Application error: no fonts and no vcl resource found on your system"_ustr );
OUString aResStr(VclResId(SV_ACCESSERROR_NO_FONTS)); if (!aResStr.isEmpty())
aError = aResStr;
Application::Abort(aError);
}
}
if (!ImplNewFont()) returnfalse; if (!mpFontInstance) returnfalse; if (!mpGraphics)
{ if (!AcquireGraphics()) returnfalse;
} elseif (!mbInitFont) returntrue;
// we need a graphics if ( !mpGraphics && !AcquireGraphics() )
{
SAL_WARN("vcl.gdi", "OutputDevice::ImplNewFont(): no Graphics, no Font"); returnfalse;
}
assert(mpGraphics);
ImplInitFontList();
// convert to pixel height // TODO: replace integer based aSize completely with subpixel accurate type float fExactHeight = ImplLogicHeightToDeviceSubPixel(maFont.GetFontHeight());
Size aSize = ImplLogicToDevicePixel( maFont.GetFontSize() ); if ( !aSize.Height() )
{ // use default pixel height only when logical height is zero if ( maFont.GetFontSize().Height() )
aSize.setHeight( 1 ); else
aSize.setHeight( (12*mnDPIY)/72 );
fExactHeight = static_cast<float>(aSize.Height());
}
// select the default width only when logical width is zero if( (0 == aSize.Width()) && (0 != maFont.GetFontSize().Width()) )
aSize.setWidth( 1 );
// decide if antialiasing is appropriate bool bNonAntialiased(GetAntialiasing() & AntialiasingFlags::DisableText); if (!comphelper::IsFuzzing())
{ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
bNonAntialiased |= bool(rStyleSettings.GetDisplayOptions() & DisplayOptions::AADisable);
bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > maFont.GetFontSize().Height());
}
if (!pFontInstance)
{
SAL_WARN("vcl.gdi", "OutputDevice::ImplNewFont(): no LogicalFontInstance, no Font"); returnfalse;
}
// mark when lower layers need to get involved
mbNewFont = false; if( bNewFontInstance )
mbInitFont = true;
// select font when it has not been initialized yet if (!pFontInstance->mbInit && InitFont())
{ // get metric data from device layers
pFontInstance->mbInit = true;
pFontInstance->mxFontMetric->ImplInitTextLineSize( this );
pFontInstance->mxFontMetric->ImplInitAboveTextLineSize( this );
pFontInstance->mxFontMetric->ImplInitFlags( this );
// #95414# fix for OLE objects which use scale factors very creatively if (mbMap && !aSize.Width())
bRet = AttemptOLEFontScaleFix(const_cast<vcl::Font&>(maFont), aSize.Height());
std::unique_ptr<SalLayout> OutputDevice::getFallbackLayout(
LogicalFontInstance* pLogicalFont, int nFallbackLevel,
vcl::text::ImplLayoutArgs& rLayoutArgs, const SalLayoutGlyphs* pGlyphs) const
{ // we need a graphics if (!mpGraphics && !AcquireGraphics()) return nullptr;
if (!pFallback->LayoutText(rLayoutArgs, pGlyphs ? pGlyphs->Impl(nFallbackLevel) : nullptr))
{ // there is no need for a font that couldn't resolve anything return nullptr;
}
mpForcedFallbackInstance = mpFontInstance;
SetFont(aOldFont); if (!InitFont()) returnfalse;
if (mpForcedFallbackInstance) returntrue;
returnfalse;
}
std::unique_ptr<SalLayout> OutputDevice::ImplGlyphFallbackLayout( std::unique_ptr<SalLayout> pSalLayout,
vcl::text::ImplLayoutArgs& rLayoutArgs, const SalLayoutGlyphs* pGlyphs ) const
{ // This function relies on a valid mpFontInstance, if it doesn't exist bail out // - we'd have crashed later on anyway. At least here we can catch the error in debug // mode. if ( !mpFontInstance )
{
SAL_WARN ("vcl.gdi", "No font entry set in OutputDevice");
assert(mpFontInstance); return nullptr;
}
// get list of code units that need glyph fallback bool bRTL; int nMinRunPos, nEndRunPos;
OUStringBuffer aMissingCodeBuf(512); while (rLayoutArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL))
aMissingCodeBuf.append(rLayoutArgs.mrStr.subView(nMinRunPos, nEndRunPos - nMinRunPos));
rLayoutArgs.ResetPos();
OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear();
// try if fallback fonts support the missing code units for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK; ++nFallbackLevel )
{
rtl::Reference<LogicalFontInstance> pFallbackFont; if (!bHasUsedFallback && mpForcedFallbackInstance)
{
pFallbackFont = mpForcedFallbackInstance;
bHasUsedFallback = true;
} elseif(pGlyphsImpl != nullptr)
{
pFallbackFont = pGlyphsImpl->GetFont();
}
// find a font family suited for glyph fallback // GetGlyphFallbackFont() needs a valid FontInstance // if the system-specific glyph fallback is active
OUString oldMissingCodes = aMissingCodes; if( !pFallbackFont )
pFallbackFont = mxFontCache->GetGlyphFallbackFont( mxFontCollection.get(),
aFontSelData, mpFontInstance.get(), nFallbackLevel, aMissingCodes ); if( !pFallbackFont ) break;
if( nFallbackLevel < MAX_FALLBACK-1)
{ // ignore fallback font if it is the same as the original font // TODO: This seems broken. Either the font does not provide any of the missing // codes, in which case the fallback should not select it. Or it does provide // some of the missing codes, and then why weren't they used the first time? // This will just loop repeatedly finding the same font (it used to remove // the found font from mxFontCache, but doesn't do that anymore and I don't // see how doing that would remove the font from consideration for fallback). if( mpFontInstance->GetFontFace() == pFallbackFont->GetFontFace())
{ if(aMissingCodes != oldMissingCodes)
{
SAL_INFO("vcl.gdi", "Font fallback to the same font, but has missing codes"); // Restore the missing codes if we're not going to use this font.
aMissingCodes = oldMissingCodes;
} continue;
}
}
// create and add glyph fallback layout to multilayout
std::unique_ptr<SalLayout> pFallback = getFallbackLayout(pFallbackFont.get(),
nFallbackLevel, rLayoutArgs, pGlyphs); if (pFallback)
{ if( !pMultiSalLayout )
pMultiSalLayout.reset( new MultiSalLayout( std::move(pSalLayout) ) );
pMultiSalLayout->AddFallback(std::move(pFallback), rLayoutArgs.maRuns); if (nFallbackLevel == MAX_FALLBACK-1)
pMultiSalLayout->SetIncomplete(true);
}
if (pGlyphs != nullptr)
pGlyphsImpl = pGlyphs->Impl(nFallbackLevel + 1);
// break when this fallback was sufficient if( !rLayoutArgs.PrepareFallback(pGlyphsImpl) ) break;
}
if (pMultiSalLayout) // due to missing glyphs, multilevel layout fallback attempted
{ // if it works, use that Layout if (pMultiSalLayout->LayoutText(rLayoutArgs, nullptr))
pSalLayout = std::move(pMultiSalLayout); else
{ // if it doesn't, give up and restore ownership of the pSalLayout // back to its original state
pSalLayout = pMultiSalLayout->ReleaseBaseLayout();
}
}
// restore orig font settings
rLayoutArgs.maRuns = std::move(aLayoutRuns);
return pSalLayout;
}
tools::Long OutputDevice::GetMinKashida() const
{ if (!ImplNewFont()) return 0;
auto nKashidaWidth = mpFontInstance->mxFontMetric->GetMinKashida(); if (!mbMap)
nKashidaWidth = std::ceil(nKashidaWidth);
// tdf#163105: Get map of valid kashida positions for a single word void OutputDevice::GetWordKashidaPositions(const OUString& rText,
std::vector<bool>* pOutMap) const
{
pOutMap->clear();
auto nEnd = rText.getLength();
// do layout
std::unique_ptr<SalLayout> pSalLayout = ImplLayout(rText, 0, nEnd); if (!pSalLayout) return;
// tdf#163215: VCL cannot suggest valid kashida positions for certain fonts (e.g. AAT). if (!pSalLayout->HasFontKashidaPositions()) return;
pOutMap->resize(nEnd, false); for (sal_Int32 i = 0; i < nEnd; ++i)
{ auto nNextPos = i + 1;
// Skip combining marks to find the next character after this position. while (nNextPos < nEnd
&& u_getIntPropertyValue(rText[nNextPos], UCHAR_JOINING_TYPE) == U_JT_TRANSPARENT)
{
++nNextPos;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.