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"
26 #include <vcl/unohelp.hxx>
27 #include <vcl/font.hxx>
28 #include <vcl/outdev.hxx>
30 static const sal_Int32 nFontEM
= 2048;
36 SVGFontExport::SVGFontExport( SVGExport
& rExport
, const ::std::vector
< ObjectRepresentation
>& rObjects
) :
38 maObjects( rObjects
),
43 // -----------------------------------------------------------------------------
45 SVGFontExport::~SVGFontExport()
49 // -----------------------------------------------------------------------------
51 SVGFontExport::GlyphSet
& SVGFontExport::implGetGlyphSet( const Font
& rFont
)
53 FontWeight
eWeight( WEIGHT_NORMAL
);
54 FontItalic
eItalic( ITALIC_NONE
);
55 OUString
aFontName( rFont
.GetName() );
56 sal_Int32
nNextTokenPos( 0 );
58 switch( rFont
.GetWeight() )
61 case WEIGHT_ULTRABOLD
:
63 eWeight
= WEIGHT_BOLD
;
70 if( rFont
.GetItalic() != ITALIC_NONE
)
71 eItalic
= ITALIC_NORMAL
;
73 return( maGlyphTree
[ aFontName
.getToken( 0, ';', nNextTokenPos
) ][ eWeight
][ eItalic
] );
76 // -----------------------------------------------------------------------------
78 void SVGFontExport::implCollectGlyphs()
81 ObjectVector::const_iterator
aIter( maObjects
.begin() );
83 aVDev
.EnableOutput( sal_False
);
85 while( aIter
!= maObjects
.end() )
87 if( (*aIter
).HasRepresentation() )
89 const GDIMetaFile
& rMtf
= (*aIter
).GetRepresentation();
93 for( size_t i
= 0, nCount
= rMtf
.GetActionSize(); i
< nCount
; ++i
)
96 MetaAction
* pAction
= rMtf
.GetAction( i
);
97 const sal_uInt16 nType
= pAction
->GetType();
101 case( META_TEXT_ACTION
):
103 const MetaTextAction
* pA
= (const MetaTextAction
*) pAction
;
104 aText
= String( pA
->GetText(), pA
->GetIndex(), pA
->GetLen() );
108 case( META_TEXTRECT_ACTION
):
110 const MetaTextRectAction
* pA
= (const MetaTextRectAction
*) pAction
;
111 aText
= pA
->GetText();
115 case( META_TEXTARRAY_ACTION
):
117 const MetaTextArrayAction
* pA
= (const MetaTextArrayAction
*) pAction
;
118 aText
= String( pA
->GetText(), pA
->GetIndex(), pA
->GetLen() );
122 case( META_STRETCHTEXT_ACTION
):
124 const MetaStretchTextAction
* pA
= (const MetaStretchTextAction
*) pAction
;
125 aText
= String( pA
->GetText(), pA
->GetIndex(), pA
->GetLen() );
130 pAction
->Execute( &aVDev
);
134 if( !aText
.isEmpty() )
136 GlyphSet
& rGlyphSet
= implGetGlyphSet( aVDev
.GetFont() );
137 ::com::sun::star::uno::Reference
< ::com::sun::star::i18n::XBreakIterator
> xBI(
138 ::vcl::unohelper::CreateBreakIterator() );
142 const ::com::sun::star::lang::Locale
& rLocale
= Application::GetSettings().GetLanguageTag().getLocale();
143 sal_Int32 nCurPos
= 0, nLastPos
= -1;
145 while( ( nCurPos
< aText
.getLength() ) && ( nCurPos
> nLastPos
) )
147 sal_Int32 nCount2
= 1;
150 nCurPos
= xBI
->nextCharacters( aText
, nCurPos
, rLocale
,
151 ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL
,
154 rGlyphSet
.insert( aText
.copy( nLastPos
, nCurPos
- nLastPos
) );
159 const sal_Unicode
* pStr
= aText
.getStr();
161 for( sal_uInt32 k
= 0, nLen
= aText
.getLength(); k
< nLen
; ++k
)
162 rGlyphSet
.insert( OUString( pStr
[ k
] ) );
174 // -----------------------------------------------------------------------------
176 void SVGFontExport::implEmbedFont( const Font
& rFont
)
178 if( mrExport
.IsEmbedFonts() )
180 GlyphSet
& rGlyphSet
= implGetGlyphSet( rFont
);
182 if( !rGlyphSet
.empty() )
184 GlyphSet::const_iterator
aIter( rGlyphSet
.begin() );
185 const OUString
aEmbeddedFontStr( "EmbeddedFont_" );
188 SvXMLElementExport
aExp( mrExport
, XML_NAMESPACE_NONE
, "defs", sal_True
, sal_True
);
189 OUString
aCurIdStr( aEmbeddedFontStr
);
190 OUString
aUnitsPerEM( OUString::valueOf( nFontEM
) );
194 aFont
.SetSize( Size( 0, nFontEM
) );
195 aFont
.SetAlign( ALIGN_BASELINE
);
197 aVDev
.SetMapMode( MAP_100TH_MM
);
198 aVDev
.SetFont( aFont
);
200 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "id", aCurIdStr
+= OUString::valueOf( ++mnCurFontId
) );
201 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "horiz-adv-x", aUnitsPerEM
);
204 SvXMLElementExport
aExp2( mrExport
, XML_NAMESPACE_NONE
, "font", sal_True
, sal_True
);
205 OUString aFontWeight
;
207 const Size
aSize( nFontEM
, nFontEM
);
210 if( aFont
.GetWeight() != WEIGHT_NORMAL
)
211 aFontWeight
= "bold";
213 aFontWeight
= "normal";
216 if( aFont
.GetItalic() != ITALIC_NONE
)
217 aFontStyle
= "italic";
219 aFontStyle
= "normal";
221 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "font-family", GetMappedFontName( rFont
.GetName() ) );
222 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "units-per-em", aUnitsPerEM
);
223 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "font-weight", aFontWeight
);
224 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "font-style", aFontStyle
);
225 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "ascent", OUString::valueOf( aVDev
.GetFontMetric().GetAscent() ) );
226 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "descent", OUString::valueOf( aVDev
.GetFontMetric().GetDescent() ) );
229 SvXMLElementExport
aExp3( mrExport
, XML_NAMESPACE_NONE
, "font-face", sal_True
, sal_True
);
232 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "horiz-adv-x", OUString::valueOf( aSize
.Width() ) );
236 const PolyPolygon
aMissingGlyphPolyPoly( Rectangle( aPos
, aSize
) );
238 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "d", SVGActionWriter::GetPathString( aMissingGlyphPolyPoly
, sal_False
) );
241 SvXMLElementExport
aExp4( mrExport
, XML_NAMESPACE_NONE
, "missing-glyph", sal_True
, sal_True
);
245 while( aIter
!= rGlyphSet
.end() )
247 implEmbedGlyph( aVDev
, *aIter
);
256 // -----------------------------------------------------------------------------
258 void SVGFontExport::implEmbedGlyph( OutputDevice
& rOut
, const OUString
& rCellStr
)
260 PolyPolygon aPolyPoly
;
261 const sal_Unicode nSpace
= ' ';
263 if( rOut
.GetTextOutline( aPolyPoly
, rCellStr
) )
265 Rectangle aBoundRect
;
267 aPolyPoly
.Scale( 1.0, -1.0 );
269 if( !rOut
.GetTextBoundRect( aBoundRect
, rCellStr
) )
270 aBoundRect
= Rectangle( Point( 0, 0 ), Size( rOut
.GetTextWidth( rCellStr
), 0 ) );
272 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "unicode", rCellStr
);
274 if( rCellStr
[ 0 ] == nSpace
&& rCellStr
.getLength() == 1 )
275 aBoundRect
= Rectangle( Point( 0, 0 ), Size( rOut
.GetTextWidth( OUString(' ') ), 0 ) );
277 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "horiz-adv-x", OUString::valueOf( aBoundRect
.GetWidth() ) );
279 const OUString
aPathString( SVGActionWriter::GetPathString( aPolyPoly
, sal_False
) );
280 if( !aPathString
.isEmpty() )
282 mrExport
.AddAttribute( XML_NAMESPACE_NONE
, "d", aPathString
);
286 SvXMLElementExport
aExp( mrExport
, XML_NAMESPACE_NONE
, "glyph", sal_True
, sal_True
);
291 // -----------------------------------------------------------------------------
293 void SVGFontExport::EmbedFonts()
297 GlyphTree::const_iterator
aGlyphTreeIter( maGlyphTree
.begin() );
299 while( aGlyphTreeIter
!= maGlyphTree
.end() )
301 const FontWeightMap
& rFontWeightMap
= (*aGlyphTreeIter
).second
;
302 FontWeightMap::const_iterator
aFontWeightIter( rFontWeightMap
.begin() );
304 while( aFontWeightIter
!= rFontWeightMap
.end() )
306 const FontItalicMap
& rFontItalicMap
= (*aFontWeightIter
).second
;
307 FontItalicMap::const_iterator
aFontItalicIter( rFontItalicMap
.begin() );
309 while( aFontItalicIter
!= rFontItalicMap
.end() )
313 aFont
.SetName( (*aGlyphTreeIter
).first
);
314 aFont
.SetWeight( (*aFontWeightIter
).first
);
315 aFont
.SetItalic( (*aFontItalicIter
).first
);
317 implEmbedFont( aFont
);
329 // -----------------------------------------------------------------------------
331 OUString
SVGFontExport::GetMappedFontName( const OUString
& rFontName
) const
333 sal_Int32
nNextTokenPos( 0 );
334 OUString
aRet( rFontName
.getToken( 0, ';', nNextTokenPos
) );
342 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */