[Libreoffice-commits] .: sw/source xmloff/inc xmloff/Library_xo.mk xmloff/source

Luboš Luňák l.lunak at suse.cz
Fri Feb 1 05:27:55 PST 2013


 sw/source/filter/xml/xmlfonte.cxx            |   23 ++++-
 sw/source/filter/xml/xmlimp.hxx              |    2 
 xmloff/Library_xo.mk                         |    1 
 xmloff/inc/xmloff/XMLFontAutoStylePool.hxx   |    5 -
 xmloff/inc/xmloff/XMLFontStylesContext.hxx   |   39 ++++++++
 xmloff/inc/xmloff/xmlimp.hxx                 |    2 
 xmloff/inc/xmloff/xmltoken.hxx               |    2 
 xmloff/source/core/xmltoken.cxx              |    2 
 xmloff/source/style/XMLFontAutoStylePool.cxx |  111 +++++++++++++++++++++++-
 xmloff/source/style/XMLFontStylesContext.cxx |  124 +++++++++++++++++++++++++++
 10 files changed, 304 insertions(+), 7 deletions(-)

New commits:
commit 989d0953a4d69bef3c8aba8e9dc7758194adcdc4
Author: Luboš Luňák <l.lunak at suse.cz>
Date:   Fri Feb 1 14:26:36 2013 +0100

    basic support for embedded fonts in odt (fdo#42195)
    
    There are still places that should be improved a bit, but this works.
    
    Change-Id: Ieb7947a294ec95b6fd8cec2e8c4bc731e2594c42

diff --git a/sw/source/filter/xml/xmlfonte.cxx b/sw/source/filter/xml/xmlfonte.cxx
index 4b4e48c..60e9dca5 100644
--- a/sw/source/filter/xml/xmlfonte.cxx
+++ b/sw/source/filter/xml/xmlfonte.cxx
@@ -25,6 +25,7 @@
 #include <unotext.hxx>
 #include <doc.hxx>
 #include <xmlexp.hxx>
+#include <xmlimp.hxx>
 
 
 using namespace ::com::sun::star::uno;
@@ -35,13 +36,13 @@ class SwXMLFontAutoStylePool_Impl: public XMLFontAutoStylePool
 {
     public:
 
-    SwXMLFontAutoStylePool_Impl( SwXMLExport& rExport );
+    SwXMLFontAutoStylePool_Impl( SwXMLExport& rExport, bool blockFontEmbedding );
 
 };
 
 SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl(
-    SwXMLExport& _rExport ) :
-    XMLFontAutoStylePool( _rExport )
+    SwXMLExport& _rExport, bool blockFontEmbedding ) :
+    XMLFontAutoStylePool( _rExport, blockFontEmbedding )
 {
     sal_uInt16 aWhichIds[3] = { RES_CHRATR_FONT, RES_CHRATR_CJK_FONT,
                                 RES_CHRATR_CTL_FONT };
@@ -75,7 +76,21 @@ SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl(
 
 XMLFontAutoStylePool* SwXMLExport::CreateFontAutoStylePool()
 {
-    return new SwXMLFontAutoStylePool_Impl( *this );
+    bool blockFontEmbedding = false;
+    // We write font info to both content.xml and styles.xml, but they are both
+    // written by different SwXMLExport instance, and would therefore write each
+    // font file twice without complicated checking for duplicates, so handle
+    // the embedding only in one of them.
+    if(( getExportFlags() & EXPORT_CONTENT ) == 0 )
+        blockFontEmbedding = true;
+    if( !getDoc()->get( IDocumentSettingAccess::EMBED_FONTS ))
+        blockFontEmbedding = true;
+    return new SwXMLFontAutoStylePool_Impl( *this, !blockFontEmbedding );
+}
+
+void SwXMLImport::NotifyEmbeddedFontRead()
+{
+    getDoc()->set( IDocumentSettingAccess::EMBED_FONTS, true );
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlimp.hxx b/sw/source/filter/xml/xmlimp.hxx
index 093aea3..9922360 100644
--- a/sw/source/filter/xml/xmlimp.hxx
+++ b/sw/source/filter/xml/xmlimp.hxx
@@ -197,6 +197,8 @@ public:
         ::com::sun::star::document::XDocumentProperties>
             GetDocumentProperties() const;
 
+    virtual void NotifyEmbeddedFontRead() SAL_OVERRIDE;
+
     const SwDoc* getDoc() const;
     SwDoc* getDoc();
 };
diff --git a/xmloff/Library_xo.mk b/xmloff/Library_xo.mk
index a24b6fd..7ffa8ba 100644
--- a/xmloff/Library_xo.mk
+++ b/xmloff/Library_xo.mk
@@ -50,6 +50,7 @@ $(eval $(call gb_Library_use_libraries,xo,\
     svl \
     tl \
     utl \
+    vcl \
 	$(gb_UWINAPI) \
 ))
 
diff --git a/xmloff/inc/xmloff/XMLFontAutoStylePool.hxx b/xmloff/inc/xmloff/XMLFontAutoStylePool.hxx
index 4fd666b..8ed243d 100644
--- a/xmloff/inc/xmloff/XMLFontAutoStylePool.hxx
+++ b/xmloff/inc/xmloff/XMLFontAutoStylePool.hxx
@@ -37,6 +37,9 @@ class XMLOFF_DLLPUBLIC XMLFontAutoStylePool : public UniRefBase
     XMLFontAutoStylePool_Impl *pPool;
     XMLFontAutoStylePoolNames_Impl m_aNames;
     sal_uInt32 nName;
+    bool tryToEmbedFonts;
+
+    OUString embedFontFile( const OUString& fontUrl, const char* style );
 
 protected:
 
@@ -44,7 +47,7 @@ protected:
 
 public:
 
-    XMLFontAutoStylePool( SvXMLExport& rExport );
+    XMLFontAutoStylePool( SvXMLExport& rExport, bool tryToEmbedFonts = false );
     ~XMLFontAutoStylePool();
 
     ::rtl::OUString Add(
diff --git a/xmloff/inc/xmloff/XMLFontStylesContext.hxx b/xmloff/inc/xmloff/XMLFontStylesContext.hxx
index e48ae0a..7a50fc7 100644
--- a/xmloff/inc/xmloff/XMLFontStylesContext.hxx
+++ b/xmloff/inc/xmloff/XMLFontStylesContext.hxx
@@ -121,12 +121,51 @@ public:
                          sal_Int32 nPitchIdx,
                          sal_Int32 nCharsetIdx ) const;
 
+    OUString familyName() const;
+
     SvXMLImportContext * CreateChildContext(
         sal_uInt16 nPrefix,
         const ::rtl::OUString& rLocalName,
         const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList > & xAttrList );
 };
 
+/// Handles <style:font-face-src>
+class XMLFontStyleContextFontFaceSrc : public SvXMLImportContext
+{
+    const XMLFontStyleContext_Impl& font;
+public:
+
+    TYPEINFO();
+
+    XMLFontStyleContextFontFaceSrc( SvXMLImport& rImport, sal_uInt16 nPrfx,
+            const ::rtl::OUString& rLName,
+            const XMLFontStyleContext_Impl& font );
+
+    virtual SvXMLImportContext * CreateChildContext(
+        sal_uInt16 nPrefix,
+        const ::rtl::OUString& rLocalName,
+        const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList > & xAttrList );
+};
+
+/// Handles <style:font-face-uri>
+class XMLFontStyleContextFontFaceUri : public SvXMLStyleContext
+{
+    const XMLFontStyleContext_Impl& font;
+    void handleEmbeddedFont( const OUString& url );
+public:
+
+    TYPEINFO();
+
+    XMLFontStyleContextFontFaceUri( SvXMLImport& rImport, sal_uInt16 nPrfx,
+            const ::rtl::OUString& rLName,
+            const ::com::sun::star::uno::Reference<
+                ::com::sun::star::xml::sax::XAttributeList > & xAttrList,
+            const XMLFontStyleContext_Impl& font );
+
+    virtual void SetAttribute( sal_uInt16 nPrefixKey, const OUString& rLocalName,
+        const OUString& rValue );
+};
+
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/inc/xmloff/xmlimp.hxx b/xmloff/inc/xmloff/xmlimp.hxx
index d97fe84..7e6381a 100644
--- a/xmloff/inc/xmloff/xmlimp.hxx
+++ b/xmloff/inc/xmloff/xmlimp.hxx
@@ -453,6 +453,8 @@ public:
         @see <member>mbIsGraphicLoadOnDemandSupported</member>
      */
     bool isGraphicLoadOnDemandSupported() const;
+
+    virtual void NotifyEmbeddedFontRead() {};
 };
 
 inline UniReference< XMLTextImportHelper > SvXMLImport::GetTextImport()
diff --git a/xmloff/inc/xmloff/xmltoken.hxx b/xmloff/inc/xmloff/xmltoken.hxx
index c4dff1c..13b59fe 100644
--- a/xmloff/inc/xmloff/xmltoken.hxx
+++ b/xmloff/inc/xmloff/xmltoken.hxx
@@ -2457,6 +2457,8 @@ namespace xmloff { namespace token {
         XML_SCRIPTS,
         XML_FONT_FACE_DECLS,
         XML_FONT_FACE,
+        XML_FONT_FACE_SRC,
+        XML_FONT_FACE_URI,
         XML_FONT_ADORNMENTS,
         XML_INCH,
         XML_SPACE_AFTER,
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index 4011f49..0318052 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -2459,6 +2459,8 @@ namespace xmloff { namespace token {
         TOKEN( "scripts",                          XML_SCRIPTS ),
         TOKEN( "font-face-decls",                 XML_FONT_FACE_DECLS ),
         TOKEN( "font-face",                        XML_FONT_FACE ),
+        TOKEN( "font-face-src",                    XML_FONT_FACE_SRC ),
+        TOKEN( "font-face-uri",                    XML_FONT_FACE_URI ),
         TOKEN( "font-adornments",                 XML_FONT_ADORNMENTS ),
         TOKEN( "inch",                             XML_INCH ),
         TOKEN( "space-after",                      XML_SPACE_AFTER ),
diff --git a/xmloff/source/style/XMLFontAutoStylePool.cxx b/xmloff/source/style/XMLFontAutoStylePool.cxx
index a496e79..0f92d66 100644
--- a/xmloff/source/style/XMLFontAutoStylePool.cxx
+++ b/xmloff/source/style/XMLFontAutoStylePool.cxx
@@ -25,11 +25,17 @@
 #include "fonthdl.hxx"
 #include <xmloff/xmlexp.hxx>
 #include <xmloff/XMLFontAutoStylePool.hxx>
+#include <vcl/temporaryfonts.hxx>
+#include <osl/file.hxx>
 
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
 
 using ::rtl::OUString;
 using ::rtl::OUStringBuffer;
 
+using namespace ::com::sun::star;
 using namespace ::com::sun::star::uno;
 using namespace ::xmloff::token;
 
@@ -128,9 +134,10 @@ public:
     ~XMLFontAutoStylePool_Impl() { DeleteAndDestroyAll(); }
 };
 
-XMLFontAutoStylePool::XMLFontAutoStylePool( SvXMLExport& rExp ) :
+XMLFontAutoStylePool::XMLFontAutoStylePool( SvXMLExport& rExp, bool _tryToEmbedFonts ) :
     rExport( rExp ),
-    pPool( new XMLFontAutoStylePool_Impl )
+    pPool( new XMLFontAutoStylePool_Impl ),
+    tryToEmbedFonts( _tryToEmbedFonts )
 {
 }
 
@@ -226,6 +233,7 @@ void XMLFontAutoStylePool::exportXML()
     XMLFontEncodingPropHdl aEncHdl;
     const SvXMLUnitConverter& rUnitConv = GetExport().GetMM100UnitConverter();
 
+    std::map< OUString, OUString > fontFilesMap; // our url to document url
     sal_uInt32 nCount = pPool->size();
     for( sal_uInt32 i=0; i<nCount; i++ )
     {
@@ -263,7 +271,106 @@ void XMLFontAutoStylePool::exportXML()
         SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE,
                                   XML_FONT_FACE,
                                   sal_True, sal_True );
+
+        if( tryToEmbedFonts )
+        {
+            std::vector< OUString > fileUrls;
+            static const char* const styles[] = { "", "b", "i", "bi" };
+            for( unsigned int j = 0;
+                 j < SAL_N_ELEMENTS( styles );
+                 ++j )
+            {
+                OUString fileUrl = TemporaryFonts::fileUrlForFont( pEntry->GetFamilyName(), styles[ j ] );
+                if( !fontFilesMap.count( fileUrl ))
+                {
+                    OUString docUrl = embedFontFile( fileUrl, styles[ j ] );
+                    if( !docUrl.isEmpty())
+                        fontFilesMap[ fileUrl ] = docUrl;
+                    else
+                        continue; // --> failed (most probably this font is not embedded)
+                }
+                fileUrls.push_back( fileUrl );
+            }
+            if( !fileUrls.empty())
+            {
+                SvXMLElementExport fontFaceSrc( GetExport(), XML_NAMESPACE_SVG,
+                    XML_FONT_FACE_SRC, true, true );
+                for( std::vector< OUString >::const_iterator it = fileUrls.begin();
+                     it != fileUrls.end();
+                     ++it )
+                {
+                    if( fontFilesMap.count( *it ))
+                    {
+                        GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, fontFilesMap[ *it ] );
+                        GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, "simple" );
+                        SvXMLElementExport fontFaceUri( GetExport(), XML_NAMESPACE_SVG,
+                            XML_FONT_FACE_URI, true, true );
+                    }
+                }
+            }
+        }
+    }
+}
+
+OUString XMLFontAutoStylePool::embedFontFile( const OUString& fileUrl, const char* style )
+{
+    try
+    {
+        osl::File file( fileUrl );
+        if( file.open( osl_File_OpenFlag_Read ) != osl::File::E_None )
+            return OUString();
+        uno::Reference< embed::XStorage > storage;
+        storage.set( GetExport().GetTargetStorage()->openStorageElement( OUString( "Fonts" ),
+            ::embed::ElementModes::WRITE ), uno::UNO_QUERY_THROW );
+        int index = 0;
+        OUString name;
+        do
+        {
+            name = "font" + OUString::number( ++index ) + OUString::createFromAscii( style ) + ".ttf";
+        } while( storage->hasByName( name ) );
+        uno::Reference< io::XOutputStream > outputStream;
+        outputStream.set( storage->openStreamElement( name, ::embed::ElementModes::WRITE ), UNO_QUERY_THROW );
+        uno::Reference < beans::XPropertySet > propertySet( outputStream, uno::UNO_QUERY );
+        assert( propertySet.is());
+        propertySet->setPropertyValue( "MediaType", uno::makeAny( OUString( "application/x-font-ttf" ))); // TODO
+        for(;;)
+        {
+            char buffer[ 4096 ];
+            sal_uInt64 readSize;
+            sal_Bool eof;
+            if( file.isEndOfFile( &eof ) != osl::File::E_None )
+            {
+                SAL_WARN( "xmloff", "Error reading font file " << fileUrl );
+                outputStream->closeOutput();
+                return OUString();
+            }
+            if( eof )
+                break;
+            if( file.read( buffer, 4096, readSize ) != osl::File::E_None )
+            {
+                SAL_WARN( "xmloff", "Error reading font file " << fileUrl );
+                outputStream->closeOutput();
+                return OUString();
+            }
+            if( readSize == 0 )
+                break;
+            outputStream->writeBytes( uno::Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( buffer ), readSize ));
+        }
+        outputStream->closeOutput();
+        if( storage.is() )
+        {
+            Reference< embed::XTransactedObject > transaction( storage, UNO_QUERY );
+            if( transaction.is())
+            {
+                transaction->commit();
+                return "Fonts/" + name;
+            }
+        }
+    } catch( const Exception& e )
+    {
+        SAL_WARN( "xmloff", "Exception when embedding a font file:" << e.Message );
     }
+    return OUString();
 }
 
 
diff --git a/xmloff/source/style/XMLFontStylesContext.cxx b/xmloff/source/style/XMLFontStylesContext.cxx
index 6a6e290..8cdb5ed 100644
--- a/xmloff/source/style/XMLFontStylesContext.cxx
+++ b/xmloff/source/style/XMLFontStylesContext.cxx
@@ -21,8 +21,11 @@
 
 #include <com/sun/star/awt/FontFamily.hpp>
 #include <com/sun/star/awt/FontPitch.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
 
+#include <osl/file.hxx>
 #include <rtl/logfile.hxx>
+#include <vcl/temporaryfonts.hxx>
 
 #include <xmloff/nmspmap.hxx>
 #include "xmloff/xmlnmspe.hxx"
@@ -172,6 +175,127 @@ void XMLFontStyleContext_Impl::FillProperties(
     }
 }
 
+SvXMLImportContext * XMLFontStyleContext_Impl::CreateChildContext(
+        sal_uInt16 nPrefix,
+        const ::rtl::OUString& rLocalName,
+        const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList > & xAttrList )
+{
+    if( nPrefix == XML_NAMESPACE_SVG && IsXMLToken( rLocalName, XML_FONT_FACE_SRC ))
+        return new XMLFontStyleContextFontFaceSrc( GetImport(), nPrefix, rLocalName, *this );
+    return SvXMLStyleContext::CreateChildContext( nPrefix, rLocalName, xAttrList );
+}
+
+OUString XMLFontStyleContext_Impl::familyName() const
+{
+    OUString ret;
+    aFamilyName >>= ret;
+    return ret;
+}
+
+
+TYPEINIT1( XMLFontStyleContextFontFaceSrc, SvXMLImportContext );
+
+XMLFontStyleContextFontFaceSrc::XMLFontStyleContextFontFaceSrc( SvXMLImport& rImport,
+        sal_uInt16 nPrfx, const OUString& rLName,
+        const XMLFontStyleContext_Impl& _font )
+    : SvXMLImportContext( rImport, nPrfx, rLName )
+    , font( _font )
+{
+}
+
+SvXMLImportContext * XMLFontStyleContextFontFaceSrc::CreateChildContext(
+        sal_uInt16 nPrefix,
+        const ::rtl::OUString& rLocalName,
+        const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList > & xAttrList )
+{
+    if( nPrefix == XML_NAMESPACE_SVG && IsXMLToken( rLocalName, XML_FONT_FACE_URI ))
+        return new XMLFontStyleContextFontFaceUri( GetImport(), nPrefix, rLocalName, xAttrList, font );
+    return SvXMLImportContext::CreateChildContext( nPrefix, rLocalName, xAttrList );
+}
+
+
+TYPEINIT1( XMLFontStyleContextFontFaceUri, SvXMLImportContext );
+
+XMLFontStyleContextFontFaceUri::XMLFontStyleContextFontFaceUri( SvXMLImport& rImport,
+        sal_uInt16 nPrfx, const OUString& rLName,
+        const ::com::sun::star::uno::Reference<
+            ::com::sun::star::xml::sax::XAttributeList > & xAttrList,
+        const XMLFontStyleContext_Impl& _font )
+    : SvXMLStyleContext( rImport, nPrfx, rLName, xAttrList )
+    , font( _font )
+{
+}
+
+void XMLFontStyleContextFontFaceUri::SetAttribute( sal_uInt16 nPrefixKey, const OUString& rLocalName,
+    const OUString& rValue )
+{
+    if( nPrefixKey == XML_NAMESPACE_XLINK && IsXMLToken( rLocalName, XML_HREF ))
+        handleEmbeddedFont( rValue );
+    else
+        SvXMLStyleContext::SetAttribute( nPrefixKey, rLocalName, rValue );
+}
+
+void XMLFontStyleContextFontFaceUri::handleEmbeddedFont( const OUString& url )
+{
+    OUString fontName = font.familyName();
+    const char* style = "";
+    // OOXML needs to know what kind of style the font is (regular, italic, bold, bold-italic),
+    // and the TemporaryFonts class is modelled after it. But ODF doesn't (need to) include
+    // this information, so try to guess from the name (LO encodes the style), otherwise
+    // go with regular and hope it works.
+    if( url.endsWithIgnoreAsciiCase( "bi.ttf" ))
+        style = "bi";
+    else if( url.endsWithIgnoreAsciiCase( "b.ttf" ))
+        style = "b";
+    else if( url.endsWithIgnoreAsciiCase( "i.ttf" ))
+        style = "i";
+    // If there's any giveMeStreamForThisURL(), then it's well-hidden for me to find it.
+    if( GetImport().IsPackageURL( url ))
+    {
+        uno::Reference< embed::XStorage > storage;
+        storage.set( GetImport().GetSourceStorage(), UNO_QUERY_THROW );
+        if( url.indexOf( '/' ) > -1 ) // TODO what if more levels?
+            storage.set( storage->openStorageElement( url.copy( 0, url.indexOf( '/' )),
+                ::embed::ElementModes::READ ), uno::UNO_QUERY_THROW );
+        OUString fileUrl = TemporaryFonts::fileUrlForFont( fontName, style );
+        osl::File file( fileUrl );
+        switch( file.open( osl_File_OpenFlag_Create | osl_File_OpenFlag_Write ))
+        {
+            case osl::File::E_None:
+                break; // ok
+            case osl::File::E_EXIST:
+                return; // Assume it's already been added correctly.
+            default:
+                SAL_WARN( "xmloff", "Cannot open file for temporary font" );
+                return;
+        }
+        uno::Reference< io::XInputStream > inputStream;
+        inputStream.set( storage->openStreamElement( url.copy( url.indexOf( '/' ) + 1 ), ::embed::ElementModes::READ ),
+            UNO_QUERY_THROW );
+        for(;;)
+        {
+            uno::Sequence< sal_Int8 > buffer;
+            int read = inputStream->readBytes( buffer, 1024 );
+            sal_uInt64 dummy;
+            if( read > 0 )
+                file.write( buffer.getConstArray(), read, dummy );
+            if( read < 1024 )
+                break;
+        }
+        inputStream->closeInput();
+        if( file.close() != osl::File::E_None )
+        {
+            SAL_WARN( "xmloff", "Writing temporary font file failed" );
+            osl::File::remove( fileUrl );
+            return;
+        }
+        TemporaryFonts::activateFont( fontName, fileUrl );
+        GetImport().NotifyEmbeddedFontRead();
+    }
+    else
+        SAL_WARN( "xmloff", "External URL for font file not handled." );
+}
+
 SvXMLStyleContext *XMLFontStylesContext::CreateStyleChildContext(
         sal_uInt16 nPrefix,
         const ::rtl::OUString& rLocalName,


More information about the Libreoffice-commits mailing list