LCOV - code coverage report
Current view: top level - sdext/source/pdfimport/tree - drawtreevisiting.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 453 615 73.7 %
Date: 2014-11-03 Functions: 27 31 87.1 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
      21             : #include "pdfiprocessor.hxx"
      22             : #include "xmlemitter.hxx"
      23             : #include "pdfihelper.hxx"
      24             : #include "imagecontainer.hxx"
      25             : #include "style.hxx"
      26             : #include "drawtreevisiting.hxx"
      27             : #include "genericelements.hxx"
      28             : 
      29             : #include "basegfx/polygon/b2dpolypolygontools.hxx"
      30             : #include "basegfx/range/b2drange.hxx"
      31             : 
      32             : #include "com/sun/star/i18n/BreakIterator.hpp"
      33             : #include "com/sun/star/i18n/CharacterClassification.hpp"
      34             : #include "com/sun/star/lang/XMultiServiceFactory.hpp"
      35             : #include "comphelper/processfactory.hxx"
      36             : #include "com/sun/star/i18n/ScriptType.hpp"
      37             : #include "com/sun/star/i18n/DirectionProperty.hpp"
      38             : 
      39             : #include <string.h>
      40             : 
      41             : using namespace ::com::sun::star;
      42             : using namespace ::com::sun::star::lang;
      43             : using namespace ::com::sun::star::i18n;
      44             : using namespace ::com::sun::star::uno;
      45             : 
      46             : namespace pdfi
      47             : {
      48             : 
      49        3006 : const Reference< XBreakIterator >& DrawXmlOptimizer::GetBreakIterator()
      50             : {
      51        3006 :     if ( !mxBreakIter.is() )
      52             :     {
      53           2 :         Reference< XComponentContext > xContext( this->m_rProcessor.m_xContext, uno::UNO_SET_THROW );
      54           2 :         mxBreakIter = BreakIterator::create(xContext);
      55             :     }
      56        3006 :     return mxBreakIter;
      57             : }
      58             : 
      59          22 : const Reference< XCharacterClassification >& DrawXmlEmitter::GetCharacterClassification()
      60             : {
      61          22 :     if ( !mxCharClass.is() )
      62             :     {
      63           2 :         Reference< XComponentContext > xContext( m_rEmitContext.m_xContext, uno::UNO_SET_THROW );
      64           2 :         mxCharClass = CharacterClassification::create(xContext);
      65             :     }
      66          22 :     return mxCharClass;
      67             : }
      68             : 
      69           0 : void DrawXmlEmitter::visit( HyperlinkElement& elem, const std::list< Element* >::const_iterator&   )
      70             : {
      71           0 :     if( elem.Children.empty() )
      72           0 :         return;
      73             : 
      74           0 :     const char* pType = dynamic_cast<DrawElement*>(elem.Children.front()) ? "draw:a" : "text:a";
      75             : 
      76           0 :     PropertyMap aProps;
      77           0 :     aProps[ "xlink:type" ] = "simple";
      78           0 :     aProps[ "xlink:href" ] = elem.URI;
      79           0 :     aProps[ "office:target-frame-name" ] = "_blank";
      80           0 :     aProps[ "xlink:show" ] = "new";
      81             : 
      82           0 :     m_rEmitContext.rEmitter.beginTag( pType, aProps );
      83           0 :     std::list< Element* >::iterator this_it =  elem.Children.begin();
      84           0 :     while( this_it !=elem.Children.end() && *this_it != &elem )
      85             :     {
      86           0 :         (*this_it)->visitedBy( *this, this_it );
      87           0 :         ++this_it;
      88             :     }
      89           0 :     m_rEmitContext.rEmitter.endTag( pType );
      90             : }
      91             : 
      92          22 : void DrawXmlEmitter::visit( TextElement& elem, const std::list< Element* >::const_iterator&   )
      93             : {
      94          22 :     if( elem.Text.isEmpty() )
      95          22 :         return;
      96             : 
      97          22 :     OUString strSpace(32);
      98          44 :     OUString strNbSpace(160);
      99          44 :     OUString tabSpace(0x09);
     100          44 :     PropertyMap aProps;
     101          22 :     if( elem.StyleId != -1 )
     102             :     {
     103          44 :         aProps[ OUString( "text:style-name"  ) ] =
     104          22 :             m_rEmitContext.rStyles.getStyleName( elem.StyleId );
     105             :     }
     106             : 
     107          44 :     OUString str(elem.Text.getStr());
     108             : 
     109             :     // Check for RTL
     110          22 :     bool isRTL = false;
     111          44 :     Reference< i18n::XCharacterClassification > xCC( GetCharacterClassification() );
     112          22 :     if( xCC.is() )
     113             :     {
     114         208 :         for(int i=1; i< elem.Text.getLength(); i++)
     115             :         {
     116         186 :             sal_Int16 nType = xCC->getCharacterDirection( str, i );
     117         186 :             if ( nType == ::com::sun::star::i18n::DirectionProperty_RIGHT_TO_LEFT           ||
     118         186 :                  nType == ::com::sun::star::i18n::DirectionProperty_RIGHT_TO_LEFT_ARABIC    ||
     119         186 :                  nType == ::com::sun::star::i18n::DirectionProperty_RIGHT_TO_LEFT_EMBEDDING ||
     120             :                  nType == ::com::sun::star::i18n::DirectionProperty_RIGHT_TO_LEFT_OVERRIDE
     121             :                 )
     122           0 :                 isRTL = true;
     123             :         }
     124             :     }
     125             : 
     126          22 :     if (isRTL)  // If so, reverse string
     127           0 :         str = m_rProcessor.mirrorString( str );
     128             : 
     129          22 :     m_rEmitContext.rEmitter.beginTag( "text:span", aProps );
     130             : 
     131         230 :     for(int i=0; i< elem.Text.getLength(); i++)
     132             :     {
     133         208 :         OUString strToken=  str.copy(i,1) ;
     134         208 :         if( strSpace.equals(strToken) || strNbSpace.equals(strToken))
     135             :         {
     136          28 :             aProps[ "text:c" ] = "1";
     137          28 :             m_rEmitContext.rEmitter.beginTag( "text:s", aProps );
     138          28 :             m_rEmitContext.rEmitter.endTag( "text:s");
     139             :         }
     140             :         else
     141             :         {
     142         180 :             if( tabSpace.equals(strToken) )
     143             :             {
     144           0 :                 m_rEmitContext.rEmitter.beginTag( "text:tab", aProps );
     145           0 :                 m_rEmitContext.rEmitter.endTag( "text:tab");
     146             :             }
     147             :             else
     148             :             {
     149         180 :                 m_rEmitContext.rEmitter.write( strToken );
     150             :             }
     151             :         }
     152         208 :     }
     153             : 
     154          22 :     std::list< Element* >::iterator this_it =  elem.Children.begin();
     155          44 :     while( this_it !=elem.Children.end() && *this_it != &elem )
     156             :     {
     157           0 :         (*this_it)->visitedBy( *this, this_it );
     158           0 :         ++this_it;
     159             :     }
     160             : 
     161          44 :     m_rEmitContext.rEmitter.endTag( "text:span" );
     162             : }
     163             : 
     164          22 : void DrawXmlEmitter::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator&   )
     165             : {
     166          22 :     PropertyMap aProps;
     167          22 :     if( elem.StyleId != -1 )
     168             :     {
     169          22 :         aProps[ "text:style-name" ] = m_rEmitContext.rStyles.getStyleName( elem.StyleId );
     170             :     }
     171          22 :     const char* pTagType = "text:p";
     172          22 :     if( elem.Type == elem.Headline )
     173           0 :         pTagType = "text:h";
     174          22 :     m_rEmitContext.rEmitter.beginTag( pTagType, aProps );
     175             : 
     176          22 :     std::list< Element* >::iterator this_it =  elem.Children.begin();
     177          66 :     while( this_it !=elem.Children.end() && *this_it != &elem )
     178             :     {
     179          22 :         (*this_it)->visitedBy( *this, this_it );
     180          22 :         ++this_it;
     181             :     }
     182             : 
     183          22 :     m_rEmitContext.rEmitter.endTag( pTagType );
     184          22 : }
     185             : 
     186          30 : void DrawXmlEmitter::fillFrameProps( DrawElement&       rElem,
     187             :                                      PropertyMap&       rProps,
     188             :                                      const EmitContext& rEmitContext,
     189             :                                      bool               bWasTransformed
     190             :                                      )
     191             : {
     192          30 :     double rel_x = rElem.x, rel_y = rElem.y;
     193             : 
     194          30 :     rProps[ "draw:z-index" ] = OUString::number( rElem.ZOrder );
     195          30 :     rProps[ "draw:style-name"] = rEmitContext.rStyles.getStyleName( rElem.StyleId );
     196          30 :     rProps[ "svg:width" ]   = convertPixelToUnitString( rElem.w );
     197          30 :     rProps[ "svg:height" ]  = convertPixelToUnitString( rElem.h );
     198             : 
     199          30 :     if (rElem.IsForText)
     200          22 :         rProps["draw:text-style-name"] = rEmitContext.rStyles.getStyleName(rElem.TextStyleId);
     201             : 
     202             :     const GraphicsContext& rGC =
     203          30 :         rEmitContext.rProcessor.getGraphicsContext( rElem.GCId );
     204          30 :     if( rGC.Transformation.isIdentity() || bWasTransformed )
     205             :     {
     206           6 :         rProps[ "svg:x" ]       = convertPixelToUnitString( rel_x );
     207           6 :         rProps[ "svg:y" ]       = convertPixelToUnitString( rel_y );
     208             :     }
     209             :     else
     210             :     {
     211          48 :         basegfx::B2DTuple aScale, aTranslation;
     212             :         double fRotate, fShearX;
     213             : 
     214          24 :         rGC.Transformation.decompose( aScale, aTranslation, fRotate, fShearX );
     215             : 
     216          48 :         OUStringBuffer aBuf( 256 );
     217             : 
     218             :         // TODO(F2): general transformation case missing; if implemented, note
     219             :         // that ODF rotation is oriented the other way
     220             : 
     221             :         // vertical mirroring is done by horizontally mirroring and rotaing 180 degree
     222             :         // quaint !
     223          24 :         if( rElem.MirrorVertical )
     224           0 :             fRotate += M_PI;
     225             : 
     226             :         // First check here is to skip image frame case
     227          94 :         if (rElem.IsForText &&
     228          22 :             (aScale.getX() < 0) &&
     229          24 :             (aScale.getY() > 0) &&
     230          24 :             (basegfx::fTools::equalZero(aScale.getX() + aScale.getY(), 0.0001)))
     231             :         {
     232           0 :             fRotate += M_PI;
     233             :         }
     234             : 
     235             :         // build transformation string
     236          24 :         if( fShearX != 0.0 )
     237             :         {
     238           0 :             aBuf.appendAscii( "skewX( " );
     239           0 :             aBuf.append( fShearX );
     240           0 :             aBuf.appendAscii( " )" );
     241             :         }
     242          24 :         if( fRotate != 0.0 )
     243             :         {
     244           0 :             if( !aBuf.isEmpty() )
     245           0 :                 aBuf.append( ' ' );
     246           0 :             aBuf.appendAscii( "rotate( " );
     247           0 :             aBuf.append( -fRotate );
     248           0 :             aBuf.appendAscii( " )" );
     249             : 
     250             :         }
     251          24 :         if( !aBuf.isEmpty() )
     252           0 :             aBuf.append( ' ' );
     253          24 :         aBuf.appendAscii( "translate( " );
     254          24 :         aBuf.append( convertPixelToUnitString( rel_x ) );
     255          24 :         aBuf.append( ' ' );
     256          24 :         aBuf.append( convertPixelToUnitString( rel_y ) );
     257          24 :         aBuf.appendAscii( " )" );
     258             : 
     259          48 :         rProps[ "draw:transform" ] = aBuf.makeStringAndClear();
     260             :     }
     261          30 : }
     262             : 
     263          24 : void DrawXmlEmitter::visit( FrameElement& elem, const std::list< Element* >::const_iterator&   )
     264             : {
     265          24 :     if( elem.Children.empty() )
     266          24 :         return;
     267             : 
     268          24 :     bool bTextBox = (dynamic_cast<ParagraphElement*>(elem.Children.front()) != NULL);
     269          24 :     PropertyMap aFrameProps;
     270          24 :     fillFrameProps( elem, aFrameProps, m_rEmitContext );
     271          24 :     m_rEmitContext.rEmitter.beginTag( "draw:frame", aFrameProps );
     272          24 :     if( bTextBox )
     273          22 :         m_rEmitContext.rEmitter.beginTag( "draw:text-box", PropertyMap() );
     274             : 
     275          24 :     std::list< Element* >::iterator this_it =  elem.Children.begin();
     276          72 :     while( this_it !=elem.Children.end() && *this_it != &elem )
     277             :     {
     278          24 :         (*this_it)->visitedBy( *this, this_it );
     279          24 :         ++this_it;
     280             :     }
     281             : 
     282          24 :     if( bTextBox )
     283          22 :         m_rEmitContext.rEmitter.endTag( "draw:text-box" );
     284          24 :     m_rEmitContext.rEmitter.endTag( "draw:frame" );
     285             : }
     286             : 
     287           6 : void DrawXmlEmitter::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& )
     288             : {
     289           6 :     elem.updateGeometry();
     290             :     /* note:
     291             :      *   aw recommends using 100dth of mm in all respects since the xml import
     292             :      *   (a) is buggy (see issue 37213)
     293             :      *   (b) is optimized for 100dth of mm and does not scale itself then,
     294             :      *       this does not gain us speed but makes for smaller rounding errors since
     295             :      *       the xml importer coordinates are integer based
     296             :      */
     297          12 :     for (sal_uInt32 i = 0; i< elem.PolyPoly.count(); i++)
     298             :     {
     299           6 :         basegfx::B2DPolygon b2dPolygon;
     300           6 :         b2dPolygon =  elem.PolyPoly.getB2DPolygon( i );
     301             : 
     302          24 :         for ( sal_uInt32 j = 0; j< b2dPolygon.count(); j++ )
     303             :         {
     304          18 :             basegfx::B2DPoint point;
     305          36 :             basegfx::B2DPoint nextPoint;
     306          18 :             point = b2dPolygon.getB2DPoint( j );
     307             : 
     308          36 :             basegfx::B2DPoint prevPoint;
     309          18 :             prevPoint = b2dPolygon.getPrevControlPoint( j ) ;
     310             : 
     311          18 :             point.setX( convPx2mmPrec2( point.getX() )*100.0 );
     312          18 :             point.setY( convPx2mmPrec2( point.getY() )*100.0 );
     313             : 
     314          18 :             if ( b2dPolygon.isPrevControlPointUsed( j ) )
     315             :             {
     316           8 :                 prevPoint.setX( convPx2mmPrec2( prevPoint.getX() )*100.0 );
     317           8 :                 prevPoint.setY( convPx2mmPrec2( prevPoint.getY() )*100.0 );
     318             :             }
     319             : 
     320          18 :             if ( b2dPolygon.isNextControlPointUsed( j ) )
     321             :             {
     322           8 :                 nextPoint = b2dPolygon.getNextControlPoint( j ) ;
     323           8 :                 nextPoint.setX( convPx2mmPrec2( nextPoint.getX() )*100.0 );
     324           8 :                 nextPoint.setY( convPx2mmPrec2( nextPoint.getY() )*100.0 );
     325             :             }
     326             : 
     327          18 :             b2dPolygon.setB2DPoint( j, point );
     328             : 
     329          18 :             if ( b2dPolygon.isPrevControlPointUsed( j ) )
     330           8 :                 b2dPolygon.setPrevControlPoint( j , prevPoint ) ;
     331             : 
     332          18 :             if ( b2dPolygon.isNextControlPointUsed( j ) )
     333           8 :                 b2dPolygon.setNextControlPoint( j , nextPoint ) ;
     334          18 :         }
     335             : 
     336           6 :         elem.PolyPoly.setB2DPolygon( i, b2dPolygon );
     337           6 :     }
     338             : 
     339           6 :     PropertyMap aProps;
     340             :     // PDFIProcessor transforms geometrical objects, not images and text
     341             :     // so we need to tell fillFrameProps here that the transformation for
     342             :     // a PolyPolyElement was already applied (aside form translation)
     343           6 :     fillFrameProps( elem, aProps, m_rEmitContext, true );
     344          12 :     OUStringBuffer aBuf( 64 );
     345           6 :     aBuf.appendAscii( "0 0 " );
     346           6 :     aBuf.append( convPx2mmPrec2(elem.w)*100.0 );
     347           6 :     aBuf.append( ' ' );
     348           6 :     aBuf.append( convPx2mmPrec2(elem.h)*100.0 );
     349           6 :     aProps[ "svg:viewBox" ] = aBuf.makeStringAndClear();
     350           6 :     aProps[ "svg:d" ]       = basegfx::tools::exportToSvgD( elem.PolyPoly, false, true, false );
     351             : 
     352           6 :     m_rEmitContext.rEmitter.beginTag( "draw:path", aProps );
     353          12 :     m_rEmitContext.rEmitter.endTag( "draw:path" );
     354           6 : }
     355             : 
     356           2 : void DrawXmlEmitter::visit( ImageElement& elem, const std::list< Element* >::const_iterator& )
     357             : {
     358           2 :     PropertyMap aImageProps;
     359           2 :     m_rEmitContext.rEmitter.beginTag( "draw:image", aImageProps );
     360           2 :     m_rEmitContext.rEmitter.beginTag( "office:binary-data", PropertyMap() );
     361           2 :     m_rEmitContext.rImages.writeBase64EncodedStream( elem.Image, m_rEmitContext);
     362           2 :     m_rEmitContext.rEmitter.endTag( "office:binary-data" );
     363           2 :     m_rEmitContext.rEmitter.endTag( "draw:image" );
     364           2 : }
     365             : 
     366           2 : void DrawXmlEmitter::visit( PageElement& elem, const std::list< Element* >::const_iterator&   )
     367             : {
     368           2 :     PropertyMap aPageProps;
     369           2 :     aPageProps[ "draw:master-page-name" ] = m_rEmitContext.rStyles.getStyleName( elem.StyleId );
     370             : 
     371           2 :     m_rEmitContext.rEmitter.beginTag("draw:page", aPageProps);
     372             : 
     373           2 :     if( m_rEmitContext.xStatusIndicator.is() )
     374           0 :         m_rEmitContext.xStatusIndicator->setValue( elem.PageNumber );
     375             : 
     376           2 :     std::list< Element* >::iterator this_it =  elem.Children.begin();
     377          34 :     while( this_it !=elem.Children.end() && *this_it != &elem )
     378             :     {
     379          30 :         (*this_it)->visitedBy( *this, this_it );
     380          30 :         ++this_it;
     381             :     }
     382             : 
     383           2 :     m_rEmitContext.rEmitter.endTag("draw:page");
     384           2 : }
     385             : 
     386           2 : void DrawXmlEmitter::visit( DocumentElement& elem, const std::list< Element* >::const_iterator&)
     387             : {
     388           2 :     m_rEmitContext.rEmitter.beginTag( "office:body", PropertyMap() );
     389             :     m_rEmitContext.rEmitter.beginTag( m_bWriteDrawDocument ? "office:drawing" : "office:presentation",
     390           2 :                                       PropertyMap() );
     391             : 
     392           2 :     std::list< Element* >::iterator this_it =  elem.Children.begin();
     393           6 :     while( this_it !=elem.Children.end() && *this_it != &elem )
     394             :     {
     395           2 :         (*this_it)->visitedBy( *this, this_it );
     396           2 :         ++this_it;
     397             :     }
     398             : 
     399           2 :     m_rEmitContext.rEmitter.endTag( m_bWriteDrawDocument ? "office:drawing" : "office:presentation" );
     400           2 :     m_rEmitContext.rEmitter.endTag( "office:body" );
     401           2 : }
     402             : 
     403             : 
     404             : 
     405           0 : void DrawXmlOptimizer::visit( HyperlinkElement&, const std::list< Element* >::const_iterator& )
     406             : {
     407           0 : }
     408             : 
     409          22 : void DrawXmlOptimizer::visit( TextElement&, const std::list< Element* >::const_iterator&)
     410             : {
     411          22 : }
     412             : 
     413          24 : void DrawXmlOptimizer::visit( FrameElement& elem, const std::list< Element* >::const_iterator& )
     414             : {
     415          24 :     elem.applyToChildren(*this);
     416          24 : }
     417             : 
     418           2 : void DrawXmlOptimizer::visit( ImageElement&, const std::list< Element* >::const_iterator& )
     419             : {
     420           2 : }
     421             : 
     422           6 : void DrawXmlOptimizer::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& )
     423             : {
     424             :     /* note: optimize two consecutive PolyPolyElements that
     425             :      *  have the same path but one of which is a stroke while
     426             :      *     the other is a fill
     427             :      */
     428           6 :     if( elem.Parent )
     429             :     {
     430             :         // find following PolyPolyElement in parent's children list
     431           6 :         std::list< Element* >::iterator this_it = elem.Parent->Children.begin();
     432          44 :         while( this_it != elem.Parent->Children.end() && *this_it != &elem )
     433          32 :             ++this_it;
     434             : 
     435           6 :         if( this_it != elem.Parent->Children.end() )
     436             :         {
     437           6 :             std::list< Element* >::iterator next_it = this_it;
     438           6 :             if( ++next_it != elem.Parent->Children.end() )
     439             :             {
     440           6 :                 PolyPolyElement* pNext = dynamic_cast<PolyPolyElement*>(*next_it);
     441             : 
     442             :                 // TODO(F2): this comparison fails for OOo-generated polygons with beziers.
     443           6 :                 if( pNext && pNext->PolyPoly == elem.PolyPoly )
     444             :                 {
     445             :                     const GraphicsContext& rNextGC =
     446           0 :                         m_rProcessor.getGraphicsContext( pNext->GCId );
     447             :                     const GraphicsContext& rThisGC =
     448           0 :                         m_rProcessor.getGraphicsContext( elem.GCId );
     449             : 
     450           0 :                     if( rThisGC.BlendMode      == rNextGC.BlendMode &&
     451           0 :                         rThisGC.Flatness       == rNextGC.Flatness &&
     452           0 :                         rThisGC.Transformation == rNextGC.Transformation &&
     453           0 :                         rThisGC.Clip           == rNextGC.Clip &&
     454           0 :                         rThisGC.FillColor.Red  == rNextGC.FillColor.Red &&
     455           0 :                         rThisGC.FillColor.Green== rNextGC.FillColor.Green &&
     456           0 :                         rThisGC.FillColor.Blue == rNextGC.FillColor.Blue &&
     457           0 :                         rThisGC.FillColor.Alpha== rNextGC.FillColor.Alpha &&
     458           0 :                         pNext->Action          == PATH_STROKE &&
     459           0 :                         (elem.Action == PATH_FILL || elem.Action == PATH_EOFILL) )
     460             :                     {
     461           0 :                         GraphicsContext aGC = rThisGC;
     462           0 :                         aGC.LineJoin  = rNextGC.LineJoin;
     463           0 :                         aGC.LineCap   = rNextGC.LineCap;
     464           0 :                         aGC.LineWidth = rNextGC.LineWidth;
     465           0 :                         aGC.MiterLimit= rNextGC.MiterLimit;
     466           0 :                         aGC.DashArray = rNextGC.DashArray;
     467           0 :                         aGC.LineColor = rNextGC.LineColor;
     468           0 :                         elem.GCId = m_rProcessor.getGCId( aGC );
     469             : 
     470           0 :                         elem.Action |= pNext->Action;
     471             : 
     472           0 :                         elem.Children.splice( elem.Children.end(), pNext->Children );
     473           0 :                         elem.Parent->Children.erase( next_it );
     474           0 :                         delete pNext;
     475             :                     }
     476             :                 }
     477             :             }
     478             :         }
     479             :     }
     480           6 : }
     481             : 
     482          22 : void DrawXmlOptimizer::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator& )
     483             : {
     484          22 :     optimizeTextElements( elem );
     485             : 
     486          22 :     elem.applyToChildren(*this);
     487          22 : }
     488             : 
     489           2 : void DrawXmlOptimizer::visit( PageElement& elem, const std::list< Element* >::const_iterator& )
     490             : {
     491           2 :     if( m_rProcessor.getStatusIndicator().is() )
     492           0 :         m_rProcessor.getStatusIndicator()->setValue( elem.PageNumber );
     493             : 
     494             :     // resolve hyperlinks
     495           2 :     elem.resolveHyperlinks();
     496             : 
     497           2 :     elem.resolveFontStyles( m_rProcessor ); // underlines and such
     498             : 
     499             :     // FIXME: until hyperlinks and font effects are adjusted for
     500             :     // geometrical search handle them before sorting
     501           2 :     m_rProcessor.sortElements( &elem );
     502             : 
     503             :     // find paragraphs in text
     504           2 :     ParagraphElement* pCurPara = NULL;
     505           2 :     std::list< Element* >::iterator page_element, next_page_element;
     506           2 :     next_page_element = elem.Children.begin();
     507           2 :     double fCurLineHeight = 0.0; // average height of text items in current para
     508           2 :     int nCurLineElements = 0; // number of line contributing elements in current para
     509           2 :     double line_left = elem.w, line_right = 0.0;
     510           2 :     double column_width = elem.w*0.75; // estimate text width
     511             :     // TODO: guess columns
     512          34 :     while( next_page_element != elem.Children.end() )
     513             :     {
     514          30 :         page_element = next_page_element++;
     515          30 :         ParagraphElement* pPagePara = dynamic_cast<ParagraphElement*>(*page_element);
     516          30 :         if( pPagePara )
     517             :         {
     518           0 :             pCurPara = pPagePara;
     519             :             // adjust line height and text items
     520           0 :             fCurLineHeight = 0.0;
     521           0 :             nCurLineElements = 0;
     522           0 :             for( std::list< Element* >::iterator it = pCurPara->Children.begin();
     523           0 :                  it != pCurPara->Children.end(); ++it )
     524             :             {
     525           0 :                 TextElement* pTestText = dynamic_cast<TextElement*>(*it);
     526           0 :                 if( pTestText )
     527             :                 {
     528           0 :                     fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pTestText->h)/double(nCurLineElements+1);
     529           0 :                     nCurLineElements++;
     530             :                 }
     531             :             }
     532           0 :             continue;
     533             :         }
     534             : 
     535          30 :         HyperlinkElement* pLink = dynamic_cast<HyperlinkElement*>(*page_element);
     536          30 :         DrawElement* pDraw = dynamic_cast<DrawElement*>(*page_element);
     537          30 :         if( ! pDraw && pLink && ! pLink->Children.empty() )
     538           0 :             pDraw = dynamic_cast<DrawElement*>(pLink->Children.front() );
     539          30 :         if( pDraw )
     540             :         {
     541             :             // insert small drawing objects as character, else leave them page bound
     542             : 
     543          30 :             bool bInsertToParagraph = false;
     544             :             // first check if this is either inside the paragraph
     545          30 :             if( pCurPara && pDraw->y < pCurPara->y + pCurPara->h )
     546             :             {
     547           0 :                 if( pDraw->h < fCurLineHeight * 1.5 )
     548             :                 {
     549           0 :                     bInsertToParagraph = true;
     550           0 :                     fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pDraw->h)/double(nCurLineElements+1);
     551           0 :                     nCurLineElements++;
     552             :                     // mark draw element as character
     553           0 :                     pDraw->isCharacter = true;
     554             :                 }
     555             :             }
     556             :             // or perhaps the draw element begins a new paragraph
     557          30 :             else if( next_page_element != elem.Children.end() )
     558             :             {
     559          28 :                 TextElement* pText = dynamic_cast<TextElement*>(*next_page_element);
     560          28 :                 if( ! pText )
     561             :                 {
     562          28 :                     ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(*next_page_element);
     563          28 :                     if( pPara && ! pPara->Children.empty() )
     564           0 :                         pText = dynamic_cast<TextElement*>(pPara->Children.front());
     565             :                 }
     566          28 :                 if( pText && // check there is a text
     567           0 :                     pDraw->h < pText->h*1.5 && // and it is approx the same height
     568             :                     // and either upper or lower edge of pDraw is inside text's vertical range
     569           0 :                     ( ( pDraw->y >= pText->y && pDraw->y <= pText->y+pText->h ) ||
     570           0 :                       ( pDraw->y+pDraw->h >= pText->y && pDraw->y+pDraw->h <= pText->y+pText->h )
     571             :                       )
     572             :                     )
     573             :                 {
     574           0 :                     bInsertToParagraph = true;
     575           0 :                     fCurLineHeight = pDraw->h;
     576           0 :                     nCurLineElements = 1;
     577           0 :                     line_left = pDraw->x;
     578           0 :                     line_right = pDraw->x + pDraw->w;
     579             :                     // begin a new paragraph
     580           0 :                     pCurPara = NULL;
     581             :                     // mark draw element as character
     582           0 :                     pDraw->isCharacter = true;
     583             :                 }
     584             :             }
     585             : 
     586          30 :             if( ! bInsertToParagraph )
     587             :             {
     588          30 :                 pCurPara = NULL;
     589          30 :                 continue;
     590             :             }
     591             :         }
     592             : 
     593           0 :         TextElement* pText = dynamic_cast<TextElement*>(*page_element);
     594           0 :         if( ! pText && pLink && ! pLink->Children.empty() )
     595           0 :             pText = dynamic_cast<TextElement*>(pLink->Children.front());
     596           0 :         if( pText )
     597             :         {
     598             :             Element* pGeo = pLink ? static_cast<Element*>(pLink) :
     599           0 :                                     static_cast<Element*>(pText);
     600           0 :             if( pCurPara )
     601             :             {
     602             :                 // there was already a text element, check for a new paragraph
     603           0 :                 if( nCurLineElements > 0 )
     604             :                 {
     605             :                     // if the new text is significantly distant from the paragraph
     606             :                     // begin a new paragraph
     607           0 :                     if( pGeo->y > pCurPara->y + pCurPara->h + fCurLineHeight*0.5  )
     608           0 :                         pCurPara = NULL; // insert new paragraph
     609           0 :                     else if( pGeo->y > (pCurPara->y+pCurPara->h - fCurLineHeight*0.05) )
     610             :                     {
     611             :                         // new paragraph if either the last line of the paragraph
     612             :                         // was significantly shorter than the paragraph as a whole
     613           0 :                         if( (line_right - line_left) < pCurPara->w*0.75 )
     614           0 :                             pCurPara = NULL;
     615             :                         // or the last line was significantly smaller than the column width
     616           0 :                         else if( (line_right - line_left) < column_width*0.75 )
     617           0 :                             pCurPara = NULL;
     618             :                     }
     619             :                 }
     620             : 
     621             : 
     622             :             }
     623             : 
     624             : 
     625             :             // update line height/width
     626           0 :             if( pCurPara )
     627             :             {
     628           0 :                 fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pGeo->h)/double(nCurLineElements+1);
     629           0 :                 nCurLineElements++;
     630           0 :                 if( pGeo->x < line_left )
     631           0 :                     line_left = pGeo->x;
     632           0 :                 if( pGeo->x+pGeo->w > line_right )
     633           0 :                     line_right = pGeo->x+pGeo->w;
     634             :             }
     635             :             else
     636             :             {
     637           0 :                 fCurLineHeight = pGeo->h;
     638           0 :                 nCurLineElements = 1;
     639           0 :                 line_left = pGeo->x;
     640           0 :                 line_right = pGeo->x + pGeo->w;
     641             :             }
     642             :         }
     643             : 
     644             : 
     645             :         // move element to current paragraph
     646           0 :        if (! pCurPara )  // new paragraph, insert one
     647             :        {
     648           0 :             pCurPara = m_rProcessor.getElementFactory()->createParagraphElement( NULL );
     649             :             // set parent
     650           0 :             pCurPara->Parent = &elem;
     651             :             //insert new paragraph before current element
     652           0 :             page_element = elem.Children.insert( page_element, pCurPara );
     653             :             // forward iterator to current element again
     654           0 :             ++ page_element;
     655             :             // update next_element which is now invalid
     656           0 :             next_page_element = page_element;
     657           0 :             ++ next_page_element;
     658             :        }
     659           0 :         Element* pCurEle = *page_element;
     660           0 :         Element::setParent( page_element, pCurPara );
     661             :         OSL_ENSURE( !pText || pCurEle == pText || pCurEle == pLink, "paragraph child list in disorder" );
     662           0 :         if( pText || pDraw )
     663           0 :             pCurPara->updateGeometryWith( pCurEle );
     664             :     }
     665             : 
     666             :     // process children
     667           2 :     elem.applyToChildren(*this);
     668           2 : }
     669             : 
     670           0 : bool isSpaces(TextElement* pTextElem)
     671             : {
     672           0 :     for (sal_Int32 i = 0; i != pTextElem->Text.getLength(); ++i) {
     673           0 :         if (pTextElem->Text[i] != ' ') {
     674           0 :             return false;
     675             :         }
     676             :     }
     677           0 :     return true;
     678             : }
     679             : 
     680         186 : bool notTransformed(const GraphicsContext& GC)
     681             : {
     682             :     return (
     683         372 :         GC.Transformation.get(0,0) ==  100.00 &&
     684         372 :         GC.Transformation.get(1,0) ==    0.00 &&
     685         558 :         GC.Transformation.get(0,1) ==    0.00 &&
     686         186 :         GC.Transformation.get(1,1) == -100.00
     687         186 :        );
     688             : }
     689             : 
     690          22 : void DrawXmlOptimizer::optimizeTextElements(Element& rParent)
     691             : {
     692          22 :     if( rParent.Children.empty() ) // this should not happen
     693             :     {
     694             :         OSL_FAIL( "empty paragraph optimized" );
     695          22 :         return;
     696             :     }
     697             : 
     698             :     // concatenate child elements with same font id
     699          22 :     std::list< Element* >::iterator next = rParent.Children.begin();
     700          22 :     std::list< Element* >::iterator it = next++;
     701             : 
     702         230 :     while( next != rParent.Children.end() )
     703             :     {
     704         186 :         bool bConcat = false;
     705         186 :         TextElement* pCur = dynamic_cast<TextElement*>(*it);
     706             : 
     707         186 :         if( pCur )
     708             :         {
     709         186 :             TextElement* pNext = dynamic_cast<TextElement*>(*next);
     710         186 :             bool isComplex = false;
     711         186 :             OUString str(pCur->Text.getStr());
     712        1596 :             for(int i=0; i< str.getLength(); i++)
     713             :             {
     714        1410 :                 sal_Int16 nType = GetBreakIterator()->getScriptType( str, i );
     715        1410 :                 if (nType == ::com::sun::star::i18n::ScriptType::COMPLEX)
     716           0 :                     isComplex = true;
     717             :             }
     718         186 :             bool bPara = strspn("ParagraphElement", typeid(rParent).name());
     719         186 :             ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(&rParent);
     720         186 :             if (bPara && pPara && isComplex)
     721           0 :                 pPara->bRtl = true;
     722         186 :             if( pNext )
     723             :             {
     724         186 :                 const GraphicsContext& rCurGC = m_rProcessor.getGraphicsContext( pCur->GCId );
     725         186 :                 const GraphicsContext& rNextGC = m_rProcessor.getGraphicsContext( pNext->GCId );
     726             : 
     727             :                 // line and space optimization; works only in strictly horizontal mode
     728             : 
     729             :                 // concatenate consecutive text elements unless there is a
     730             :                 // font or text color or matrix change, leave a new span in that case
     731         558 :                 if( (pCur->FontId == pNext->FontId || isSpaces(pNext)) &&
     732         372 :                     rCurGC.FillColor.Red == rNextGC.FillColor.Red &&
     733         372 :                     rCurGC.FillColor.Green == rNextGC.FillColor.Green &&
     734         372 :                     rCurGC.FillColor.Blue == rNextGC.FillColor.Blue &&
     735         744 :                     rCurGC.FillColor.Alpha == rNextGC.FillColor.Alpha &&
     736         372 :                     (rCurGC.Transformation == rNextGC.Transformation || notTransformed(rNextGC))
     737             :                     )
     738             :                 {
     739         186 :                     pCur->updateGeometryWith( pNext );
     740             :                     // append text to current element
     741         186 :                         pCur->Text.append( pNext->Text.getStr(), pNext->Text.getLength() );
     742             : 
     743         186 :                         str = pCur->Text.getStr();
     744        1782 :                     for(int i=0; i< str.getLength(); i++)
     745             :                     {
     746        1596 :                         sal_Int16 nType = GetBreakIterator()->getScriptType( str, i );
     747        1596 :                         if (nType == ::com::sun::star::i18n::ScriptType::COMPLEX)
     748           0 :                             isComplex = true;
     749             :                     }
     750         186 :                     if (bPara && pPara && isComplex)
     751           0 :                         pPara->bRtl = true;
     752             :                     // append eventual children to current element
     753             :                     // and clear children (else the children just
     754             :                     // appended to pCur would be destroyed)
     755         186 :                     pCur->Children.splice( pCur->Children.end(), pNext->Children );
     756             :                     // get rid of the now useless element
     757         186 :                     rParent.Children.erase( next );
     758         186 :                     delete pNext;
     759         186 :                     bConcat = true;
     760             :                 }
     761         186 :             }
     762             :         }
     763           0 :         else if( dynamic_cast<HyperlinkElement*>(*it) )
     764           0 :             optimizeTextElements( **it );
     765         186 :         if ( bConcat )
     766         186 :             next = it;
     767             :         else
     768           0 :             ++it;
     769         186 :         ++next;
     770             :     }
     771             : }
     772             : 
     773           2 : void DrawXmlOptimizer::visit( DocumentElement& elem, const std::list< Element* >::const_iterator&)
     774             : {
     775           2 :     elem.applyToChildren(*this);
     776           2 : }
     777             : 
     778             : 
     779           6 : void DrawXmlFinalizer::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& )
     780             : {
     781             :     // xxx TODO copied from DrawElement
     782           6 :     const GraphicsContext& rGC = m_rProcessor.getGraphicsContext(elem.GCId );
     783             : 
     784           6 :     PropertyMap aProps;
     785           6 :     aProps[ "style:family" ] = "graphic";
     786           6 :     aProps[ "style:parent-style-name" ] = "standard";
     787             :     // generate standard graphic style if necessary
     788           6 :     m_rStyleContainer.getStandardStyleId( "graphic" );
     789             : 
     790          12 :     PropertyMap aGCProps;
     791           6 :     if (elem.Action & PATH_STROKE)
     792             :     {
     793           4 :         double scale = GetAverageTransformationScale(rGC.Transformation);
     794           4 :         if (rGC.DashArray.size() < 2)
     795             :         {
     796           2 :             aGCProps[ "draw:stroke" ] = "solid";
     797             :         }
     798             :         else
     799             :         {
     800           2 :             PropertyMap props;
     801           2 :             FillDashStyleProps(props, rGC.DashArray, scale);
     802           4 :             StyleContainer::Style style("draw:stroke-dash", props);
     803             : 
     804           2 :             aGCProps[ "draw:stroke" ] = "dash";
     805           4 :             aGCProps[ "draw:stroke-dash" ] =
     806             :                 m_rStyleContainer.getStyleName(
     807           4 :                 m_rStyleContainer.getStyleId(style));
     808             :         }
     809             : 
     810           4 :         aGCProps[ "svg:stroke-color" ] = getColorString(rGC.LineColor);
     811           4 :         if (rGC.LineColor.Alpha != 1.0)
     812           0 :             aGCProps["svg:stroke-opacity"] = getPercentString(rGC.LineColor.Alpha * 100.0);
     813           4 :         aGCProps[ "svg:stroke-width" ] = convertPixelToUnitString(rGC.LineWidth * scale);
     814           4 :         aGCProps[ "draw:stroke-linejoin" ] = rGC.GetLineJoinString();
     815           4 :         aGCProps[ "svg:stroke-linecap" ] = rGC.GetLineCapString();
     816             :     }
     817             :     else
     818             :     {
     819           2 :         aGCProps[ "draw:stroke" ] = "none";
     820             :     }
     821             : 
     822             :     // TODO(F1): check whether stuff could be emulated by gradient/bitmap/hatch
     823           6 :     if( elem.Action & (PATH_FILL | PATH_EOFILL) )
     824             :     {
     825           2 :         aGCProps[ "draw:fill" ]   = "solid";
     826           2 :         aGCProps[ "draw:fill-color" ] = getColorString(rGC.FillColor);
     827           2 :         if (rGC.FillColor.Alpha != 1.0)
     828           0 :             aGCProps["draw:opacity"] = getPercentString(rGC.FillColor.Alpha * 100.0);
     829             :     }
     830             :     else
     831             :     {
     832           4 :         aGCProps[ "draw:fill" ] = "none";
     833             :     }
     834             : 
     835          12 :     StyleContainer::Style aStyle( "style:style", aProps );
     836          12 :     StyleContainer::Style aSubStyle( "style:graphic-properties", aGCProps );
     837           6 :     aStyle.SubStyles.push_back( &aSubStyle );
     838             : 
     839          12 :     elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
     840           6 : }
     841             : 
     842           0 : void DrawXmlFinalizer::visit( HyperlinkElement&, const std::list< Element* >::const_iterator& )
     843             : {
     844           0 : }
     845             : 
     846          44 : void SetFontsizeProperties(PropertyMap& props, double fontSize)
     847             : {
     848          44 :     OUStringBuffer aBuf(32);
     849          44 :     aBuf.append(fontSize * 72 / PDFI_OUTDEV_RESOLUTION);
     850          44 :     aBuf.appendAscii("pt");
     851          88 :     OUString aFSize = aBuf.makeStringAndClear();
     852          44 :     props["fo:font-size"] = aFSize;
     853          44 :     props["style:font-size-asian"] = aFSize;
     854          88 :     props["style:font-size-complex"] = aFSize;
     855          44 : }
     856             : 
     857          22 : void DrawXmlFinalizer::visit( TextElement& elem, const std::list< Element* >::const_iterator& )
     858             : {
     859          22 :     const FontAttributes& rFont = m_rProcessor.getFont( elem.FontId );
     860          22 :     PropertyMap aProps;
     861          22 :     aProps[ "style:family" ] = "text";
     862             : 
     863          44 :     PropertyMap aFontProps;
     864             : 
     865             :     // family name
     866          22 :     aFontProps[ "fo:font-family" ] = rFont.familyName;
     867          22 :     aFontProps[ "style:font-family-complex" ] = rFont.familyName;
     868             : 
     869             :     // bold
     870          22 :     if( rFont.isBold )
     871             :     {
     872           0 :         aFontProps[ "fo:font-weight" ]         = "bold";
     873           0 :         aFontProps[ "fo:font-weight-asian" ]   = "bold";
     874           0 :         aFontProps[ "style:font-weight-complex" ] = "bold";
     875             :     }
     876             :     // italic
     877          22 :     if( rFont.isItalic )
     878             :     {
     879           0 :         aFontProps[ "fo:font-style" ]         = "italic";
     880           0 :         aFontProps[ "fo:font-style-asian" ]   = "italic";
     881           0 :         aFontProps[ "style:font-style-complex" ] = "italic";
     882             :     }
     883             :     // underline
     884          22 :     if( rFont.isUnderline )
     885             :     {
     886           0 :         aFontProps[ "style:text-underline-style" ]  = "solid";
     887           0 :         aFontProps[ "style:text-underline-width" ]  = "auto";
     888           0 :         aFontProps[ "style:text-underline-color" ]  = "font-color";
     889             :     }
     890             :     // outline
     891          22 :     if( rFont.isOutline )
     892             :     {
     893           0 :         aFontProps[ "style:text-outline" ]  = "true";
     894             :     }
     895             : 
     896             :     // size
     897          22 :     SetFontsizeProperties(aFontProps, rFont.size);
     898             : 
     899             :     // color
     900          22 :     const GraphicsContext& rGC = m_rProcessor.getGraphicsContext( elem.GCId );
     901          22 :     aFontProps[ "fo:color" ] = getColorString( rFont.isOutline ? rGC.LineColor : rGC.FillColor );
     902             : 
     903             :     // scale
     904             :     double fRotate, fShearX;
     905          44 :     basegfx::B2DTuple aScale, aTranslation;
     906          22 :     rGC.Transformation.decompose(aScale, aTranslation, fRotate, fShearX);
     907          22 :     double textScale = -100 * aScale.getX() / aScale.getY();
     908          22 :     if (((textScale >= 1) && (textScale <= 99)) ||
     909           0 :         ((textScale >= 101) && (textScale <= 999)))
     910             :     {
     911           0 :         aFontProps[ "style:text-scale" ] = getPercentString(textScale);
     912             :     }
     913             : 
     914          44 :     StyleContainer::Style aStyle( "style:style", aProps );
     915          44 :     StyleContainer::Style aSubStyle( "style:text-properties", aFontProps );
     916          22 :     aStyle.SubStyles.push_back( &aSubStyle );
     917          44 :     elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
     918          22 : }
     919             : 
     920          22 : void DrawXmlFinalizer::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator& )
     921             : {
     922             : 
     923          22 :     PropertyMap aProps;
     924          22 :     aProps[ "style:family" ] = "paragraph";
     925             :     // generate standard paragraph style if necessary
     926          22 :     m_rStyleContainer.getStandardStyleId( "paragraph" );
     927             : 
     928          44 :     PropertyMap aParProps;
     929             : 
     930          22 :     aParProps[ "fo:text-align"]                   = "start";
     931          22 :     if (elem.bRtl)
     932           0 :         aParProps[ "style:writing-mode"]                    = "rl-tb";
     933             :     else
     934          22 :         aParProps[ "style:writing-mode"]                    = "lr-tb";
     935             : 
     936          44 :     StyleContainer::Style aStyle( "style:style", aProps );
     937          44 :     StyleContainer::Style aSubStyle( "style:paragraph-properties", aParProps );
     938          22 :     aStyle.SubStyles.push_back( &aSubStyle );
     939             : 
     940          22 :     elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
     941             : 
     942          44 :     elem.applyToChildren(*this);
     943          22 : }
     944             : 
     945          24 : void DrawXmlFinalizer::visit( FrameElement& elem, const std::list< Element* >::const_iterator&)
     946             : {
     947          24 :     PropertyMap props1;
     948          24 :     props1[ "style:family" ] = "graphic";
     949          24 :     props1[ "style:parent-style-name" ] = "standard";
     950             :     // generate standard graphic style if necessary
     951          24 :     m_rStyleContainer.getStandardStyleId( "graphic" );
     952             : 
     953          48 :     PropertyMap aGCProps;
     954             : 
     955          24 :     aGCProps[ "draw:stroke" ]                    = "none";
     956          24 :     aGCProps[ "draw:fill" ]                      = "none";
     957          24 :     aGCProps[ "draw:auto-grow-height" ]          = "true";
     958          24 :     aGCProps[ "draw:auto-grow-width" ]           = "true";
     959          24 :     aGCProps[ "draw:textarea-horizontal-align" ] = "left";
     960          24 :     aGCProps[ "draw:textarea-vertical-align" ]   = "top";
     961          24 :     aGCProps[ "fo:min-height"]                   = "0cm";
     962          24 :     aGCProps[ "fo:min-width"]                    = "0cm";
     963          24 :     aGCProps[ "fo:padding-top" ]                 = "0cm";
     964          24 :     aGCProps[ "fo:padding-left" ]                = "0cm";
     965          24 :     aGCProps[ "fo:padding-right" ]               = "0cm";
     966          24 :     aGCProps[ "fo:padding-bottom" ]              = "0cm";
     967             : 
     968             :     // remark: vertical mirroring is done in current OOO by
     969             :     // mirroring horzontally and rotating 180 degrees
     970             :     // this is quaint, but unfortunately it seems
     971             :     // mirror=vertical is defined but not implemented in current code
     972          24 :     if( elem.MirrorVertical )
     973           0 :         aGCProps[ "style:mirror" ] = "horizontal";
     974             : 
     975          48 :     StyleContainer::Style style1( "style:style", props1 );
     976          48 :     StyleContainer::Style subStyle1( "style:graphic-properties", aGCProps );
     977          24 :     style1.SubStyles.push_back(&subStyle1);
     978             : 
     979          24 :     elem.StyleId = m_rStyleContainer.getStyleId(style1);
     980             : 
     981          24 :     if (elem.IsForText)
     982             :     {
     983          22 :         PropertyMap props2;
     984          22 :         props2["style:family"] = "paragraph";
     985             : 
     986          44 :         PropertyMap textProps;
     987          22 :         SetFontsizeProperties(textProps, elem.FontSize);
     988             : 
     989          44 :         StyleContainer::Style style2("style:style", props2);
     990          44 :         StyleContainer::Style subStyle2("style:text-properties", textProps);
     991          22 :         style2.SubStyles.push_back(&subStyle2);
     992          44 :         elem.TextStyleId = m_rStyleContainer.getStyleId(style2);
     993             :     }
     994             : 
     995          48 :     elem.applyToChildren(*this);
     996          24 : }
     997             : 
     998           2 : void DrawXmlFinalizer::visit( ImageElement&, const std::list< Element* >::const_iterator& )
     999             : {
    1000           2 : }
    1001             : 
    1002           2 : void DrawXmlFinalizer::visit( PageElement& elem, const std::list< Element* >::const_iterator& )
    1003             : {
    1004           2 :     if( m_rProcessor.getStatusIndicator().is() )
    1005           0 :         m_rProcessor.getStatusIndicator()->setValue( elem.PageNumber );
    1006             : 
    1007             :     // transform from pixel to mm
    1008           2 :     double page_width = convPx2mm( elem.w ), page_height = convPx2mm( elem.h );
    1009             : 
    1010             :     // calculate page margins out of the relevant children (paragraphs)
    1011           2 :     elem.TopMargin = elem.h, elem.BottomMargin = 0, elem.LeftMargin = elem.w, elem.RightMargin = 0;
    1012             : 
    1013          32 :     for( std::list< Element* >::const_iterator it = elem.Children.begin(); it != elem.Children.end(); ++it )
    1014             :     {
    1015          30 :         if( (*it)->x < elem.LeftMargin )
    1016           2 :             elem.LeftMargin = (*it)->x;
    1017          30 :         if( (*it)->y < elem.TopMargin )
    1018           4 :             elem.TopMargin = (*it)->y;
    1019          30 :         if( (*it)->x + (*it)->w > elem.RightMargin )
    1020           8 :             elem.RightMargin = ((*it)->x + (*it)->w);
    1021          30 :         if( (*it)->y + (*it)->h > elem.BottomMargin )
    1022          16 :             elem.BottomMargin = ((*it)->y + (*it)->h);
    1023             :     }
    1024             : 
    1025             :     // transform margins to mm
    1026           2 :     double left_margin     = convPx2mm( elem.LeftMargin );
    1027           2 :     double right_margin    = convPx2mm( elem.RightMargin );
    1028           2 :     double top_margin      = convPx2mm( elem.TopMargin );
    1029           2 :     double bottom_margin   = convPx2mm( elem.BottomMargin );
    1030             : 
    1031             :     // round left/top margin to nearest mm
    1032           2 :     left_margin     = rtl_math_round( left_margin, 0, rtl_math_RoundingMode_Floor );
    1033           2 :     top_margin      = rtl_math_round( top_margin, 0, rtl_math_RoundingMode_Floor );
    1034             :     // round (fuzzy) right/bottom margin to nearest cm
    1035           2 :     right_margin    = rtl_math_round( right_margin, right_margin >= 10 ? -1 : 0, rtl_math_RoundingMode_Floor );
    1036           2 :     bottom_margin   = rtl_math_round( bottom_margin, bottom_margin >= 10 ? -1 : 0, rtl_math_RoundingMode_Floor );
    1037             : 
    1038             :     // set reasonable default in case of way too large margins
    1039             :     // e.g. no paragraph case
    1040           2 :     if( left_margin > page_width/2.0 - 10 )
    1041           0 :         left_margin = 10;
    1042           2 :     if( right_margin > page_width/2.0 - 10 )
    1043           2 :         right_margin = 10;
    1044           2 :     if( top_margin > page_height/2.0 - 10 )
    1045           0 :         top_margin = 10;
    1046           2 :     if( bottom_margin > page_height/2.0 - 10 )
    1047           2 :         bottom_margin = 10;
    1048             : 
    1049             :     // catch the weird cases
    1050           2 :     if( left_margin < 0 )
    1051           0 :         left_margin = 0;
    1052           2 :     if( right_margin < 0 )
    1053           0 :         right_margin = 0;
    1054           2 :     if( top_margin < 0 )
    1055           0 :         top_margin = 0;
    1056           2 :     if( bottom_margin < 0 )
    1057           0 :         bottom_margin = 0;
    1058             : 
    1059             :     // widely differing margins are unlikely to be correct
    1060           2 :     if( right_margin > left_margin*1.5 )
    1061           0 :         right_margin = left_margin;
    1062             : 
    1063           2 :     elem.LeftMargin      = convmm2Px( left_margin );
    1064           2 :     elem.RightMargin     = convmm2Px( right_margin );
    1065           2 :     elem.TopMargin       = convmm2Px( top_margin );
    1066           2 :     elem.BottomMargin    = convmm2Px( bottom_margin );
    1067             : 
    1068             :     // get styles for paragraphs
    1069           2 :     PropertyMap aPageProps;
    1070           4 :     PropertyMap aPageLayoutProps;
    1071           2 :     aPageLayoutProps[ "fo:margin-top" ]     =  unitMMString( top_margin );
    1072           2 :     aPageLayoutProps[ "fo:margin-bottom" ]  =  unitMMString( bottom_margin );
    1073           2 :     aPageLayoutProps[ "fo:margin-left" ]    =  unitMMString( left_margin );
    1074           2 :     aPageLayoutProps[ "fo:margin-right" ]   =  unitMMString( right_margin );
    1075           2 :     aPageLayoutProps[ "fo:page-width" ]     =  unitMMString( page_width );
    1076           2 :     aPageLayoutProps[ "fo:page-height" ]    =  unitMMString( page_height );
    1077           2 :     aPageLayoutProps[ "style:print-orientation" ]= elem.w < elem.h ? OUString("portrait") : OUString("landscape");
    1078           2 :     aPageLayoutProps[ "style:writing-mode" ]= "lr-tb";
    1079             : 
    1080           4 :     StyleContainer::Style aStyle( "style:page-layout", aPageProps);
    1081           4 :     StyleContainer::Style aSubStyle( "style:page-layout-properties", aPageLayoutProps);
    1082           2 :     aStyle.SubStyles.push_back(&aSubStyle);
    1083           2 :     sal_Int32 nPageStyle = m_rStyleContainer.impl_getStyleId( aStyle, false );
    1084             : 
    1085             :     // create master page
    1086           4 :     OUString aMasterPageLayoutName = m_rStyleContainer.getStyleName( nPageStyle );
    1087           2 :     aPageProps[ "style:page-layout-name" ] = aMasterPageLayoutName;
    1088             : 
    1089           4 :     StyleContainer::Style aMPStyle( "style:master-page", aPageProps);
    1090             : 
    1091           4 :     StyleContainer::Style aHeaderStyle( "style:header", PropertyMap() );
    1092           4 :     StyleContainer::Style aFooterStyle( "style:footer", PropertyMap() );
    1093             : 
    1094           2 :     elem.StyleId = m_rStyleContainer.impl_getStyleId( aMPStyle,false );
    1095             : 
    1096             :     // create styles for children
    1097           4 :     elem.applyToChildren(*this);
    1098           2 : }
    1099             : 
    1100           2 : void DrawXmlFinalizer::visit( DocumentElement& elem, const std::list< Element* >::const_iterator& )
    1101             : {
    1102           2 :     elem.applyToChildren(*this);
    1103           2 : }
    1104             : 
    1105             : }
    1106             : 
    1107             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10