1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <xmloff/XMLFontStylesContext.hxx>
21 #include "XMLFontStylesContext_impl.hxx"
22 
23 #include <com/sun/star/awt/FontFamily.hpp>
24 #include <com/sun/star/awt/FontPitch.hpp>
25 #include <com/sun/star/embed/ElementModes.hpp>
26 #include <com/sun/star/embed/XStorage.hpp>
27 
28 #include <comphelper/seqstream.hxx>
29 
30 #include <sal/log.hxx>
31 #include <vcl/embeddedfontshelper.hxx>
32 
33 #include <xmloff/xmlnmspe.hxx>
34 #include <xmloff/xmltoken.hxx>
35 #include "fonthdl.hxx"
36 #include <xmloff/xmlimp.hxx>
37 #include <xmloff/maptype.hxx>
38 #include <xmloff/XMLBase64ImportContext.hxx>
39 
40 
41 using namespace ::com::sun::star;
42 using namespace ::com::sun::star::uno;
43 using namespace ::com::sun::star::xml::sax;
44 using namespace ::com::sun::star::container;
45 using namespace ::com::sun::star::beans;
46 using namespace ::com::sun::star::lang;
47 using namespace ::com::sun::star::awt;
48 using namespace ::xmloff::token;
49 
50 
51 #define XML_STYLE_FAMILY_FONT 1
52 
53 enum XMLFontStyleAttrTokens
54 {
55     XML_TOK_FONT_STYLE_ATTR_FAMILY,
56     XML_TOK_FONT_STYLE_ATTR_FAMILY_GENERIC,
57     XML_TOK_FONT_STYLE_ATTR_STYLENAME,
58     XML_TOK_FONT_STYLE_ATTR_PITCH,
59     XML_TOK_FONT_STYLE_ATTR_CHARSET,
60 };
61 
lcl_getFontStyleAttrTokenMap()62 static const SvXMLTokenMapEntry* lcl_getFontStyleAttrTokenMap()
63 {
64     static const SvXMLTokenMapEntry aFontStyleAttrTokenMap[] =
65     {
66         { XML_NAMESPACE_SVG, XML_FONT_FAMILY,
67                 XML_TOK_FONT_STYLE_ATTR_FAMILY },
68         { XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC,
69                 XML_TOK_FONT_STYLE_ATTR_FAMILY_GENERIC },
70         { XML_NAMESPACE_STYLE, XML_FONT_ADORNMENTS,
71                 XML_TOK_FONT_STYLE_ATTR_STYLENAME },
72         { XML_NAMESPACE_STYLE, XML_FONT_PITCH,
73                 XML_TOK_FONT_STYLE_ATTR_PITCH },
74         { XML_NAMESPACE_STYLE, XML_FONT_CHARSET,
75                 XML_TOK_FONT_STYLE_ATTR_CHARSET },
76 
77         XML_TOKEN_MAP_END
78     };
79     return aFontStyleAttrTokenMap;
80 }
81 
82 
XMLFontStyleContextFontFace(SvXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName,const Reference<XAttributeList> & xAttrList,XMLFontStylesContext & rStyles)83 XMLFontStyleContextFontFace::XMLFontStyleContextFontFace( SvXMLImport& rImport,
84         sal_uInt16 nPrfx, const OUString& rLName,
85         const Reference< XAttributeList > & xAttrList,
86         XMLFontStylesContext& rStyles ) :
87     SvXMLStyleContext( rImport, nPrfx, rLName, xAttrList, XML_STYLE_FAMILY_FONT ),
88     xStyles( &rStyles )
89 {
90     aFamilyName <<= OUString();
91     aStyleName <<= OUString();
92     aFamily <<= sal_Int16(awt::FontFamily::DONTKNOW);
93     aPitch <<= sal_Int16(awt::FontPitch::DONTKNOW);
94     aEnc <<= static_cast<sal_Int16>(rStyles.GetDfltCharset());
95 }
96 
SetAttribute(sal_uInt16 nPrefixKey,const OUString & rLocalName,const OUString & rValue)97 void XMLFontStyleContextFontFace::SetAttribute( sal_uInt16 nPrefixKey,
98                                         const OUString& rLocalName,
99                                         const OUString& rValue )
100 {
101     SvXMLUnitConverter& rUnitConv = GetImport().GetMM100UnitConverter();
102     const SvXMLTokenMap& rTokenMap = GetStyles()->GetFontStyleAttrTokenMap();
103     Any aAny;
104 
105     switch( rTokenMap.Get( nPrefixKey, rLocalName ) )
106     {
107     case XML_TOK_FONT_STYLE_ATTR_FAMILY:
108         if( GetStyles()->GetFamilyNameHdl().importXML( rValue, aAny,
109                                                           rUnitConv ) )
110             aFamilyName = aAny;
111         break;
112     case XML_TOK_FONT_STYLE_ATTR_STYLENAME:
113         aStyleName <<= rValue;
114         break;
115     case XML_TOK_FONT_STYLE_ATTR_FAMILY_GENERIC:
116         if( GetStyles()->GetFamilyHdl().importXML( rValue, aAny,
117                                                       rUnitConv ) )
118             aFamily = aAny;
119         break;
120     case XML_TOK_FONT_STYLE_ATTR_PITCH:
121         if( GetStyles()->GetPitchHdl().importXML( rValue, aAny,
122                                                       rUnitConv ) )
123             aPitch = aAny;
124         break;
125     case XML_TOK_FONT_STYLE_ATTR_CHARSET:
126         if( GetStyles()->GetEncodingHdl().importXML( rValue, aAny,
127                                                       rUnitConv ) )
128             aEnc = aAny;
129         break;
130     default:
131         SvXMLStyleContext::SetAttribute( nPrefixKey, rLocalName, rValue );
132         break;
133     }
134 }
135 
~XMLFontStyleContextFontFace()136 XMLFontStyleContextFontFace::~XMLFontStyleContextFontFace()
137 {
138 }
139 
FillProperties(::std::vector<XMLPropertyState> & rProps,sal_Int32 nFamilyNameIdx,sal_Int32 nStyleNameIdx,sal_Int32 nFamilyIdx,sal_Int32 nPitchIdx,sal_Int32 nCharsetIdx) const140 void XMLFontStyleContextFontFace::FillProperties(
141         ::std::vector< XMLPropertyState > &rProps,
142         sal_Int32 nFamilyNameIdx,
143         sal_Int32 nStyleNameIdx,
144         sal_Int32 nFamilyIdx,
145         sal_Int32 nPitchIdx,
146         sal_Int32 nCharsetIdx ) const
147 {
148     if( nFamilyNameIdx != -1 )
149     {
150         XMLPropertyState aPropState( nFamilyNameIdx, aFamilyName );
151         rProps.push_back( aPropState );
152     }
153     if( nStyleNameIdx != -1 )
154     {
155         XMLPropertyState aPropState( nStyleNameIdx, aStyleName );
156         rProps.push_back( aPropState );
157     }
158     if( nFamilyIdx != -1 )
159     {
160         XMLPropertyState aPropState( nFamilyIdx, aFamily );
161         rProps.push_back( aPropState );
162     }
163     if( nPitchIdx != -1 )
164     {
165         XMLPropertyState aPropState( nPitchIdx, aPitch );
166         rProps.push_back( aPropState );
167     }
168     if( nCharsetIdx != -1 )
169     {
170         XMLPropertyState aPropState( nCharsetIdx, aEnc );
171         rProps.push_back( aPropState );
172     }
173 }
174 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const css::uno::Reference<css::xml::sax::XAttributeList> & xAttrList)175 SvXMLImportContextRef XMLFontStyleContextFontFace::CreateChildContext(
176         sal_uInt16 nPrefix,
177         const OUString& rLocalName,
178         const css::uno::Reference< css::xml::sax::XAttributeList > & xAttrList )
179 {
180     if( nPrefix == XML_NAMESPACE_SVG && IsXMLToken( rLocalName, XML_FONT_FACE_SRC ))
181         return new XMLFontStyleContextFontFaceSrc( GetImport(), nPrefix, rLocalName, *this );
182     return SvXMLStyleContext::CreateChildContext( nPrefix, rLocalName, xAttrList );
183 }
184 
familyName() const185 OUString XMLFontStyleContextFontFace::familyName() const
186 {
187     OUString ret;
188     aFamilyName >>= ret;
189     return ret;
190 }
191 
192 
XMLFontStyleContextFontFaceFormat(SvXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName,const css::uno::Reference<css::xml::sax::XAttributeList> & xAttrList,XMLFontStyleContextFontFaceUri & _uri)193 XMLFontStyleContextFontFaceFormat::XMLFontStyleContextFontFaceFormat( SvXMLImport& rImport,
194         sal_uInt16 nPrfx, const OUString& rLName,
195         const css::uno::Reference< css::xml::sax::XAttributeList > &xAttrList,
196         XMLFontStyleContextFontFaceUri& _uri )
197     : SvXMLStyleContext( rImport, nPrfx, rLName, xAttrList)
198     , uri(_uri)
199 {
200 }
201 
SetAttribute(sal_uInt16 nPrefixKey,const OUString & rLocalName,const OUString & rValue)202 void XMLFontStyleContextFontFaceFormat::SetAttribute( sal_uInt16 nPrefixKey, const OUString& rLocalName,
203     const OUString& rValue )
204 {
205     if( nPrefixKey == XML_NAMESPACE_SVG && IsXMLToken( rLocalName, XML_STRING ))
206         uri.SetFormat(rValue);
207     else
208         SvXMLStyleContext::SetAttribute( nPrefixKey, rLocalName, rValue );
209 }
210 
211 
XMLFontStyleContextFontFaceSrc(SvXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName,const XMLFontStyleContextFontFace & _font)212 XMLFontStyleContextFontFaceSrc::XMLFontStyleContextFontFaceSrc( SvXMLImport& rImport,
213         sal_uInt16 nPrfx, const OUString& rLName,
214         const XMLFontStyleContextFontFace& _font )
215     : SvXMLImportContext( rImport, nPrfx, rLName )
216     , font( _font )
217 {
218 }
219 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const css::uno::Reference<css::xml::sax::XAttributeList> & xAttrList)220 SvXMLImportContextRef XMLFontStyleContextFontFaceSrc::CreateChildContext(
221         sal_uInt16 nPrefix,
222         const OUString& rLocalName,
223         const css::uno::Reference< css::xml::sax::XAttributeList > & xAttrList )
224 {
225     if( nPrefix == XML_NAMESPACE_SVG && IsXMLToken( rLocalName, XML_FONT_FACE_URI ))
226         return new XMLFontStyleContextFontFaceUri( GetImport(), nPrefix, rLocalName, xAttrList, font );
227     return SvXMLImportContext::CreateChildContext( nPrefix, rLocalName, xAttrList );
228 }
229 
230 
XMLFontStyleContextFontFaceUri(SvXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName,const css::uno::Reference<css::xml::sax::XAttributeList> & xAttrList,const XMLFontStyleContextFontFace & _font)231 XMLFontStyleContextFontFaceUri::XMLFontStyleContextFontFaceUri( SvXMLImport& rImport,
232         sal_uInt16 nPrfx, const OUString& rLName,
233         const css::uno::Reference< css::xml::sax::XAttributeList > & xAttrList,
234         const XMLFontStyleContextFontFace& _font )
235     : SvXMLStyleContext( rImport, nPrfx, rLName, xAttrList )
236     , font( _font )
237 {
238 }
239 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const css::uno::Reference<css::xml::sax::XAttributeList> & xAttrList)240 SvXMLImportContextRef XMLFontStyleContextFontFaceUri::CreateChildContext(
241         sal_uInt16 nPrefix,
242         const OUString& rLocalName,
243         const css::uno::Reference< css::xml::sax::XAttributeList > & xAttrList )
244 {
245     if( nPrefix == XML_NAMESPACE_SVG && IsXMLToken( rLocalName, XML_FONT_FACE_FORMAT ))
246         return new XMLFontStyleContextFontFaceFormat( GetImport(), nPrefix, rLocalName, xAttrList, *this );
247     if( linkPath.isEmpty() && ( nPrefix == XML_NAMESPACE_OFFICE ) && IsXMLToken( rLocalName, XML_BINARY_DATA ) )
248     {
249         mxBase64Stream.set( new comphelper::OSequenceOutputStream( maFontData ) );
250         if( mxBase64Stream.is() )
251             return new XMLBase64ImportContext( GetImport(), nPrefix, rLocalName, xAttrList, mxBase64Stream );
252     }
253     return SvXMLImportContext::CreateChildContext( nPrefix, rLocalName, xAttrList );
254 }
255 
SetAttribute(sal_uInt16 nPrefixKey,const OUString & rLocalName,const OUString & rValue)256 void XMLFontStyleContextFontFaceUri::SetAttribute( sal_uInt16 nPrefixKey, const OUString& rLocalName,
257     const OUString& rValue )
258 {
259     if( nPrefixKey == XML_NAMESPACE_XLINK && IsXMLToken( rLocalName, XML_HREF ))
260         linkPath = rValue;
261     else
262         SvXMLStyleContext::SetAttribute( nPrefixKey, rLocalName, rValue );
263 }
264 
SetFormat(const OUString & rFormat)265 void XMLFontStyleContextFontFaceUri::SetFormat( const OUString& rFormat )
266 {
267     format = rFormat;
268 }
269 
270 // the CSS2 standard ( http://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#referencing )
271 // defines these format strings.
272 const char OPENTYPE_FORMAT[] = "opentype";
273 const char TRUETYPE_FORMAT[] = "truetype";
274 const char EOT_FORMAT[]      = "embedded-opentype";
275 
EndElement()276 void XMLFontStyleContextFontFaceUri::EndElement()
277 {
278     if( ( linkPath.getLength() == 0 ) && ( !maFontData.hasElements() ) )
279     {
280         SAL_WARN( "xmloff", "svg:font-face-uri tag with no link or base64 data; ignoring." );
281         return;
282     }
283     bool eot;
284     // Assume by default that the font is not compressed.
285     if( format.getLength() == 0
286         || format == OPENTYPE_FORMAT
287         || format == TRUETYPE_FORMAT )
288     {
289         eot = false;
290     }
291     else if( format == EOT_FORMAT )
292     {
293         eot = true;
294     }
295     else
296     {
297         SAL_WARN( "xmloff", "Unknown format of embedded font; assuming TTF." );
298         eot = false;
299     }
300     if ( !maFontData.hasElements() )
301         handleEmbeddedFont( linkPath, eot );
302     else
303         handleEmbeddedFont( maFontData, eot );
304 }
305 
handleEmbeddedFont(const OUString & url,bool eot)306 void XMLFontStyleContextFontFaceUri::handleEmbeddedFont( const OUString& url, bool eot )
307 {
308     if( GetImport().embeddedFontAlreadyProcessed( url ))
309     {
310         GetImport().NotifyEmbeddedFontRead();
311         return;
312     }
313     OUString fontName = font.familyName();
314     // If there's any giveMeStreamForThisURL(), then it's well-hidden for me to find it.
315     if( GetImport().IsPackageURL( url ))
316     {
317         uno::Reference< embed::XStorage > storage;
318         storage.set( GetImport().GetSourceStorage(), UNO_SET_THROW );
319         if( url.indexOf( '/' ) > -1 ) // TODO what if more levels?
320             storage.set( storage->openStorageElement( url.copy( 0, url.indexOf( '/' )),
321                 ::embed::ElementModes::READ ), uno::UNO_SET_THROW );
322         uno::Reference< io::XInputStream > inputStream;
323         inputStream.set( storage->openStreamElement( url.copy( url.indexOf( '/' ) + 1 ), ::embed::ElementModes::READ ),
324             UNO_QUERY_THROW );
325         if( EmbeddedFontsHelper::addEmbeddedFont( inputStream, fontName, "?", std::vector< unsigned char >(), eot ))
326             GetImport().NotifyEmbeddedFontRead();
327         inputStream->closeInput();
328     }
329     else
330         SAL_WARN( "xmloff", "External URL for font file not handled." );
331 }
332 
handleEmbeddedFont(const::css::uno::Sequence<sal_Int8> & rData,const bool eot)333 void XMLFontStyleContextFontFaceUri::handleEmbeddedFont( const ::css::uno::Sequence< sal_Int8 >& rData, const bool eot )
334 {
335     const uno::Reference< io::XInputStream > xInput( new comphelper::SequenceInputStream( rData ) );
336     const OUString fontName = font.familyName();
337     if( EmbeddedFontsHelper::addEmbeddedFont( xInput, fontName, "?", std::vector< unsigned char >(), eot ) )
338         GetImport().NotifyEmbeddedFontRead();
339     xInput->closeInput();
340 }
341 
CreateStyleChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const css::uno::Reference<css::xml::sax::XAttributeList> & xAttrList)342 SvXMLStyleContext *XMLFontStylesContext::CreateStyleChildContext(
343         sal_uInt16 nPrefix,
344         const OUString& rLocalName,
345         const css::uno::Reference< css::xml::sax::XAttributeList > & xAttrList )
346 {
347     SvXMLStyleContext *pStyle;
348     if( XML_NAMESPACE_STYLE == nPrefix &&
349         IsXMLToken( rLocalName, XML_FONT_FACE ) )
350     {
351         pStyle = new XMLFontStyleContextFontFace( GetImport(), nPrefix,
352                                                rLocalName, xAttrList, *this );
353     }
354     else
355     {
356         pStyle = SvXMLStylesContext::CreateStyleChildContext( nPrefix,
357                                                rLocalName, xAttrList );
358     }
359 
360     return pStyle;
361 }
362 
363 
XMLFontStylesContext(SvXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName,const Reference<XAttributeList> & xAttrList,rtl_TextEncoding eDfltEnc)364 XMLFontStylesContext::XMLFontStylesContext( SvXMLImport& rImport,
365         sal_uInt16 nPrfx, const OUString& rLName,
366         const Reference< XAttributeList > & xAttrList,
367         rtl_TextEncoding eDfltEnc ) :
368     SvXMLStylesContext( rImport, nPrfx, rLName, xAttrList ),
369     pFamilyNameHdl( new XMLFontFamilyNamePropHdl ),
370     pFamilyHdl( new XMLFontFamilyPropHdl ),
371     pPitchHdl( new XMLFontPitchPropHdl ),
372     pEncHdl( new XMLFontEncodingPropHdl ),
373     pFontStyleAttrTokenMap( new SvXMLTokenMap(lcl_getFontStyleAttrTokenMap()) ),
374     eDfltEncoding( eDfltEnc )
375 {
376 }
377 
~XMLFontStylesContext()378 XMLFontStylesContext::~XMLFontStylesContext() {}
379 
FillProperties(const OUString & rName,::std::vector<XMLPropertyState> & rProps,sal_Int32 nFamilyNameIdx,sal_Int32 nStyleNameIdx,sal_Int32 nFamilyIdx,sal_Int32 nPitchIdx,sal_Int32 nCharsetIdx) const380 bool XMLFontStylesContext::FillProperties( const OUString& rName,
381                          ::std::vector< XMLPropertyState > &rProps,
382                          sal_Int32 nFamilyNameIdx,
383                          sal_Int32 nStyleNameIdx,
384                          sal_Int32 nFamilyIdx,
385                          sal_Int32 nPitchIdx,
386                          sal_Int32 nCharsetIdx ) const
387 {
388     const SvXMLStyleContext* pStyle = FindStyleChildContext( XML_STYLE_FAMILY_FONT, rName, true );
389     const XMLFontStyleContextFontFace *pFontStyle = dynamic_cast<const XMLFontStyleContextFontFace*>(pStyle);// use temp var, PTR_CAST is a bad macro, FindStyleChildContext will be called twice
390     if( pFontStyle )
391         pFontStyle->FillProperties( rProps, nFamilyNameIdx, nStyleNameIdx,
392                                     nFamilyIdx, nPitchIdx, nCharsetIdx );
393     return nullptr != pFontStyle;
394 }
395 
396 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
397