Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / filter / source / svg / svgfontexport.cxx
blob203655f4281bed5dfbcd1bd047eb453200da2a7f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "svgfontexport.hxx"
22 #include "svgfilter.hxx"
23 #include "svgwriter.hxx"
25 #include <vcl/unohelp.hxx>
26 #include <vcl/font.hxx>
27 #include <vcl/outdev.hxx>
28 #include <vcl/settings.hxx>
29 #include <i18nlangtag/languagetag.hxx>
31 static const sal_Int32 nFontEM = 2048;
34 SVGFontExport::SVGFontExport( SVGExport& rExport, const ::std::vector< ObjectRepresentation >& rObjects ) :
35 mrExport( rExport ),
36 maObjects( rObjects ),
37 mnCurFontId( 0 )
42 SVGFontExport::~SVGFontExport()
47 SVGFontExport::GlyphSet& SVGFontExport::implGetGlyphSet( const vcl::Font& rFont )
49 FontWeight eWeight( WEIGHT_NORMAL );
50 FontItalic eItalic( ITALIC_NONE );
51 const OUString& aFontName( rFont.GetFamilyName() );
53 switch( rFont.GetWeight() )
55 case WEIGHT_BOLD:
56 case WEIGHT_ULTRABOLD:
57 case WEIGHT_BLACK:
58 eWeight = WEIGHT_BOLD;
59 break;
61 default:
62 break;
65 if( rFont.GetItalic() != ITALIC_NONE )
66 eItalic = ITALIC_NORMAL;
68 return( maGlyphTree[ aFontName.getToken( 0, ';' ) ][ eWeight ][ eItalic ] );
72 void SVGFontExport::implCollectGlyphs()
74 ScopedVclPtrInstance< VirtualDevice > pVDev;
76 pVDev->EnableOutput( false );
78 for (auto const& elem : maObjects)
80 if( elem.HasRepresentation() )
82 const GDIMetaFile& rMtf = elem.GetRepresentation();
84 pVDev->Push();
86 for( size_t i = 0, nCount = rMtf.GetActionSize(); i < nCount; ++i )
88 OUString aText;
89 MetaAction* pAction = rMtf.GetAction( i );
90 const MetaActionType nType = pAction->GetType();
92 switch( nType )
94 case MetaActionType::TEXT:
96 const MetaTextAction* pA = static_cast<const MetaTextAction*>(pAction);
97 sal_Int32 aLength=std::min( pA->GetText().getLength(), pA->GetLen() );
98 aText = pA->GetText().copy( pA->GetIndex(), aLength );
100 break;
102 case MetaActionType::TEXTRECT:
104 const MetaTextRectAction* pA = static_cast<const MetaTextRectAction*>(pAction);
105 aText = pA->GetText();
107 break;
109 case MetaActionType::TEXTARRAY:
111 const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pAction);
112 sal_Int32 aLength=std::min( pA->GetText().getLength(), pA->GetLen() );
113 aText = pA->GetText().copy( pA->GetIndex(), aLength );
115 break;
117 case MetaActionType::STRETCHTEXT:
119 const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction*>(pAction);
120 sal_Int32 aLength=std::min( pA->GetText().getLength(), pA->GetLen() );
121 aText = pA->GetText().copy( pA->GetIndex(), aLength );
123 break;
125 default:
126 pAction->Execute( pVDev );
127 break;
130 if( !aText.isEmpty() )
132 GlyphSet& rGlyphSet = implGetGlyphSet( pVDev->GetFont() );
133 css::uno::Reference< css::i18n::XBreakIterator > xBI(
134 vcl::unohelper::CreateBreakIterator() );
136 if( xBI.is() )
138 const css::lang::Locale& rLocale = Application::GetSettings().GetLanguageTag().getLocale();
139 sal_Int32 nCurPos = 0, nLastPos = -1;
141 while( ( nCurPos < aText.getLength() ) && ( nCurPos > nLastPos ) )
143 sal_Int32 nCount2 = 1;
145 nLastPos = nCurPos;
146 nCurPos = xBI->nextCharacters( aText, nCurPos, rLocale,
147 css::i18n::CharacterIteratorMode::SKIPCELL,
148 nCount2, nCount2 );
150 rGlyphSet.insert( aText.copy( nLastPos, nCurPos - nLastPos ) );
153 else
155 const sal_Unicode* pStr = aText.getStr();
157 for( sal_uInt32 k = 0, nLen = aText.getLength(); k < nLen; ++k )
158 rGlyphSet.insert( OUString( pStr[ k ] ) );
163 pVDev->Pop();
169 void SVGFontExport::implEmbedFont( const vcl::Font& rFont )
171 if( mrExport.IsEmbedFonts() )
173 GlyphSet& rGlyphSet = implGetGlyphSet( rFont );
175 if( !rGlyphSet.empty() )
177 const OUString aEmbeddedFontStr( "EmbeddedFont_" );
180 SvXMLElementExport aExp( mrExport, XML_NAMESPACE_NONE, "defs", true, true );
181 OUString aCurIdStr( aEmbeddedFontStr );
182 OUString aUnitsPerEM( OUString::number( nFontEM ) );
183 ScopedVclPtrInstance< VirtualDevice > pVDev;
184 vcl::Font aFont( rFont );
186 aFont.SetFontSize( Size( 0, nFontEM ) );
187 aFont.SetAlignment( ALIGN_BASELINE );
189 pVDev->SetMapMode(MapMode(MapUnit::Map100thMM));
190 pVDev->SetFont( aFont );
192 aCurIdStr += OUString::number( ++mnCurFontId );
193 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", aCurIdStr );
194 mrExport.AddAttribute( XML_NAMESPACE_NONE, "horiz-adv-x", aUnitsPerEM );
197 SvXMLElementExport aExp2( mrExport, XML_NAMESPACE_NONE, "font", true, true );
198 OUString aFontWeight;
199 OUString aFontStyle;
200 const Size aSize( nFontEM, nFontEM );
202 // Font Weight
203 if( aFont.GetWeight() != WEIGHT_NORMAL )
204 aFontWeight = "bold";
205 else
206 aFontWeight = "normal";
208 // Font Italic
209 if( aFont.GetItalic() != ITALIC_NONE )
210 aFontStyle = "italic";
211 else
212 aFontStyle = "normal";
214 mrExport.AddAttribute( XML_NAMESPACE_NONE, "font-family", GetMappedFontName( rFont.GetFamilyName() ) );
215 mrExport.AddAttribute( XML_NAMESPACE_NONE, "units-per-em", aUnitsPerEM );
216 mrExport.AddAttribute( XML_NAMESPACE_NONE, "font-weight", aFontWeight );
217 mrExport.AddAttribute( XML_NAMESPACE_NONE, "font-style", aFontStyle );
218 mrExport.AddAttribute( XML_NAMESPACE_NONE, "ascent", OUString::number( pVDev->GetFontMetric().GetAscent() ) );
219 mrExport.AddAttribute( XML_NAMESPACE_NONE, "descent", OUString::number( pVDev->GetFontMetric().GetDescent() ) );
222 SvXMLElementExport aExp3( mrExport, XML_NAMESPACE_NONE, "font-face", true, true );
225 mrExport.AddAttribute( XML_NAMESPACE_NONE, "horiz-adv-x", OUString::number( aSize.Width() ) );
228 const Point aPos;
229 const tools::PolyPolygon aMissingGlyphPolyPoly( tools::Rectangle( aPos, aSize ) );
231 mrExport.AddAttribute( XML_NAMESPACE_NONE, "d", SVGActionWriter::GetPathString( aMissingGlyphPolyPoly, false ) );
234 SvXMLElementExport aExp4( mrExport, XML_NAMESPACE_NONE, "missing-glyph", true, true );
237 for (auto const& glyph : rGlyphSet)
239 implEmbedGlyph( *pVDev, glyph);
248 void SVGFontExport::implEmbedGlyph( OutputDevice const & rOut, const OUString& rCellStr )
250 tools::PolyPolygon aPolyPoly;
251 const sal_Unicode nSpace = ' ';
253 if( rOut.GetTextOutline( aPolyPoly, rCellStr ) )
255 tools::Rectangle aBoundRect;
257 aPolyPoly.Scale( 1.0, -1.0 );
259 if( !rOut.GetTextBoundRect( aBoundRect, rCellStr ) )
260 aBoundRect = tools::Rectangle( Point( 0, 0 ), Size( rOut.GetTextWidth( rCellStr ), 0 ) );
262 mrExport.AddAttribute( XML_NAMESPACE_NONE, "unicode", rCellStr );
264 if( rCellStr[ 0 ] == nSpace && rCellStr.getLength() == 1 )
265 aBoundRect = tools::Rectangle( Point( 0, 0 ), Size( rOut.GetTextWidth( OUString(' ') ), 0 ) );
267 mrExport.AddAttribute( XML_NAMESPACE_NONE, "horiz-adv-x", OUString::number( aBoundRect.GetWidth() ) );
269 const OUString aPathString( SVGActionWriter::GetPathString( aPolyPoly, false ) );
270 if( !aPathString.isEmpty() )
272 mrExport.AddAttribute( XML_NAMESPACE_NONE, "d", aPathString );
276 SvXMLElementExport aExp( mrExport, XML_NAMESPACE_NONE, "glyph", true, true );
282 void SVGFontExport::EmbedFonts()
284 implCollectGlyphs();
286 for (auto const& glyph : maGlyphTree)
288 const FontWeightMap& rFontWeightMap = glyph.second;
289 for (auto const& fontWeight : rFontWeightMap)
291 const FontItalicMap& rFontItalicMap = fontWeight.second;
292 for (auto const& fontItalic : rFontItalicMap)
294 vcl::Font aFont;
296 aFont.SetFamilyName( glyph.first );
297 aFont.SetWeight( fontWeight.first );
298 aFont.SetItalic( fontItalic.first );
300 implEmbedFont( aFont );
307 OUString SVGFontExport::GetMappedFontName( const OUString& rFontName ) const
309 OUString aRet( rFontName.getToken( 0, ';' ) );
311 if( mnCurFontId )
312 aRet += " embedded";
314 return aRet;
317 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */