1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26
27 #include "svgfontexport.hxx"
28 #include <vcl/unohelp.hxx>
29
30 static const sal_Int32 nFontEM = 2048;
31
32 // -----------------
33 // - SVGFontExport -
34 // -----------------
35
SVGFontExport(SVGExport & rExport,const::std::vector<ObjectRepresentation> & rObjects)36 SVGFontExport::SVGFontExport( SVGExport& rExport, const ::std::vector< ObjectRepresentation >& rObjects ) :
37 mrExport( rExport ),
38 maObjects( rObjects ),
39 mnCurFontId( 0 )
40 {
41 }
42
43 // -----------------------------------------------------------------------------
44
~SVGFontExport()45 SVGFontExport::~SVGFontExport()
46 {
47 }
48
49 // -----------------------------------------------------------------------------
50
implGetGlyphSet(const Font & rFont)51 SVGFontExport::GlyphSet& SVGFontExport::implGetGlyphSet( const Font& rFont )
52 {
53 FontWeight eWeight( WEIGHT_NORMAL );
54 FontItalic eItalic( ITALIC_NONE );
55 ::rtl::OUString aFontName( rFont.GetName() );
56 sal_Int32 nNextTokenPos( 0 );
57
58 switch( rFont.GetWeight() )
59 {
60 case WEIGHT_BOLD:
61 case WEIGHT_ULTRABOLD:
62 case WEIGHT_BLACK:
63 eWeight = WEIGHT_BOLD;
64 break;
65
66 default:
67 break;
68 }
69
70 if( rFont.GetItalic() != ITALIC_NONE )
71 eItalic = ITALIC_NORMAL;
72
73 return( maGlyphTree[ aFontName.getToken( 0, ';', nNextTokenPos ) ][ eWeight ][ eItalic ] );
74 }
75
76 // -----------------------------------------------------------------------------
77
implCollectGlyphs()78 void SVGFontExport::implCollectGlyphs()
79 {
80 VirtualDevice aVDev;
81 ObjectVector::const_iterator aIter( maObjects.begin() );
82
83 aVDev.EnableOutput( sal_False );
84
85 while( aIter != maObjects.end() )
86 {
87 if( (*aIter).HasRepresentation() )
88 {
89 const GDIMetaFile& rMtf = (*aIter).GetRepresentation();
90
91 aVDev.Push();
92
93 for( sal_uInt32 i = 0, nCount = rMtf.GetActionCount(); i < nCount; ++i )
94 {
95 ::rtl::OUString aText;
96 MetaAction* pAction = rMtf.GetAction( i );
97 const sal_uInt16 nType = pAction->GetType();
98
99 switch( nType )
100 {
101 case( META_TEXT_ACTION ):
102 {
103 const MetaTextAction* pA = (const MetaTextAction*) pAction;
104 aText = String( pA->GetText(), pA->GetIndex(), pA->GetLen() );
105 }
106 break;
107
108 case( META_TEXTRECT_ACTION ):
109 {
110 const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction;
111 aText = pA->GetText();
112 }
113 break;
114
115 case( META_TEXTARRAY_ACTION ):
116 {
117 const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pAction;
118 aText = String( pA->GetText(), pA->GetIndex(), pA->GetLen() );
119 }
120 break;
121
122 case( META_STRETCHTEXT_ACTION ):
123 {
124 const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction;
125 aText = String( pA->GetText(), pA->GetIndex(), pA->GetLen() );
126 }
127 break;
128
129 default:
130 pAction->Execute( &aVDev );
131 break;
132 }
133
134 if( aText.getLength() )
135 {
136 GlyphSet& rGlyphSet = implGetGlyphSet( aVDev.GetFont() );
137 ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xBI(
138 ::vcl::unohelper::CreateBreakIterator() );
139
140 if( xBI.is() )
141 {
142 const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetLocale();
143 sal_Int32 nCurPos = 0, nLastPos = -1;
144
145 while( ( nCurPos < aText.getLength() ) && ( nCurPos > nLastPos ) )
146 {
147 sal_Int32 nCount2 = 1;
148
149 nLastPos = nCurPos;
150 nCurPos = xBI->nextCharacters( aText, nCurPos, rLocale,
151 ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL,
152 nCount2, nCount2 );
153
154 rGlyphSet.insert( aText.copy( nLastPos, nCurPos - nLastPos ) );
155 }
156 }
157 else
158 {
159 const sal_Unicode* pStr = aText.getStr();
160
161 for( sal_uInt32 k = 0, nLen = aText.getLength(); k < nLen; ++k )
162 rGlyphSet.insert( rtl::OUString( pStr[ k ] ) );
163 }
164 }
165 }
166
167 aVDev.Pop();
168 }
169
170 ++aIter;
171 }
172 }
173
174 // -----------------------------------------------------------------------------
175
implEmbedFont(const Font & rFont)176 void SVGFontExport::implEmbedFont( const Font& rFont )
177 {
178 if( mrExport.IsEmbedFonts() )
179 {
180 GlyphSet& rGlyphSet = implGetGlyphSet( rFont );
181
182 if( !rGlyphSet.empty() )
183 {
184 GlyphSet::const_iterator aIter( rGlyphSet.begin() );
185 const ::rtl::OUString aEmbeddedFontStr( B2UCONST( "EmbeddedFont_" ) );
186
187 {
188 SvXMLElementExport aExp( mrExport, XML_NAMESPACE_NONE, "defs", sal_True, sal_True );
189 ::rtl::OUString aCurIdStr( aEmbeddedFontStr );
190 ::rtl::OUString aUnitsPerEM( ::rtl::OUString::valueOf( nFontEM ) );
191 VirtualDevice aVDev;
192 Font aFont( rFont );
193
194 aFont.SetSize( Size( 0, nFontEM ) );
195 aFont.SetAlign( ALIGN_BASELINE );
196
197 aVDev.SetMapMode( MAP_100TH_MM );
198 aVDev.SetFont( aFont );
199
200 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", aCurIdStr += ::rtl::OUString::valueOf( ++mnCurFontId ) );
201 mrExport.AddAttribute( XML_NAMESPACE_NONE, "horiz-adv-x", aUnitsPerEM );
202
203 {
204 SvXMLElementExport aExp2( mrExport, XML_NAMESPACE_NONE, "font", sal_True, sal_True );
205 ::rtl::OUString aFontWeight;
206 ::rtl::OUString aFontStyle;
207 const Size aSize( nFontEM, nFontEM );
208
209 // Font Weight
210 if( aFont.GetWeight() != WEIGHT_NORMAL )
211 aFontWeight = B2UCONST( "bold" );
212 else
213 aFontWeight = B2UCONST( "normal" );
214
215 // Font Italic
216 if( aFont.GetItalic() != ITALIC_NONE )
217 aFontStyle = B2UCONST( "italic" );
218 else
219 aFontStyle = B2UCONST( "normal" );
220
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", ::rtl::OUString::valueOf( aVDev.GetFontMetric().GetAscent() ) );
226 mrExport.AddAttribute( XML_NAMESPACE_NONE, "descent", ::rtl::OUString::valueOf( aVDev.GetFontMetric().GetDescent() ) );
227
228 {
229 SvXMLElementExport aExp3( mrExport, XML_NAMESPACE_NONE, "font-face", sal_True, sal_True );
230 }
231
232 mrExport.AddAttribute( XML_NAMESPACE_NONE, "horiz-adv-x", ::rtl::OUString::valueOf( aSize.Width() ) );
233
234 {
235 const Point aPos;
236 const PolyPolygon aMissingGlyphPolyPoly( Rectangle( aPos, aSize ) );
237
238 mrExport.AddAttribute( XML_NAMESPACE_NONE, "d", SVGActionWriter::GetPathString( aMissingGlyphPolyPoly, sal_False ) );
239
240 {
241 SvXMLElementExport aExp4( mrExport, XML_NAMESPACE_NONE, "missing-glyph", sal_True, sal_True );
242 }
243 }
244
245 while( aIter != rGlyphSet.end() )
246 {
247 implEmbedGlyph( aVDev, *aIter );
248 ++aIter;
249 }
250 }
251 }
252 }
253 }
254 }
255
256 // -----------------------------------------------------------------------------
257
implEmbedGlyph(OutputDevice & rOut,const::rtl::OUString & rCellStr)258 void SVGFontExport::implEmbedGlyph( OutputDevice& rOut, const ::rtl::OUString& rCellStr )
259 {
260 PolyPolygon aPolyPoly;
261 const sal_Unicode nSpace = ' ';
262
263 if( rOut.GetTextOutline( aPolyPoly, rCellStr ) )
264 {
265 Rectangle aBoundRect;
266
267 aPolyPoly.Scale( 1.0, -1.0 );
268
269 if( !rOut.GetTextBoundRect( aBoundRect, rCellStr ) )
270 aBoundRect = Rectangle( Point( 0, 0 ), Size( rOut.GetTextWidth( rCellStr ), 0 ) );
271
272 mrExport.AddAttribute( XML_NAMESPACE_NONE, "unicode", rCellStr );
273
274 if( rCellStr[ 0 ] == nSpace && rCellStr.getLength() == 1 )
275 aBoundRect = Rectangle( Point( 0, 0 ), Size( rOut.GetTextWidth( sal_Unicode( ' ' ) ), 0 ) );
276
277 mrExport.AddAttribute( XML_NAMESPACE_NONE, "horiz-adv-x", ::rtl::OUString::valueOf( aBoundRect.GetWidth() ) );
278
279 const ::rtl::OUString aPathString( SVGActionWriter::GetPathString( aPolyPoly, sal_False ) );
280
281 if( aPathString.getLength() )
282 {
283 mrExport.AddAttribute( XML_NAMESPACE_NONE, "d", aPathString );
284 }
285
286 {
287 SvXMLElementExport aExp( mrExport, XML_NAMESPACE_NONE, "glyph", sal_True, sal_True );
288 }
289 }
290 }
291
292 // -----------------------------------------------------------------------------
293
EmbedFonts()294 void SVGFontExport::EmbedFonts()
295 {
296 implCollectGlyphs();
297
298 GlyphTree::const_iterator aGlyphTreeIter( maGlyphTree.begin() );
299
300 while( aGlyphTreeIter != maGlyphTree.end() )
301 {
302 const FontWeightMap& rFontWeightMap = (*aGlyphTreeIter).second;
303 FontWeightMap::const_iterator aFontWeightIter( rFontWeightMap.begin() );
304
305 while( aFontWeightIter != rFontWeightMap.end() )
306 {
307 const FontItalicMap& rFontItalicMap = (*aFontWeightIter).second;
308 FontItalicMap::const_iterator aFontItalicIter( rFontItalicMap.begin() );
309
310 while( aFontItalicIter != rFontItalicMap.end() )
311 {
312 Font aFont;
313
314 aFont.SetName( (*aGlyphTreeIter).first );
315 aFont.SetWeight( (*aFontWeightIter).first );
316 aFont.SetItalic( (*aFontItalicIter).first );
317
318 implEmbedFont( aFont );
319
320 ++aFontItalicIter;
321 }
322
323 ++aFontWeightIter;
324 }
325
326 ++aGlyphTreeIter;
327 }
328 }
329
330 // -----------------------------------------------------------------------------
331
GetMappedFontName(const::rtl::OUString & rFontName) const332 ::rtl::OUString SVGFontExport::GetMappedFontName( const ::rtl::OUString& rFontName ) const
333 {
334 sal_Int32 nNextTokenPos( 0 );
335 ::rtl::OUString aRet( rFontName.getToken( 0, ';', nNextTokenPos ) );
336
337 if( mnCurFontId )
338 aRet += B2UCONST( " embedded" );
339
340 return aRet;
341 }
342