xref: /AOO41X/main/filter/source/svg/svgfontexport.cxx (revision 9e0fc027f109ec4ffcb6033aeec742a099701108)
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