Kaydet (Commit) 989d0953 authored tarafından Luboš Luňák's avatar Luboš Luňák

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
üst 5ceaa68c
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <unotext.hxx> #include <unotext.hxx>
#include <doc.hxx> #include <doc.hxx>
#include <xmlexp.hxx> #include <xmlexp.hxx>
#include <xmlimp.hxx>
using namespace ::com::sun::star::uno; using namespace ::com::sun::star::uno;
...@@ -35,13 +36,13 @@ class SwXMLFontAutoStylePool_Impl: public XMLFontAutoStylePool ...@@ -35,13 +36,13 @@ class SwXMLFontAutoStylePool_Impl: public XMLFontAutoStylePool
{ {
public: public:
SwXMLFontAutoStylePool_Impl( SwXMLExport& rExport ); SwXMLFontAutoStylePool_Impl( SwXMLExport& rExport, bool blockFontEmbedding );
}; };
SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl( SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl(
SwXMLExport& _rExport ) : SwXMLExport& _rExport, bool blockFontEmbedding ) :
XMLFontAutoStylePool( _rExport ) XMLFontAutoStylePool( _rExport, blockFontEmbedding )
{ {
sal_uInt16 aWhichIds[3] = { RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, sal_uInt16 aWhichIds[3] = { RES_CHRATR_FONT, RES_CHRATR_CJK_FONT,
RES_CHRATR_CTL_FONT }; RES_CHRATR_CTL_FONT };
...@@ -75,7 +76,21 @@ SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl( ...@@ -75,7 +76,21 @@ SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl(
XMLFontAutoStylePool* SwXMLExport::CreateFontAutoStylePool() 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: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
...@@ -197,6 +197,8 @@ public: ...@@ -197,6 +197,8 @@ public:
::com::sun::star::document::XDocumentProperties> ::com::sun::star::document::XDocumentProperties>
GetDocumentProperties() const; GetDocumentProperties() const;
virtual void NotifyEmbeddedFontRead() SAL_OVERRIDE;
const SwDoc* getDoc() const; const SwDoc* getDoc() const;
SwDoc* getDoc(); SwDoc* getDoc();
}; };
......
...@@ -50,6 +50,7 @@ $(eval $(call gb_Library_use_libraries,xo,\ ...@@ -50,6 +50,7 @@ $(eval $(call gb_Library_use_libraries,xo,\
svl \ svl \
tl \ tl \
utl \ utl \
vcl \
$(gb_UWINAPI) \ $(gb_UWINAPI) \
)) ))
......
...@@ -37,6 +37,9 @@ class XMLOFF_DLLPUBLIC XMLFontAutoStylePool : public UniRefBase ...@@ -37,6 +37,9 @@ class XMLOFF_DLLPUBLIC XMLFontAutoStylePool : public UniRefBase
XMLFontAutoStylePool_Impl *pPool; XMLFontAutoStylePool_Impl *pPool;
XMLFontAutoStylePoolNames_Impl m_aNames; XMLFontAutoStylePoolNames_Impl m_aNames;
sal_uInt32 nName; sal_uInt32 nName;
bool tryToEmbedFonts;
OUString embedFontFile( const OUString& fontUrl, const char* style );
protected: protected:
...@@ -44,7 +47,7 @@ protected: ...@@ -44,7 +47,7 @@ protected:
public: public:
XMLFontAutoStylePool( SvXMLExport& rExport ); XMLFontAutoStylePool( SvXMLExport& rExport, bool tryToEmbedFonts = false );
~XMLFontAutoStylePool(); ~XMLFontAutoStylePool();
::rtl::OUString Add( ::rtl::OUString Add(
......
...@@ -121,12 +121,51 @@ public: ...@@ -121,12 +121,51 @@ public:
sal_Int32 nPitchIdx, sal_Int32 nPitchIdx,
sal_Int32 nCharsetIdx ) const; sal_Int32 nCharsetIdx ) const;
OUString familyName() const;
SvXMLImportContext * CreateChildContext( SvXMLImportContext * CreateChildContext(
sal_uInt16 nPrefix, sal_uInt16 nPrefix,
const ::rtl::OUString& rLocalName, const ::rtl::OUString& rLocalName,
const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); 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 #endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
...@@ -453,6 +453,8 @@ public: ...@@ -453,6 +453,8 @@ public:
@see <member>mbIsGraphicLoadOnDemandSupported</member> @see <member>mbIsGraphicLoadOnDemandSupported</member>
*/ */
bool isGraphicLoadOnDemandSupported() const; bool isGraphicLoadOnDemandSupported() const;
virtual void NotifyEmbeddedFontRead() {};
}; };
inline UniReference< XMLTextImportHelper > SvXMLImport::GetTextImport() inline UniReference< XMLTextImportHelper > SvXMLImport::GetTextImport()
......
...@@ -2457,6 +2457,8 @@ namespace xmloff { namespace token { ...@@ -2457,6 +2457,8 @@ namespace xmloff { namespace token {
XML_SCRIPTS, XML_SCRIPTS,
XML_FONT_FACE_DECLS, XML_FONT_FACE_DECLS,
XML_FONT_FACE, XML_FONT_FACE,
XML_FONT_FACE_SRC,
XML_FONT_FACE_URI,
XML_FONT_ADORNMENTS, XML_FONT_ADORNMENTS,
XML_INCH, XML_INCH,
XML_SPACE_AFTER, XML_SPACE_AFTER,
......
...@@ -2459,6 +2459,8 @@ namespace xmloff { namespace token { ...@@ -2459,6 +2459,8 @@ namespace xmloff { namespace token {
TOKEN( "scripts", XML_SCRIPTS ), TOKEN( "scripts", XML_SCRIPTS ),
TOKEN( "font-face-decls", XML_FONT_FACE_DECLS ), TOKEN( "font-face-decls", XML_FONT_FACE_DECLS ),
TOKEN( "font-face", XML_FONT_FACE ), 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( "font-adornments", XML_FONT_ADORNMENTS ),
TOKEN( "inch", XML_INCH ), TOKEN( "inch", XML_INCH ),
TOKEN( "space-after", XML_SPACE_AFTER ), TOKEN( "space-after", XML_SPACE_AFTER ),
......
...@@ -25,11 +25,17 @@ ...@@ -25,11 +25,17 @@
#include "fonthdl.hxx" #include "fonthdl.hxx"
#include <xmloff/xmlexp.hxx> #include <xmloff/xmlexp.hxx>
#include <xmloff/XMLFontAutoStylePool.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::OUString;
using ::rtl::OUStringBuffer; using ::rtl::OUStringBuffer;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno; using namespace ::com::sun::star::uno;
using namespace ::xmloff::token; using namespace ::xmloff::token;
...@@ -128,9 +134,10 @@ public: ...@@ -128,9 +134,10 @@ public:
~XMLFontAutoStylePool_Impl() { DeleteAndDestroyAll(); } ~XMLFontAutoStylePool_Impl() { DeleteAndDestroyAll(); }
}; };
XMLFontAutoStylePool::XMLFontAutoStylePool( SvXMLExport& rExp ) : XMLFontAutoStylePool::XMLFontAutoStylePool( SvXMLExport& rExp, bool _tryToEmbedFonts ) :
rExport( rExp ), rExport( rExp ),
pPool( new XMLFontAutoStylePool_Impl ) pPool( new XMLFontAutoStylePool_Impl ),
tryToEmbedFonts( _tryToEmbedFonts )
{ {
} }
...@@ -226,6 +233,7 @@ void XMLFontAutoStylePool::exportXML() ...@@ -226,6 +233,7 @@ void XMLFontAutoStylePool::exportXML()
XMLFontEncodingPropHdl aEncHdl; XMLFontEncodingPropHdl aEncHdl;
const SvXMLUnitConverter& rUnitConv = GetExport().GetMM100UnitConverter(); const SvXMLUnitConverter& rUnitConv = GetExport().GetMM100UnitConverter();
std::map< OUString, OUString > fontFilesMap; // our url to document url
sal_uInt32 nCount = pPool->size(); sal_uInt32 nCount = pPool->size();
for( sal_uInt32 i=0; i<nCount; i++ ) for( sal_uInt32 i=0; i<nCount; i++ )
{ {
...@@ -263,7 +271,106 @@ void XMLFontAutoStylePool::exportXML() ...@@ -263,7 +271,106 @@ void XMLFontAutoStylePool::exportXML()
SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE, SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE,
XML_FONT_FACE, XML_FONT_FACE,
sal_True, sal_True ); 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();
} }
......
...@@ -21,8 +21,11 @@ ...@@ -21,8 +21,11 @@
#include <com/sun/star/awt/FontFamily.hpp> #include <com/sun/star/awt/FontFamily.hpp>
#include <com/sun/star/awt/FontPitch.hpp> #include <com/sun/star/awt/FontPitch.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <osl/file.hxx>
#include <rtl/logfile.hxx> #include <rtl/logfile.hxx>
#include <vcl/temporaryfonts.hxx>
#include <xmloff/nmspmap.hxx> #include <xmloff/nmspmap.hxx>
#include "xmloff/xmlnmspe.hxx" #include "xmloff/xmlnmspe.hxx"
...@@ -172,6 +175,127 @@ void XMLFontStyleContext_Impl::FillProperties( ...@@ -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( SvXMLStyleContext *XMLFontStylesContext::CreateStyleChildContext(
sal_uInt16 nPrefix, sal_uInt16 nPrefix,
const ::rtl::OUString& rLocalName, const ::rtl::OUString& rLocalName,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment