LibreOffice Module filter (master) 1
svgfontexport.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21#include "svgfontexport.hxx"
22#include "svgfilter.hxx"
23#include "svgwriter.hxx"
24
25#include <vcl/unohelp.hxx>
26#include <vcl/font.hxx>
27#include <vcl/metric.hxx>
28#include <vcl/outdev.hxx>
29#include <vcl/settings.hxx>
32#include <o3tl/string_view.hxx>
33
34#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
35#include <com/sun/star/i18n/XBreakIterator.hpp>
36
37const sal_Int32 nFontEM = 2048;
38
39
40SVGFontExport::SVGFontExport( SVGExport& rExport, ::std::vector< ObjectRepresentation >&& rObjects ) :
41 mrExport( rExport ),
42 maObjects( std::move(rObjects) ),
43 mnCurFontId( 0 )
44{
45}
46
47
49{
50}
51
52
54{
55 FontWeight eWeight( WEIGHT_NORMAL );
56 FontItalic eItalic( ITALIC_NONE );
57 const OUString& aFontName( rFont.GetFamilyName() );
58
59 switch( rFont.GetWeight() )
60 {
61 case WEIGHT_BOLD:
63 case WEIGHT_BLACK:
64 eWeight = WEIGHT_BOLD;
65 break;
66
67 default:
68 break;
69 }
70
71 if( rFont.GetItalic() != ITALIC_NONE )
72 eItalic = ITALIC_NORMAL;
73
74 return( maGlyphTree[ aFontName.getToken( 0, ';' ) ][ eWeight ][ eItalic ] );
75}
76
77
79{
81
82 pVDev->EnableOutput( false );
83
84 for (auto const& elem : maObjects)
85 {
86 if( elem.HasRepresentation() )
87 {
88 const GDIMetaFile& rMtf = elem.GetRepresentation();
89
90 pVDev->Push();
91
92 for( size_t i = 0, nCount = rMtf.GetActionSize(); i < nCount; ++i )
93 {
94 OUString aText;
95 MetaAction* pAction = rMtf.GetAction( i );
96 const MetaActionType nType = pAction->GetType();
97
98 switch( nType )
99 {
100 case MetaActionType::TEXT:
101 {
102 const MetaTextAction* pA = static_cast<const MetaTextAction*>(pAction);
103 sal_Int32 aLength=std::min( pA->GetText().getLength(), pA->GetLen() );
104 aText = pA->GetText().copy( pA->GetIndex(), aLength );
105 }
106 break;
107
108 case MetaActionType::TEXTRECT:
109 {
110 const MetaTextRectAction* pA = static_cast<const MetaTextRectAction*>(pAction);
111 aText = pA->GetText();
112 }
113 break;
114
115 case MetaActionType::TEXTARRAY:
116 {
117 const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pAction);
118 sal_Int32 aLength=std::min( pA->GetText().getLength(), pA->GetLen() );
119 aText = pA->GetText().copy( pA->GetIndex(), aLength );
120 }
121 break;
122
123 case MetaActionType::STRETCHTEXT:
124 {
125 const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction*>(pAction);
126 sal_Int32 aLength=std::min( pA->GetText().getLength(), pA->GetLen() );
127 aText = pA->GetText().copy( pA->GetIndex(), aLength );
128 }
129 break;
130
131 default:
132 pAction->Execute( pVDev );
133 break;
134 }
135
136 if( !aText.isEmpty() )
137 {
138 GlyphSet& rGlyphSet = implGetGlyphSet( pVDev->GetFont() );
139 css::uno::Reference< css::i18n::XBreakIterator > xBI(
141
142 if( xBI.is() )
143 {
144 const css::lang::Locale& rLocale = Application::GetSettings().GetLanguageTag().getLocale();
145 sal_Int32 nCurPos = 0, nLastPos = -1;
146
147 while( ( nCurPos < aText.getLength() ) && ( nCurPos > nLastPos ) )
148 {
149 sal_Int32 nCount2 = 1;
150
151 nLastPos = nCurPos;
152 nCurPos = xBI->nextCharacters( aText, nCurPos, rLocale,
153 css::i18n::CharacterIteratorMode::SKIPCELL,
154 nCount2, nCount2 );
155
156 rGlyphSet.insert( aText.copy( nLastPos, nCurPos - nLastPos ) );
157 }
158 }
159 else
160 {
161 const sal_Unicode* pStr = aText.getStr();
162
163 for( sal_uInt32 k = 0, nLen = aText.getLength(); k < nLen; ++k )
164 rGlyphSet.insert( OUString( pStr[ k ] ) );
165 }
166 }
167 }
168
169 pVDev->Pop();
170 }
171 }
172}
173
174
176{
177 if( !mrExport.IsEmbedFonts() )
178 return;
179
180 GlyphSet& rGlyphSet = implGetGlyphSet( rFont );
181
182 if( rGlyphSet.empty() )
183 return;
184
185 {
186 SvXMLElementExport aExp( mrExport, XML_NAMESPACE_NONE, "defs", true, true );
187 OUString aCurIdStr( "EmbeddedFont_" );
188 OUString aUnitsPerEM( OUString::number( nFontEM ) );
190 vcl::Font aFont( rFont );
191
192 aFont.SetFontSize( Size( 0, nFontEM ) );
194
195 pVDev->SetMapMode(MapMode(MapUnit::Map100thMM));
196 pVDev->SetFont( aFont );
197
198 aCurIdStr += OUString::number( ++mnCurFontId );
199 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", aCurIdStr );
200 mrExport.AddAttribute( XML_NAMESPACE_NONE, "horiz-adv-x", aUnitsPerEM );
201
202 {
203 SvXMLElementExport aExp2( mrExport, XML_NAMESPACE_NONE, "font", true, true );
204 OUString aFontWeight;
205 OUString aFontStyle;
206 const Size aSize( nFontEM, nFontEM );
207
208 // Font Weight
209 if( aFont.GetWeight() != WEIGHT_NORMAL )
210 aFontWeight = "bold";
211 else
212 aFontWeight = "normal";
213
214 // Font Italic
215 if( aFont.GetItalic() != ITALIC_NONE )
216 aFontStyle = "italic";
217 else
218 aFontStyle = "normal";
219
221 mrExport.AddAttribute( XML_NAMESPACE_NONE, "units-per-em", aUnitsPerEM );
222 mrExport.AddAttribute( XML_NAMESPACE_NONE, "font-weight", aFontWeight );
223 mrExport.AddAttribute( XML_NAMESPACE_NONE, "font-style", aFontStyle );
224 mrExport.AddAttribute( XML_NAMESPACE_NONE, "ascent", OUString::number( pVDev->GetFontMetric().GetAscent() ) );
225 mrExport.AddAttribute( XML_NAMESPACE_NONE, "descent", OUString::number( pVDev->GetFontMetric().GetDescent() ) );
226
227 {
228 SvXMLElementExport aExp3( mrExport, XML_NAMESPACE_NONE, "font-face", true, true );
229 }
230
231 mrExport.AddAttribute( XML_NAMESPACE_NONE, "horiz-adv-x", OUString::number( aSize.Width() ) );
232
233 {
234 const Point aPos;
235 const tools::PolyPolygon aMissingGlyphPolyPoly( tools::Rectangle( aPos, aSize ) );
236
237 mrExport.AddAttribute( XML_NAMESPACE_NONE, "d", SVGActionWriter::GetPathString( aMissingGlyphPolyPoly, false ) );
238
239 {
240 SvXMLElementExport aExp4( mrExport, XML_NAMESPACE_NONE, "missing-glyph", true, true );
241 }
242 }
243 for (auto const& glyph : rGlyphSet)
244 {
245 implEmbedGlyph( *pVDev, glyph);
246 }
247 }
248 }
249}
250
251
252void SVGFontExport::implEmbedGlyph( OutputDevice const & rOut, const OUString& rCellStr )
253{
254 tools::PolyPolygon aPolyPoly;
255 const sal_Unicode nSpace = ' ';
256
257 if( !rOut.GetTextOutline( aPolyPoly, rCellStr ) )
258 return;
259
260 tools::Rectangle aBoundRect;
261
262 aPolyPoly.Scale( 1.0, -1.0 );
263
264 if( !rOut.GetTextBoundRect( aBoundRect, rCellStr ) )
265 aBoundRect = tools::Rectangle( Point( 0, 0 ), Size( rOut.GetTextWidth( rCellStr ), 0 ) );
266
267 mrExport.AddAttribute( XML_NAMESPACE_NONE, "unicode", rCellStr );
268
269 if( rCellStr[ 0 ] == nSpace && rCellStr.getLength() == 1 )
270 aBoundRect = tools::Rectangle( Point( 0, 0 ), Size( rOut.GetTextWidth( OUString(' ') ), 0 ) );
271
272 mrExport.AddAttribute( XML_NAMESPACE_NONE, "horiz-adv-x", OUString::number( aBoundRect.GetWidth() ) );
273
274 const OUString aPathString( SVGActionWriter::GetPathString( aPolyPoly, false ) );
275 if( !aPathString.isEmpty() )
276 {
277 mrExport.AddAttribute( XML_NAMESPACE_NONE, "d", aPathString );
278 }
279
280 {
281 SvXMLElementExport aExp( mrExport, XML_NAMESPACE_NONE, "glyph", true, true );
282 }
283}
284
285
287{
289
290 for (auto const& glyph : maGlyphTree)
291 {
292 const FontWeightMap& rFontWeightMap = glyph.second;
293 for (auto const& fontWeight : rFontWeightMap)
294 {
295 const FontItalicMap& rFontItalicMap = fontWeight.second;
296 for (auto const& fontItalic : rFontItalicMap)
297 {
298 vcl::Font aFont;
299
300 aFont.SetFamilyName( glyph.first );
301 aFont.SetWeight( fontWeight.first );
302 aFont.SetItalic( fontItalic.first );
303
304 implEmbedFont( aFont );
305 }
306 }
307 }
308}
309
310
311OUString SVGFontExport::GetMappedFontName( std::u16string_view rFontName ) const
312{
313 OUString aRet( o3tl::getToken(rFontName, 0, ';' ) );
314
315 if( mnCurFontId )
316 aRet += " embedded";
317
318 return aRet;
319}
320
321/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const LanguageTag & GetLanguageTag() const
static const AllSettings & GetSettings()
size_t GetActionSize() const
MetaAction * GetAction(size_t nAction) const
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
MetaActionType GetType() const
virtual void Execute(OutputDevice *pOut)
sal_Int32 GetLen() const
sal_Int32 GetIndex() const
const OUString & GetText() const
sal_Int32 GetLen() const
const OUString & GetText() const
sal_Int32 GetIndex() const
sal_Int32 GetIndex() const
sal_Int32 GetLen() const
const OUString & GetText() const
const OUString & GetText() const
bool GetTextOutline(tools::PolyPolygon &, const OUString &rStr) const
bool GetTextBoundRect(tools::Rectangle &rRect, const OUString &rStr, sal_Int32 nBase=0, sal_Int32 nIndex=0, sal_Int32 nLen=-1, sal_uLong nLayoutWidth=0, KernArraySpan aDXArray=KernArraySpan(), o3tl::span< const sal_Bool > pKashidaArray={}, const SalLayoutGlyphs *pGlyphs=nullptr) const
tools::Long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::text::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
static OUString GetPathString(const tools::PolyPolygon &rPolyPoly, bool bLine)
Definition: svgwriter.cxx:1894
bool IsEmbedFonts() const
Definition: svgfilter.hxx:81
::std::map< FontItalic, GlyphSet > FontItalicMap
SVGFontExport(SVGExport &rExport, ::std::vector< ObjectRepresentation > &&rObjects)
GlyphSet & implGetGlyphSet(const vcl::Font &rFont)
SVGExport & mrExport
sal_Int32 mnCurFontId
::std::set< OUString, ::std::greater< OUString > > GlyphSet
ObjectVector maObjects
GlyphTree maGlyphTree
::std::map< FontWeight, FontItalicMap > FontWeightMap
OUString GetMappedFontName(std::u16string_view rFontName) const
void implEmbedGlyph(OutputDevice const &rOut, const OUString &rCellStr)
void implCollectGlyphs()
void implEmbedFont(const vcl::Font &rFont)
constexpr tools::Long Width() const
void AddAttribute(sal_uInt16 nPrefix, const OUString &rName, const OUString &rValue)
void Scale(double fScaleX, double fScaleY)
constexpr tools::Long GetWidth() const
void SetFontSize(const Size &)
FontItalic GetItalic()
void SetItalic(FontItalic)
void SetWeight(FontWeight)
const OUString & GetFamilyName() const
void SetAlignment(TextAlign)
FontWeight GetWeight()
void SetFamilyName(const OUString &rFamilyName)
int nCount
FontItalic
ITALIC_NORMAL
ITALIC_NONE
ALIGN_BASELINE
WEIGHT_ULTRABOLD
WEIGHT_BOLD
WEIGHT_NORMAL
WEIGHT_BLACK
MetaActionType
int i
Definition: gentoken.py:48
const sal_uInt16 XML_NAMESPACE_NONE
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
FontWeight
VCL_DLLPUBLIC css::uno::Reference< css::i18n::XBreakIterator > CreateBreakIterator()
QPRO_FUNC_TYPE nType
const sal_Int32 nFontEM
sal_uInt16 sal_Unicode