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

Generated by: LCOV version 1.10