blob: c10f242a1477d1476844b8123150597672dc1a2b [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_filter.hxx"
#include "svgfontexport.hxx"
#include <vcl/unohelp.hxx>
static const sal_Int32 nFontEM = 2048;
// -----------------
// - SVGFontExport -
// -----------------
SVGFontExport::SVGFontExport( SVGExport& rExport, const ::std::vector< ObjectRepresentation >& rObjects ) :
mrExport( rExport ),
maObjects( rObjects ),
mnCurFontId( 0 )
{
}
// -----------------------------------------------------------------------------
SVGFontExport::~SVGFontExport()
{
}
// -----------------------------------------------------------------------------
SVGFontExport::GlyphSet& SVGFontExport::implGetGlyphSet( const Font& rFont )
{
FontWeight eWeight( WEIGHT_NORMAL );
FontItalic eItalic( ITALIC_NONE );
::rtl::OUString aFontName( rFont.GetName() );
sal_Int32 nNextTokenPos( 0 );
switch( rFont.GetWeight() )
{
case WEIGHT_BOLD:
case WEIGHT_ULTRABOLD:
case WEIGHT_BLACK:
eWeight = WEIGHT_BOLD;
break;
default:
break;
}
if( rFont.GetItalic() != ITALIC_NONE )
eItalic = ITALIC_NORMAL;
return( maGlyphTree[ aFontName.getToken( 0, ';', nNextTokenPos ) ][ eWeight ][ eItalic ] );
}
// -----------------------------------------------------------------------------
void SVGFontExport::implCollectGlyphs()
{
VirtualDevice aVDev;
ObjectVector::const_iterator aIter( maObjects.begin() );
aVDev.EnableOutput( sal_False );
while( aIter != maObjects.end() )
{
if( (*aIter).HasRepresentation() )
{
const GDIMetaFile& rMtf = (*aIter).GetRepresentation();
aVDev.Push();
for( sal_uInt32 i = 0, nCount = rMtf.GetActionCount(); i < nCount; ++i )
{
::rtl::OUString aText;
MetaAction* pAction = rMtf.GetAction( i );
const sal_uInt16 nType = pAction->GetType();
switch( nType )
{
case( META_TEXT_ACTION ):
{
const MetaTextAction* pA = (const MetaTextAction*) pAction;
aText = String( pA->GetText(), pA->GetIndex(), pA->GetLen() );
}
break;
case( META_TEXTRECT_ACTION ):
{
const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction;
aText = pA->GetText();
}
break;
case( META_TEXTARRAY_ACTION ):
{
const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pAction;
aText = String( pA->GetText(), pA->GetIndex(), pA->GetLen() );
}
break;
case( META_STRETCHTEXT_ACTION ):
{
const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction;
aText = String( pA->GetText(), pA->GetIndex(), pA->GetLen() );
}
break;
default:
pAction->Execute( &aVDev );
break;
}
if( aText.getLength() )
{
GlyphSet& rGlyphSet = implGetGlyphSet( aVDev.GetFont() );
::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xBI(
::vcl::unohelper::CreateBreakIterator() );
if( xBI.is() )
{
const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetLocale();
sal_Int32 nCurPos = 0, nLastPos = -1;
while( ( nCurPos < aText.getLength() ) && ( nCurPos > nLastPos ) )
{
sal_Int32 nCount2 = 1;
nLastPos = nCurPos;
nCurPos = xBI->nextCharacters( aText, nCurPos, rLocale,
::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL,
nCount2, nCount2 );
rGlyphSet.insert( aText.copy( nLastPos, nCurPos - nLastPos ) );
}
}
else
{
const sal_Unicode* pStr = aText.getStr();
for( sal_uInt32 k = 0, nLen = aText.getLength(); k < nLen; ++k )
rGlyphSet.insert( rtl::OUString( pStr[ k ] ) );
}
}
}
aVDev.Pop();
}
++aIter;
}
}
// -----------------------------------------------------------------------------
void SVGFontExport::implEmbedFont( const Font& rFont )
{
if( mrExport.IsEmbedFonts() )
{
GlyphSet& rGlyphSet = implGetGlyphSet( rFont );
if( !rGlyphSet.empty() )
{
GlyphSet::const_iterator aIter( rGlyphSet.begin() );
const ::rtl::OUString aEmbeddedFontStr( B2UCONST( "EmbeddedFont_" ) );
{
SvXMLElementExport aExp( mrExport, XML_NAMESPACE_NONE, "defs", sal_True, sal_True );
::rtl::OUString aCurIdStr( aEmbeddedFontStr );
::rtl::OUString aUnitsPerEM( ::rtl::OUString::valueOf( nFontEM ) );
VirtualDevice aVDev;
Font aFont( rFont );
aFont.SetSize( Size( 0, nFontEM ) );
aFont.SetAlign( ALIGN_BASELINE );
aVDev.SetMapMode( MAP_100TH_MM );
aVDev.SetFont( aFont );
mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", aCurIdStr += ::rtl::OUString::valueOf( ++mnCurFontId ) );
mrExport.AddAttribute( XML_NAMESPACE_NONE, "horiz-adv-x", aUnitsPerEM );
{
SvXMLElementExport aExp2( mrExport, XML_NAMESPACE_NONE, "font", sal_True, sal_True );
::rtl::OUString aFontWeight;
::rtl::OUString aFontStyle;
const Size aSize( nFontEM, nFontEM );
// Font Weight
if( aFont.GetWeight() != WEIGHT_NORMAL )
aFontWeight = B2UCONST( "bold" );
else
aFontWeight = B2UCONST( "normal" );
// Font Italic
if( aFont.GetItalic() != ITALIC_NONE )
aFontStyle = B2UCONST( "italic" );
else
aFontStyle = B2UCONST( "normal" );
mrExport.AddAttribute( XML_NAMESPACE_NONE, "font-family", GetMappedFontName( rFont.GetName() ) );
mrExport.AddAttribute( XML_NAMESPACE_NONE, "units-per-em", aUnitsPerEM );
mrExport.AddAttribute( XML_NAMESPACE_NONE, "font-weight", aFontWeight );
mrExport.AddAttribute( XML_NAMESPACE_NONE, "font-style", aFontStyle );
mrExport.AddAttribute( XML_NAMESPACE_NONE, "ascent", ::rtl::OUString::valueOf( aVDev.GetFontMetric().GetAscent() ) );
mrExport.AddAttribute( XML_NAMESPACE_NONE, "descent", ::rtl::OUString::valueOf( aVDev.GetFontMetric().GetDescent() ) );
{
SvXMLElementExport aExp3( mrExport, XML_NAMESPACE_NONE, "font-face", sal_True, sal_True );
}
mrExport.AddAttribute( XML_NAMESPACE_NONE, "horiz-adv-x", ::rtl::OUString::valueOf( aSize.Width() ) );
{
const Point aPos;
const PolyPolygon aMissingGlyphPolyPoly( Rectangle( aPos, aSize ) );
mrExport.AddAttribute( XML_NAMESPACE_NONE, "d", SVGActionWriter::GetPathString( aMissingGlyphPolyPoly, sal_False ) );
{
SvXMLElementExport aExp4( mrExport, XML_NAMESPACE_NONE, "missing-glyph", sal_True, sal_True );
}
}
while( aIter != rGlyphSet.end() )
{
implEmbedGlyph( aVDev, *aIter );
++aIter;
}
}
}
}
}
}
// -----------------------------------------------------------------------------
void SVGFontExport::implEmbedGlyph( OutputDevice& rOut, const ::rtl::OUString& rCellStr )
{
PolyPolygon aPolyPoly;
const sal_Unicode nSpace = ' ';
if( rOut.GetTextOutline( aPolyPoly, rCellStr ) )
{
Rectangle aBoundRect;
aPolyPoly.Scale( 1.0, -1.0 );
if( !rOut.GetTextBoundRect( aBoundRect, rCellStr ) )
aBoundRect = Rectangle( Point( 0, 0 ), Size( rOut.GetTextWidth( rCellStr ), 0 ) );
mrExport.AddAttribute( XML_NAMESPACE_NONE, "unicode", rCellStr );
if( rCellStr[ 0 ] == nSpace && rCellStr.getLength() == 1 )
aBoundRect = Rectangle( Point( 0, 0 ), Size( rOut.GetTextWidth( sal_Unicode( ' ' ) ), 0 ) );
mrExport.AddAttribute( XML_NAMESPACE_NONE, "horiz-adv-x", ::rtl::OUString::valueOf( aBoundRect.GetWidth() ) );
const ::rtl::OUString aPathString( SVGActionWriter::GetPathString( aPolyPoly, sal_False ) );
if( aPathString.getLength() )
{
mrExport.AddAttribute( XML_NAMESPACE_NONE, "d", aPathString );
}
{
SvXMLElementExport aExp( mrExport, XML_NAMESPACE_NONE, "glyph", sal_True, sal_True );
}
}
}
// -----------------------------------------------------------------------------
void SVGFontExport::EmbedFonts()
{
implCollectGlyphs();
GlyphTree::const_iterator aGlyphTreeIter( maGlyphTree.begin() );
while( aGlyphTreeIter != maGlyphTree.end() )
{
const FontWeightMap& rFontWeightMap = (*aGlyphTreeIter).second;
FontWeightMap::const_iterator aFontWeightIter( rFontWeightMap.begin() );
while( aFontWeightIter != rFontWeightMap.end() )
{
const FontItalicMap& rFontItalicMap = (*aFontWeightIter).second;
FontItalicMap::const_iterator aFontItalicIter( rFontItalicMap.begin() );
while( aFontItalicIter != rFontItalicMap.end() )
{
Font aFont;
aFont.SetName( (*aGlyphTreeIter).first );
aFont.SetWeight( (*aFontWeightIter).first );
aFont.SetItalic( (*aFontItalicIter).first );
implEmbedFont( aFont );
++aFontItalicIter;
}
++aFontWeightIter;
}
++aGlyphTreeIter;
}
}
// -----------------------------------------------------------------------------
::rtl::OUString SVGFontExport::GetMappedFontName( const ::rtl::OUString& rFontName ) const
{
sal_Int32 nNextTokenPos( 0 );
::rtl::OUString aRet( rFontName.getToken( 0, ';', nNextTokenPos ) );
if( mnCurFontId )
aRet += B2UCONST( " embedded" );
return aRet;
}