1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
30 static const sal_Int32 nFontEM
= 2048;
33 SVGFontExport::SVGFontExport( SVGExport
& rExport
, const ::std::vector
< ObjectRepresentation
>& rObjects
) :
35 maObjects( rObjects
),
41 SVGFontExport::~SVGFontExport()
46 SVGFontExport::GlyphSet
& SVGFontExport::implGetGlyphSet( const vcl::Font
& rFont
)
48 FontWeight
eWeight( WEIGHT_NORMAL
);
49 FontItalic
eItalic( ITALIC_NONE
);
50 const OUString
& aFontName( rFont
.GetFamilyName() );
51 sal_Int32
nNextTokenPos( 0 );
53 switch( rFont
.GetWeight() )
56 case WEIGHT_ULTRABOLD
:
58 eWeight
= WEIGHT_BOLD
;
65 if( rFont
.GetItalic() != ITALIC_NONE
)
66 eItalic
= ITALIC_NORMAL
;
68 return( maGlyphTree
[ aFontName
.getToken( 0, ';', nNextTokenPos
) ][ eWeight
][ eItalic
] );
72 void SVGFontExport::implCollectGlyphs()
74 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
75 ObjectVector::const_iterator
aIter( maObjects
.begin() );
77 pVDev
->EnableOutput( false );
79 while( aIter
!= maObjects
.end() )
81 if( (*aIter
).HasRepresentation() )
83 const GDIMetaFile
& rMtf
= (*aIter
).GetRepresentation();
87 for( size_t i
= 0, nCount
= rMtf
.GetActionSize(); i
< nCount
; ++i
)
90 MetaAction
* pAction
= rMtf
.GetAction( i
);
91 const MetaActionType nType
= pAction
->GetType();
95 case( MetaActionType::TEXT
):
97 const MetaTextAction
* pA
= static_cast<const MetaTextAction
*>(pAction
);
98 sal_Int32 aLength
=std::min( pA
->GetText().getLength(), pA
->GetLen() );
99 aText
= pA
->GetText().copy( pA
->GetIndex(), aLength
);
103 case( MetaActionType::TEXTRECT
):
105 const MetaTextRectAction
* pA
= static_cast<const MetaTextRectAction
*>(pAction
);
106 aText
= pA
->GetText();
110 case( MetaActionType::TEXTARRAY
):
112 const MetaTextArrayAction
* pA
= static_cast<const MetaTextArrayAction
*>(pAction
);
113 sal_Int32 aLength
=std::min( pA
->GetText().getLength(), pA
->GetLen() );
114 aText
= pA
->GetText().copy( pA
->GetIndex(), aLength
);
118 case( MetaActionType::STRETCHTEXT
):
120 const MetaStretchTextAction
* pA
= static_cast<const MetaStretchTextAction
*>(pAction
);
121 sal_Int32 aLength
=std::min( pA
->GetText().getLength(), pA
->GetLen() );
122 aText
= pA
->GetText().copy( pA
->GetIndex(), aLength
);
127 pAction
->Execute( pVDev
);
131 if( !aText
.isEmpty() )
133 GlyphSet
& rGlyphSet
= implGetGlyphSet( pVDev
->GetFont() );
134 css::uno::Reference
< css::i18n::XBreakIterator
> xBI(
135 vcl::unohelper::CreateBreakIterator() );
139 const css::lang::Locale
& rLocale
= Application::GetSettings().GetLanguageTag().getLocale();
140 sal_Int32 nCurPos
= 0, nLastPos
= -1;
142 while( ( nCurPos
< aText
.getLength() ) && ( nCurPos
> nLastPos
) )
144 sal_Int32 nCount2
= 1;
147 nCurPos
= xBI
->nextCharacters( aText
, nCurPos
, rLocale
,
148 css::i18n::CharacterIteratorMode::SKIPCELL
,
151 rGlyphSet
.insert( aText
.copy( nLastPos
, nCurPos
- nLastPos
) );
156 const sal_Unicode
* pStr
= aText
.getStr();
158 for( sal_uInt32 k
= 0, nLen
= aText
.getLength(); k
< nLen
; ++k
)
159 rGlyphSet
.insert( OUString( pStr
[ k
] ) );
172 void SVGFontExport::implEmbedFont( const vcl::Font
& rFont
)
174 if( mrExport
.IsEmbedFonts() )
176 GlyphSet
& rGlyphSet
= implGetGlyphSet( rFont
);
178 if( !rGlyphSet
.empty() )
180 GlyphSet::const_iterator
aIter( rGlyphSet
.begin() );
181 const OUString
aEmbeddedFontStr( "EmbeddedFont_" );
184 SvXMLElementExport
aExp( mrExport
, XML_NAMESPACE_NONE
, "defs", true, true );
185 OUString
aCurIdStr( aEmbeddedFontStr
);
186 OUString
aUnitsPerEM( OUString::number( nFontEM
) );
187 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
188 vcl::Font
aFont( rFont
);
190 aFont
.SetFontSize( Size( 0, nFontEM
) );
191 aFont
.SetAlignment( ALIGN_BASELINE
);
193 pVDev
->SetMapMode( MapUnit::Map100thMM
);
194 pVDev
->SetFont( aFont
);
196 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "id", aCurIdStr
+= OUString::number( ++mnCurFontId
) );
197 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "horiz-adv-x", aUnitsPerEM
);
200 SvXMLElementExport
aExp2( mrExport
, XML_NAMESPACE_NONE
, "font", true, true );
201 OUString aFontWeight
;
203 const Size
aSize( nFontEM
, nFontEM
);
206 if( aFont
.GetWeight() != WEIGHT_NORMAL
)
207 aFontWeight
= "bold";
209 aFontWeight
= "normal";
212 if( aFont
.GetItalic() != ITALIC_NONE
)
213 aFontStyle
= "italic";
215 aFontStyle
= "normal";
217 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "font-family", GetMappedFontName( rFont
.GetFamilyName() ) );
218 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "units-per-em", aUnitsPerEM
);
219 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "font-weight", aFontWeight
);
220 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "font-style", aFontStyle
);
221 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "ascent", OUString::number( pVDev
->GetFontMetric().GetAscent() ) );
222 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "descent", OUString::number( pVDev
->GetFontMetric().GetDescent() ) );
225 SvXMLElementExport
aExp3( mrExport
, XML_NAMESPACE_NONE
, "font-face", true, true );
228 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "horiz-adv-x", OUString::number( aSize
.Width() ) );
232 const tools::PolyPolygon
aMissingGlyphPolyPoly( Rectangle( aPos
, aSize
) );
234 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "d", SVGActionWriter::GetPathString( aMissingGlyphPolyPoly
, false ) );
237 SvXMLElementExport
aExp4( mrExport
, XML_NAMESPACE_NONE
, "missing-glyph", true, true );
241 while( aIter
!= rGlyphSet
.end() )
243 implEmbedGlyph( *pVDev
.get(), *aIter
);
253 void SVGFontExport::implEmbedGlyph( OutputDevice
& rOut
, const OUString
& rCellStr
)
255 tools::PolyPolygon aPolyPoly
;
256 const sal_Unicode nSpace
= ' ';
258 if( rOut
.GetTextOutline( aPolyPoly
, rCellStr
) )
260 Rectangle aBoundRect
;
262 aPolyPoly
.Scale( 1.0, -1.0 );
264 if( !rOut
.GetTextBoundRect( aBoundRect
, rCellStr
) )
265 aBoundRect
= Rectangle( Point( 0, 0 ), Size( rOut
.GetTextWidth( rCellStr
), 0 ) );
267 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "unicode", rCellStr
);
269 if( rCellStr
[ 0 ] == nSpace
&& rCellStr
.getLength() == 1 )
270 aBoundRect
= Rectangle( Point( 0, 0 ), Size( rOut
.GetTextWidth( OUString(' ') ), 0 ) );
272 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "horiz-adv-x", OUString::number( aBoundRect
.GetWidth() ) );
274 const OUString
aPathString( SVGActionWriter::GetPathString( aPolyPoly
, false ) );
275 if( !aPathString
.isEmpty() )
277 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "d", aPathString
);
281 SvXMLElementExport
aExp( mrExport
, XML_NAMESPACE_NONE
, "glyph", true, true );
287 void SVGFontExport::EmbedFonts()
291 GlyphTree::const_iterator
aGlyphTreeIter( maGlyphTree
.begin() );
293 while( aGlyphTreeIter
!= maGlyphTree
.end() )
295 const FontWeightMap
& rFontWeightMap
= (*aGlyphTreeIter
).second
;
296 FontWeightMap::const_iterator
aFontWeightIter( rFontWeightMap
.begin() );
298 while( aFontWeightIter
!= rFontWeightMap
.end() )
300 const FontItalicMap
& rFontItalicMap
= (*aFontWeightIter
).second
;
301 FontItalicMap::const_iterator
aFontItalicIter( rFontItalicMap
.begin() );
303 while( aFontItalicIter
!= rFontItalicMap
.end() )
307 aFont
.SetFamilyName( (*aGlyphTreeIter
).first
);
308 aFont
.SetWeight( (*aFontWeightIter
).first
);
309 aFont
.SetItalic( (*aFontItalicIter
).first
);
311 implEmbedFont( aFont
);
324 OUString
SVGFontExport::GetMappedFontName( const OUString
& rFontName
) const
326 sal_Int32
nNextTokenPos( 0 );
327 OUString
aRet( rFontName
.getToken( 0, ';', nNextTokenPos
) );
335 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */