bump product version to 5.0.4.1
[LibreOffice.git] / xmloff / source / style / XMLFontAutoStylePool.cxx
blob04410018bda4c6e602d8a0eaadfe672a9244fd09
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <o3tl/sorted_vector.hxx>
21 #include <tools/fontenum.hxx>
22 #include <xmloff/xmlnmspe.hxx>
23 #include <xmloff/xmltoken.hxx>
24 #include <xmloff/xmluconv.hxx>
25 #include "fonthdl.hxx"
26 #include <xmloff/xmlexp.hxx>
27 #include <xmloff/XMLFontAutoStylePool.hxx>
28 #include <vcl/embeddedfontshelper.hxx>
29 #include <osl/file.hxx>
31 #include <com/sun/star/embed/ElementModes.hpp>
32 #include <com/sun/star/embed/XTransactedObject.hpp>
33 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
34 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
36 #include "XMLBase64Export.hxx"
38 using namespace ::com::sun::star;
39 using namespace ::com::sun::star::uno;
40 using namespace ::xmloff::token;
42 class XMLFontAutoStylePoolEntry_Impl
44 OUString sName;
45 OUString sFamilyName;
46 OUString sStyleName;
47 FontFamily nFamily;
48 FontPitch nPitch;
49 rtl_TextEncoding eEnc;
51 public:
53 inline XMLFontAutoStylePoolEntry_Impl(
54 const OUString& rName,
55 const OUString& rFamilyName,
56 const OUString& rStyleName,
57 FontFamily nFamily,
58 FontPitch nPitch,
59 rtl_TextEncoding eEnc );
61 inline XMLFontAutoStylePoolEntry_Impl(
62 const OUString& rFamilyName,
63 const OUString& rStyleName,
64 FontFamily nFamily,
65 FontPitch nPitch,
66 rtl_TextEncoding eEnc );
68 const OUString& GetName() const { return sName; }
69 const OUString& GetFamilyName() const { return sFamilyName; }
70 const OUString& GetStyleName() const { return sStyleName; }
71 FontFamily GetFamily() const { return nFamily; }
72 FontPitch GetPitch() const { return nPitch; }
73 rtl_TextEncoding GetEncoding() const { return eEnc; }
77 inline XMLFontAutoStylePoolEntry_Impl::XMLFontAutoStylePoolEntry_Impl(
78 const OUString& rName,
79 const OUString& rFamilyName,
80 const OUString& rStyleName,
81 FontFamily nFam,
82 FontPitch nP,
83 rtl_TextEncoding eE ) :
84 sName( rName ),
85 sFamilyName( rFamilyName ),
86 sStyleName( rStyleName ),
87 nFamily( nFam ),
88 nPitch( nP ),
89 eEnc( eE )
93 inline XMLFontAutoStylePoolEntry_Impl::XMLFontAutoStylePoolEntry_Impl(
94 const OUString& rFamilyName,
95 const OUString& rStyleName,
96 FontFamily nFam,
97 FontPitch nP,
98 rtl_TextEncoding eE ) :
99 sFamilyName( rFamilyName ),
100 sStyleName( rStyleName ),
101 nFamily( nFam ),
102 nPitch( nP ),
103 eEnc( eE )
107 struct XMLFontAutoStylePoolEntryCmp_Impl {
108 bool operator()(
109 XMLFontAutoStylePoolEntry_Impl* const& r1,
110 XMLFontAutoStylePoolEntry_Impl* const& r2 ) const
112 bool nEnc1(r1->GetEncoding() != RTL_TEXTENCODING_SYMBOL);
113 bool nEnc2(r2->GetEncoding() != RTL_TEXTENCODING_SYMBOL);
114 if( nEnc1 != nEnc2 )
115 return nEnc1 < nEnc2;
116 else if( r1->GetPitch() != r2->GetPitch() )
117 return r1->GetPitch() < r2->GetPitch();
118 else if( r1->GetFamily() != r2->GetFamily() )
119 return r1->GetFamily() < r2->GetFamily();
120 else
122 sal_Int32 nCmp = r1->GetFamilyName().compareTo( r2->GetFamilyName() );
123 if( 0 == nCmp )
124 return r1->GetStyleName().compareTo( r2->GetStyleName() ) < 0;
125 else
126 return nCmp < 0;
131 class XMLFontAutoStylePool_Impl : public o3tl::sorted_vector<XMLFontAutoStylePoolEntry_Impl*, XMLFontAutoStylePoolEntryCmp_Impl>
133 public:
134 ~XMLFontAutoStylePool_Impl() { DeleteAndDestroyAll(); }
137 XMLFontAutoStylePool::XMLFontAutoStylePool( SvXMLExport& rExp, bool _tryToEmbedFonts ) :
138 rExport( rExp ),
139 pPool( new XMLFontAutoStylePool_Impl ),
140 tryToEmbedFonts( _tryToEmbedFonts )
144 XMLFontAutoStylePool::~XMLFontAutoStylePool()
146 delete pPool;
149 OUString XMLFontAutoStylePool::Add(
150 const OUString& rFamilyName,
151 const OUString& rStyleName,
152 FontFamily nFamily,
153 FontPitch nPitch,
154 rtl_TextEncoding eEnc )
156 OUString sPoolName;
157 XMLFontAutoStylePoolEntry_Impl aTmp( rFamilyName, rStyleName, nFamily,
158 nPitch, eEnc );
159 XMLFontAutoStylePool_Impl::const_iterator it = pPool->find( &aTmp );
160 if( it != pPool->end() )
162 sPoolName = (*it)->GetName();
164 else
166 OUString sName;
167 sal_Int32 nLen = rFamilyName.indexOf( ';', 0 );
168 if( -1 == nLen )
170 sName = rFamilyName;
172 else if( nLen > 0 )
174 sName = rFamilyName.copy( 0, nLen );
175 sName = sName.trim();
178 if( sName.isEmpty() )
179 sName = "F";
181 if( m_aNames.find(sName) != m_aNames.end() )
183 sal_Int32 nCount = 1;
184 OUString sPrefix( sName );
185 sName += OUString::number( nCount );
186 while( m_aNames.find(sName) != m_aNames.end() )
188 sName = sPrefix;
189 sName += OUString::number( ++nCount );
193 XMLFontAutoStylePoolEntry_Impl *pEntry =
194 new XMLFontAutoStylePoolEntry_Impl( sName, rFamilyName, rStyleName,
195 nFamily, nPitch, eEnc );
196 pPool->insert( pEntry );
197 m_aNames.insert(sName);
200 return sPoolName;
203 OUString XMLFontAutoStylePool::Find(
204 const OUString& rFamilyName,
205 const OUString& rStyleName,
206 FontFamily nFamily,
207 FontPitch nPitch,
208 rtl_TextEncoding eEnc ) const
210 OUString sName;
211 XMLFontAutoStylePoolEntry_Impl aTmp( rFamilyName, rStyleName, nFamily,
212 nPitch, eEnc );
213 XMLFontAutoStylePool_Impl::const_iterator it = pPool->find( &aTmp );
214 if( it != pPool->end() )
216 sName = (*it)->GetName();
219 return sName;
222 namespace
225 OUString lcl_checkFontFile( const OUString &fileUrl )
227 osl::DirectoryItem aDirItem;
228 if( osl::DirectoryItem::get( fileUrl, aDirItem ) == osl::File::E_None )
230 osl::FileStatus aStatus( osl_FileStatus_Mask_Type );
231 if( aDirItem.getFileStatus( aStatus ) == osl::File::E_None )
233 if( !aStatus.isDirectory() )
234 return fileUrl;
237 return OUString();
242 void XMLFontAutoStylePool::exportXML()
244 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_OFFICE,
245 XML_FONT_FACE_DECLS,
246 true, true );
247 Any aAny;
248 OUString sTmp;
249 XMLFontFamilyNamePropHdl aFamilyNameHdl;
250 XMLFontFamilyPropHdl aFamilyHdl;
251 XMLFontPitchPropHdl aPitchHdl;
252 XMLFontEncodingPropHdl aEncHdl;
253 const SvXMLUnitConverter& rUnitConv = GetExport().GetMM100UnitConverter();
255 std::map< OUString, OUString > fontFilesMap; // our url to document url
256 sal_uInt32 nCount = pPool->size();
257 for( sal_uInt32 i=0; i<nCount; i++ )
259 const XMLFontAutoStylePoolEntry_Impl *pEntry = (*pPool)[ i ];
261 GetExport().AddAttribute( XML_NAMESPACE_STYLE,
262 XML_NAME, pEntry->GetName() );
264 aAny <<= pEntry->GetFamilyName();
265 if( aFamilyNameHdl.exportXML( sTmp, aAny, rUnitConv ) )
266 GetExport().AddAttribute( XML_NAMESPACE_SVG,
267 XML_FONT_FAMILY, sTmp );
269 const OUString& rStyleName = pEntry->GetStyleName();
270 if( !rStyleName.isEmpty() )
271 GetExport().AddAttribute( XML_NAMESPACE_STYLE,
272 XML_FONT_ADORNMENTS,
273 rStyleName );
275 aAny <<= (sal_Int16)pEntry->GetFamily();
276 if( aFamilyHdl.exportXML( sTmp, aAny, rUnitConv ) )
277 GetExport().AddAttribute( XML_NAMESPACE_STYLE,
278 XML_FONT_FAMILY_GENERIC, sTmp );
280 aAny <<= (sal_Int16)pEntry->GetPitch();
281 if( aPitchHdl.exportXML( sTmp, aAny, rUnitConv ) )
282 GetExport().AddAttribute( XML_NAMESPACE_STYLE,
283 XML_FONT_PITCH, sTmp );
285 aAny <<= (sal_Int16)pEntry->GetEncoding();
286 if( aEncHdl.exportXML( sTmp, aAny, rUnitConv ) )
287 GetExport().AddAttribute( XML_NAMESPACE_STYLE,
288 XML_FONT_CHARSET, sTmp );
290 SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE,
291 XML_FONT_FACE,
292 true, true );
294 if( tryToEmbedFonts )
296 const bool bExportFlat( GetExport().getExportFlags() & SvXMLExportFlags::EMBEDDED );
297 std::vector< OUString > fileUrls;
298 static const FontWeight weight[] = { WEIGHT_NORMAL, WEIGHT_BOLD, WEIGHT_NORMAL, WEIGHT_BOLD };
299 static const FontItalic italic[] = { ITALIC_NONE, ITALIC_NONE, ITALIC_NORMAL, ITALIC_NORMAL };
300 assert( SAL_N_ELEMENTS( weight ) == SAL_N_ELEMENTS( italic ));
301 for( unsigned int j = 0;
302 j < SAL_N_ELEMENTS( weight );
303 ++j )
305 // Embed font if at least viewing is allowed (in which case the opening app must check
306 // the font license rights too and open either read-only or not use the font for editing).
307 OUString fileUrl = EmbeddedFontsHelper::fontFileUrl( pEntry->GetFamilyName(), pEntry->GetFamily(),
308 italic[ j ], weight[ j ], pEntry->GetPitch(), pEntry->GetEncoding(),
309 EmbeddedFontsHelper::ViewingAllowed );
310 if( fileUrl.isEmpty())
311 continue;
312 if( !fontFilesMap.count( fileUrl ))
314 const OUString docUrl = bExportFlat ? lcl_checkFontFile( fileUrl ) : embedFontFile( fileUrl );
315 if( !docUrl.isEmpty())
316 fontFilesMap[ fileUrl ] = docUrl;
317 else
318 continue; // --> failed to embed
320 fileUrls.push_back( fileUrl );
322 if( !fileUrls.empty())
324 SvXMLElementExport fontFaceSrc( GetExport(), XML_NAMESPACE_SVG,
325 XML_FONT_FACE_SRC, true, true );
326 for( std::vector< OUString >::const_iterator it = fileUrls.begin();
327 it != fileUrls.end();
328 ++it )
330 if( fontFilesMap.count( *it ))
332 if( !bExportFlat )
334 GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, fontFilesMap[ *it ] );
335 GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, "simple" );
337 SvXMLElementExport fontFaceUri( GetExport(), XML_NAMESPACE_SVG,
338 XML_FONT_FACE_URI, true, true );
340 if( bExportFlat )
342 const uno::Reference< ucb::XSimpleFileAccess > xFileAccess( ucb::SimpleFileAccess::create( GetExport().getComponentContext() ) );
345 const uno::Reference< io::XInputStream > xInput( xFileAccess->openFileRead( fontFilesMap[ *it ] ) );
346 XMLBase64Export aBase64Exp( GetExport() );
347 aBase64Exp.exportOfficeBinaryDataElement( xInput );
349 catch( const uno::Exception & )
351 // opening the file failed, ignore
355 GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_STRING, "truetype" );
356 SvXMLElementExport fontFaceFormat( GetExport(), XML_NAMESPACE_SVG,
357 XML_FONT_FACE_FORMAT, true, true );
365 OUString XMLFontAutoStylePool::embedFontFile( const OUString& fileUrl )
369 osl::File file( fileUrl );
370 if( file.open( osl_File_OpenFlag_Read ) != osl::File::E_None )
371 return OUString();
373 if ( !GetExport().GetTargetStorage().is() )
374 return OUString();
376 uno::Reference< embed::XStorage > storage;
377 storage.set( GetExport().GetTargetStorage()->openStorageElement( OUString( "Fonts" ),
378 ::embed::ElementModes::WRITE ), uno::UNO_QUERY_THROW );
379 int index = 0;
380 OUString name;
383 name = "font" + OUString::number( ++index ) + ".ttf";
384 } while( storage->hasByName( name ) );
385 uno::Reference< io::XOutputStream > outputStream;
386 outputStream.set( storage->openStreamElement( name, ::embed::ElementModes::WRITE ), UNO_QUERY_THROW );
387 uno::Reference < beans::XPropertySet > propertySet( outputStream, uno::UNO_QUERY );
388 assert( propertySet.is());
389 propertySet->setPropertyValue( "MediaType", uno::makeAny( OUString( "application/x-font-ttf" ))); // TODO
390 for(;;)
392 char buffer[ 4096 ];
393 sal_uInt64 readSize;
394 sal_Bool eof;
395 if( file.isEndOfFile( &eof ) != osl::File::E_None )
397 SAL_WARN( "xmloff", "Error reading font file " << fileUrl );
398 outputStream->closeOutput();
399 return OUString();
401 if( eof )
402 break;
403 if( file.read( buffer, 4096, readSize ) != osl::File::E_None )
405 SAL_WARN( "xmloff", "Error reading font file " << fileUrl );
406 outputStream->closeOutput();
407 return OUString();
409 if( readSize == 0 )
410 break;
411 outputStream->writeBytes( uno::Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( buffer ), readSize ));
413 outputStream->closeOutput();
414 if( storage.is() )
416 Reference< embed::XTransactedObject > transaction( storage, UNO_QUERY );
417 if( transaction.is())
419 transaction->commit();
420 return "Fonts/" + name;
423 } catch( const Exception& e )
425 SAL_WARN( "xmloff", "Exception when embedding a font file:" << e.Message );
427 return OUString();
431 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */