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