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

Generated by: LCOV version 1.10