LCOV - code coverage report
Current view: top level - sdext/source/pdfimport/tree - writertreevisiting.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 407 646 63.0 %
Date: 2012-08-25 Functions: 22 28 78.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 478 1398 34.2 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*************************************************************************
       3                 :            :  *
       4                 :            :  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       5                 :            :  *
       6                 :            :  * Copyright 2000, 2010 Oracle and/or its affiliates.
       7                 :            :  *
       8                 :            :  * OpenOffice.org - a multi-platform office productivity suite
       9                 :            :  *
      10                 :            :  * This file is part of OpenOffice.org.
      11                 :            :  *
      12                 :            :  * OpenOffice.org is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU Lesser General Public License version 3
      14                 :            :  * only, as published by the Free Software Foundation.
      15                 :            :  *
      16                 :            :  * OpenOffice.org is distributed in the hope that it will be useful,
      17                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19                 :            :  * GNU Lesser General Public License version 3 for more details
      20                 :            :  * (a copy is included in the LICENSE file that accompanied this code).
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU Lesser General Public License
      23                 :            :  * version 3 along with OpenOffice.org.  If not, see
      24                 :            :  * <http://www.openoffice.org/license.html>
      25                 :            :  * for a copy of the LGPLv3 License.
      26                 :            :  *
      27                 :            :  ************************************************************************/
      28                 :            : 
      29                 :            : 
      30                 :            : #include "pdfiprocessor.hxx"
      31                 :            : #include "xmlemitter.hxx"
      32                 :            : #include "pdfihelper.hxx"
      33                 :            : #include "imagecontainer.hxx"
      34                 :            : #include "style.hxx"
      35                 :            : #include "writertreevisiting.hxx"
      36                 :            : #include "genericelements.hxx"
      37                 :            : 
      38                 :            : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      39                 :            : #include <basegfx/range/b2drange.hxx>
      40                 :            : 
      41                 :            : 
      42                 :            : namespace pdfi
      43                 :            : {
      44                 :            : 
      45                 :          0 : void WriterXmlEmitter::visit( HyperlinkElement& elem, const std::list< Element* >::const_iterator&   )
      46                 :            : {
      47         [ #  # ]:          0 :     if( elem.Children.empty() )
      48                 :          0 :         return;
      49                 :            : 
      50 [ #  # ][ #  # ]:          0 :     const char* pType = dynamic_cast<DrawElement*>(elem.Children.front()) ? "draw:a" : "text:a";
                 [ #  # ]
      51                 :            : 
      52         [ #  # ]:          0 :     PropertyMap aProps;
      53 [ #  # ][ #  # ]:          0 :     aProps[ USTR( "xlink:type" ) ] = USTR( "simple" );
                 [ #  # ]
      54 [ #  # ][ #  # ]:          0 :     aProps[ USTR( "xlink:href" ) ] = elem.URI;
      55 [ #  # ][ #  # ]:          0 :     aProps[ USTR( "office:target-frame-name" ) ] = USTR( "_blank" );
                 [ #  # ]
      56 [ #  # ][ #  # ]:          0 :     aProps[ USTR( "xlink:show" ) ] = USTR( "new" );
                 [ #  # ]
      57                 :            : 
      58         [ #  # ]:          0 :     m_rEmitContext.rEmitter.beginTag( pType, aProps );
      59                 :          0 :     std::list< Element* >::iterator this_it =  elem.Children.begin();
      60 [ #  # ][ #  # ]:          0 :     while( this_it !=elem.Children.end() && *this_it != &elem )
         [ #  # ][ #  # ]
      61                 :            :     {
      62         [ #  # ]:          0 :         (*this_it)->visitedBy( *this, this_it );
      63                 :          0 :         ++this_it;
      64                 :            :     }
      65 [ #  # ][ #  # ]:          0 :     m_rEmitContext.rEmitter.endTag( pType );
      66                 :            : }
      67                 :            : 
      68                 :         66 : void WriterXmlEmitter::visit( TextElement& elem, const std::list< Element* >::const_iterator&   )
      69                 :            : {
      70         [ +  + ]:         66 :     if( ! elem.Text.getLength() )
      71                 :         66 :         return;
      72                 :            : 
      73         [ +  - ]:         33 :     PropertyMap aProps;
      74         [ +  - ]:         33 :     if( elem.StyleId != -1 )
      75                 :            :     {
      76 [ +  - ][ +  - ]:         66 :         aProps[ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "text:style-name" ) ) ] =
      77         [ +  - ]:         99 :             m_rEmitContext.rStyles.getStyleName( elem.StyleId );
      78                 :            :     }
      79                 :            : 
      80         [ +  - ]:         33 :     m_rEmitContext.rEmitter.beginTag( "text:span", aProps );
      81 [ +  - ][ +  - ]:         33 :     m_rEmitContext.rEmitter.write( elem.Text.makeStringAndClear() );
      82                 :         33 :     std::list< Element* >::iterator this_it =  elem.Children.begin();
      83 [ -  + ][ #  # ]:         33 :     while( this_it !=elem.Children.end() && *this_it != &elem )
         [ +  - ][ -  + ]
      84                 :            :     {
      85         [ #  # ]:          0 :         (*this_it)->visitedBy( *this, this_it );
      86                 :          0 :         ++this_it;
      87                 :            :     }
      88                 :            : 
      89 [ +  - ][ +  - ]:         66 :     m_rEmitContext.rEmitter.endTag( "text:span" );
      90                 :            : }
      91                 :            : 
      92                 :         69 : void WriterXmlEmitter::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator&   )
      93                 :            : {
      94         [ +  - ]:         69 :     PropertyMap aProps;
      95         [ +  + ]:         69 :     if( elem.StyleId != -1 )
      96                 :            :     {
      97 [ +  - ][ +  - ]:          3 :         aProps[ USTR( "text:style-name" ) ] = m_rEmitContext.rStyles.getStyleName( elem.StyleId );
                 [ +  - ]
      98                 :            :     }
      99                 :         69 :     const char* pTagType = "text:p";
     100         [ -  + ]:         69 :     if( elem.Type == elem.Headline )
     101                 :          0 :         pTagType = "text:h";
     102         [ +  - ]:         69 :     m_rEmitContext.rEmitter.beginTag( pTagType, aProps );
     103                 :            : 
     104                 :         69 :     std::list< Element* >::iterator this_it =  elem.Children.begin();
     105 [ +  + ][ +  - ]:        135 :     while( this_it !=elem.Children.end() && *this_it != &elem )
         [ +  - ][ +  + ]
     106                 :            :     {
     107         [ +  - ]:         66 :         (*this_it)->visitedBy( *this, this_it );
     108                 :         66 :         ++this_it;
     109                 :            :     }
     110                 :            : 
     111 [ +  - ][ +  - ]:         69 :     m_rEmitContext.rEmitter.endTag( pTagType );
     112                 :         69 : }
     113                 :            : 
     114                 :         84 : void WriterXmlEmitter::fillFrameProps( DrawElement&       rElem,
     115                 :            :                                        PropertyMap&       rProps,
     116                 :            :                                        const EmitContext& rEmitContext )
     117                 :            : {
     118                 :         84 :     double rel_x = rElem.x, rel_y = rElem.y;
     119                 :            : 
     120                 :            :     // find anchor type by recursing though parents
     121                 :         84 :     Element* pAnchor = rElem.Parent;
     122 [ +  - ][ +  - ]:        252 :     while( pAnchor &&
         [ +  - ][ -  + ]
     123         [ +  - ]:         84 :            ! dynamic_cast<ParagraphElement*>(pAnchor) &&
     124         [ -  + ]:         84 :            ! dynamic_cast<PageElement*>(pAnchor) )
     125                 :            :     {
     126                 :          0 :         pAnchor = pAnchor->Parent;
     127                 :            :     }
     128         [ +  - ]:         84 :     if( pAnchor )
     129                 :            :     {
     130 [ +  - ][ -  + ]:         84 :         if( dynamic_cast<ParagraphElement*>(pAnchor) )
                 [ -  + ]
     131                 :            :         {
     132 [ #  # ][ #  # ]:          0 :             rProps[ USTR( "text:anchor-type" ) ] =
     133         [ #  # ]:          0 :                 rElem.isCharacter ? USTR( "character" ) : USTR( "paragraph" );
     134                 :            :         }
     135                 :            :         else
     136                 :            :         {
     137         [ -  + ]:         84 :             PageElement* pPage = dynamic_cast<PageElement*>(pAnchor);
     138 [ +  - ][ +  - ]:         84 :             rProps[ USTR( "text:anchor-type" ) ] = USTR( "page" );
     139 [ +  - ][ +  - ]:         84 :             rProps[ USTR( "text:anchor-page-number" ) ] = rtl::OUString::valueOf(pPage->PageNumber);
     140                 :            :         }
     141                 :         84 :         rel_x -= pAnchor->x;
     142                 :         84 :         rel_y -= pAnchor->y;
     143                 :            :     }
     144                 :            : 
     145 [ +  - ][ +  - ]:         84 :     rProps[ USTR( "draw:z-index" ) ] = rtl::OUString::valueOf( rElem.ZOrder );
     146 [ +  - ][ +  - ]:         84 :     rProps[ USTR( "draw:style-name" )] = rEmitContext.rStyles.getStyleName( rElem.StyleId );
     147 [ +  - ][ +  - ]:         84 :     rProps[ USTR( "svg:width" ) ]   = convertPixelToUnitString( rElem.w );
     148 [ +  - ][ +  - ]:         84 :     rProps[ USTR( "svg:height" ) ]  = convertPixelToUnitString( rElem.h );
     149                 :            : 
     150                 :            :     const GraphicsContext& rGC =
     151                 :         84 :         rEmitContext.rProcessor.getGraphicsContext( rElem.GCId );
     152         [ -  + ]:         84 :     if( rGC.Transformation.isIdentity() )
     153                 :            :     {
     154         [ #  # ]:          0 :         if( !rElem.isCharacter )
     155                 :            :         {
     156 [ #  # ][ #  # ]:          0 :             rProps[ USTR( "svg:x" ) ]       = convertPixelToUnitString( rel_x );
     157 [ #  # ][ #  # ]:          0 :             rProps[ USTR( "svg:y" ) ]       = convertPixelToUnitString( rel_y );
     158                 :            :         }
     159                 :            :     }
     160                 :            :     else
     161                 :            :     {
     162                 :         84 :         basegfx::B2DTuple aScale, aTranslation;
     163                 :            :         double fRotate, fShearX;
     164                 :            : 
     165         [ +  - ]:         84 :         rGC.Transformation.decompose( aScale, aTranslation, fRotate, fShearX );
     166                 :            : 
     167                 :         84 :         rtl::OUStringBuffer aBuf( 256 );
     168                 :            : 
     169                 :            :         // TODO(F2): general transformation case missing; if implemented, note
     170                 :            :         // that ODF rotation is oriented the other way
     171                 :            : 
     172                 :            :         // build transformation string
     173         [ -  + ]:         84 :         if( fShearX != 0.0 )
     174                 :            :         {
     175         [ #  # ]:          0 :             aBuf.appendAscii( "skewX( " );
     176         [ #  # ]:          0 :             aBuf.append( fShearX );
     177         [ #  # ]:          0 :             aBuf.appendAscii( " )" );
     178                 :            :         }
     179         [ -  + ]:         84 :         if( fRotate != 0.0 )
     180                 :            :         {
     181         [ #  # ]:          0 :             if( aBuf.getLength() > 0 )
     182         [ #  # ]:          0 :                 aBuf.append( sal_Unicode(' ') );
     183         [ #  # ]:          0 :             aBuf.appendAscii( "rotate( " );
     184         [ #  # ]:          0 :             aBuf.append( -fRotate );
     185         [ #  # ]:          0 :             aBuf.appendAscii( " )" );
     186                 :            : 
     187                 :            :         }
     188         [ +  - ]:         84 :         if( ! rElem.isCharacter )
     189                 :            :         {
     190         [ -  + ]:         84 :             if( aBuf.getLength() > 0 )
     191         [ #  # ]:          0 :                 aBuf.append( sal_Unicode(' ') );
     192         [ +  - ]:         84 :             aBuf.appendAscii( "translate( " );
     193 [ +  - ][ +  - ]:         84 :             aBuf.append( convertPixelToUnitString( rel_x ) );
     194         [ +  - ]:         84 :             aBuf.append( sal_Unicode(' ') );
     195 [ +  - ][ +  - ]:         84 :             aBuf.append( convertPixelToUnitString( rel_y ) );
     196         [ +  - ]:         84 :             aBuf.appendAscii( " )" );
     197                 :            :          }
     198                 :            : 
     199 [ +  - ][ +  - ]:         84 :         rProps[ USTR( "draw:transform" ) ] = aBuf.makeStringAndClear();
                 [ +  - ]
     200                 :            :     }
     201                 :         84 : }
     202                 :            : 
     203                 :         66 : void WriterXmlEmitter::visit( FrameElement& elem, const std::list< Element* >::const_iterator&   )
     204                 :            : {
     205         [ +  - ]:         66 :     if( elem.Children.empty() )
     206                 :         66 :         return;
     207                 :            : 
     208 [ +  - ][ +  - ]:         66 :     bool bTextBox = (dynamic_cast<ParagraphElement*>(elem.Children.front()) != NULL);
                 [ +  - ]
     209         [ +  - ]:         66 :     PropertyMap aFrameProps;
     210         [ +  - ]:         66 :     fillFrameProps( elem, aFrameProps, m_rEmitContext );
     211         [ +  - ]:         66 :     m_rEmitContext.rEmitter.beginTag( "draw:frame", aFrameProps );
     212         [ +  - ]:         66 :     if( bTextBox )
     213 [ +  - ][ +  - ]:         66 :         m_rEmitContext.rEmitter.beginTag( "draw:text-box", PropertyMap() );
                 [ +  - ]
     214                 :            : 
     215                 :         66 :     std::list< Element* >::iterator this_it =  elem.Children.begin();
     216 [ +  + ][ +  - ]:        132 :     while( this_it !=elem.Children.end() && *this_it != &elem )
         [ +  - ][ +  + ]
     217                 :            :     {
     218         [ +  - ]:         66 :         (*this_it)->visitedBy( *this, this_it );
     219                 :         66 :         ++this_it;
     220                 :            :     }
     221                 :            : 
     222         [ +  - ]:         66 :     if( bTextBox )
     223         [ +  - ]:         66 :         m_rEmitContext.rEmitter.endTag( "draw:text-box" );
     224 [ +  - ][ +  - ]:         66 :     m_rEmitContext.rEmitter.endTag( "draw:frame" );
     225                 :            : }
     226                 :            : 
     227                 :         18 : void WriterXmlEmitter::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& )
     228                 :            : {
     229         [ +  - ]:         18 :     elem.updateGeometry();
     230                 :            :     /* note:
     231                 :            :      *   aw recommends using 100dth of mm in all respects since the xml import
     232                 :            :      *   (a) is buggy (see issue 37213)
     233                 :            :      *   (b) is optimized for 100dth of mm and does not scale itself then,
     234                 :            :      *       this does not gain us speed but makes for smaller rounding errors since
     235                 :            :      *       the xml importer coordinates are integer based
     236                 :            :      */
     237 [ +  - ][ +  + ]:         36 :     for (sal_uInt32 i = 0; i< elem.PolyPoly.count(); i++)
     238                 :            :     {
     239         [ +  - ]:         18 :         basegfx::B2DPolygon b2dPolygon;
     240 [ +  - ][ +  - ]:         18 :         b2dPolygon =  elem.PolyPoly.getB2DPolygon( i );
                 [ +  - ]
     241                 :            : 
     242 [ +  - ][ +  + ]:         72 :         for ( sal_uInt32 j = 0; j< b2dPolygon.count(); j++ )
     243                 :            :         {
     244                 :         54 :             basegfx::B2DPoint point;
     245                 :         54 :             basegfx::B2DPoint nextPoint;
     246         [ +  - ]:         54 :             point = b2dPolygon.getB2DPoint( j );
     247                 :            : 
     248                 :         54 :             basegfx::B2DPoint prevPoint;
     249         [ +  - ]:         54 :             prevPoint = b2dPolygon.getPrevControlPoint( j ) ;
     250                 :            : 
     251                 :         54 :             point.setX( convPx2mmPrec2( point.getX() )*100.0 );
     252                 :         54 :             point.setY( convPx2mmPrec2( point.getY() )*100.0 );
     253                 :            : 
     254 [ +  + ][ +  - ]:         54 :             if ( b2dPolygon.isPrevControlPointUsed( j ) )
     255                 :            :             {
     256                 :         24 :                 prevPoint.setX( convPx2mmPrec2( prevPoint.getX() )*100.0 );
     257                 :         24 :                 prevPoint.setY( convPx2mmPrec2( prevPoint.getY() )*100.0 );
     258                 :            :             }
     259                 :            : 
     260 [ +  - ][ +  + ]:         54 :             if ( b2dPolygon.isNextControlPointUsed( j ) )
     261                 :            :             {
     262         [ +  - ]:         24 :                 nextPoint = b2dPolygon.getNextControlPoint( j ) ;
     263                 :         24 :                 nextPoint.setX( convPx2mmPrec2( nextPoint.getX() )*100.0 );
     264                 :         24 :                 nextPoint.setY( convPx2mmPrec2( nextPoint.getY() )*100.0 );
     265                 :            :             }
     266                 :            : 
     267         [ +  - ]:         54 :             b2dPolygon.setB2DPoint( j, point );
     268                 :            : 
     269 [ +  - ][ +  + ]:         54 :             if ( b2dPolygon.isPrevControlPointUsed( j ) )
     270         [ +  - ]:         24 :                 b2dPolygon.setPrevControlPoint( j , prevPoint ) ;
     271                 :            : 
     272 [ +  - ][ +  + ]:         54 :             if ( b2dPolygon.isNextControlPointUsed( j ) )
     273         [ +  - ]:         24 :                 b2dPolygon.setNextControlPoint( j , nextPoint ) ;
     274                 :         54 :         }
     275                 :            : 
     276         [ +  - ]:         18 :         elem.PolyPoly.setB2DPolygon( i, b2dPolygon );
     277         [ +  - ]:         18 :     }
     278                 :            : 
     279         [ +  - ]:         18 :     PropertyMap aProps;
     280         [ +  - ]:         18 :     fillFrameProps( elem, aProps, m_rEmitContext );
     281                 :         18 :     rtl::OUStringBuffer aBuf( 64 );
     282         [ +  - ]:         18 :     aBuf.appendAscii( "0 0 " );
     283         [ +  - ]:         18 :     aBuf.append( convPx2mmPrec2(elem.w)*100.0 );
     284         [ +  - ]:         18 :     aBuf.append( sal_Unicode(' ') );
     285         [ +  - ]:         18 :     aBuf.append( convPx2mmPrec2(elem.h)*100.0 );
     286 [ +  - ][ +  - ]:         18 :     aProps[ USTR( "svg:viewBox" ) ] = aBuf.makeStringAndClear();
                 [ +  - ]
     287 [ +  - ][ +  - ]:         18 :     aProps[ USTR( "svg:d" ) ]       = basegfx::tools::exportToSvgD( elem.PolyPoly );
                 [ +  - ]
     288                 :            : 
     289         [ +  - ]:         18 :     m_rEmitContext.rEmitter.beginTag( "draw:path", aProps );
     290 [ +  - ][ +  - ]:         18 :     m_rEmitContext.rEmitter.endTag( "draw:path" );
     291                 :         18 : }
     292                 :            : 
     293                 :          0 : void WriterXmlEmitter::visit( ImageElement& elem, const std::list< Element* >::const_iterator& )
     294                 :            : {
     295         [ #  # ]:          0 :     PropertyMap aImageProps;
     296         [ #  # ]:          0 :     m_rEmitContext.rEmitter.beginTag( "draw:image", aImageProps );
     297 [ #  # ][ #  # ]:          0 :     m_rEmitContext.rEmitter.beginTag( "office:binary-data", PropertyMap() );
                 [ #  # ]
     298         [ #  # ]:          0 :     m_rEmitContext.rImages.writeBase64EncodedStream( elem.Image, m_rEmitContext);
     299         [ #  # ]:          0 :     m_rEmitContext.rEmitter.endTag( "office:binary-data" );
     300 [ #  # ][ #  # ]:          0 :     m_rEmitContext.rEmitter.endTag( "draw:image" );
     301                 :          0 : }
     302                 :            : 
     303                 :          3 : void WriterXmlEmitter::visit( PageElement& elem, const std::list< Element* >::const_iterator&   )
     304                 :            : {
     305         [ -  + ]:          3 :     if( m_rEmitContext.xStatusIndicator.is() )
     306 [ #  # ][ #  # ]:          0 :         m_rEmitContext.xStatusIndicator->setValue( elem.PageNumber );
     307                 :            : 
     308                 :          3 :     std::list< Element* >::iterator this_it =  elem.Children.begin();
     309 [ +  + ][ +  - ]:         48 :     while( this_it !=elem.Children.end() && *this_it != &elem )
         [ +  - ][ +  + ]
     310                 :            :     {
     311         [ +  - ]:         45 :         (*this_it)->visitedBy( *this, this_it );
     312                 :         45 :         ++this_it;
     313                 :            :     }
     314                 :          3 : }
     315                 :            : 
     316                 :          3 : void WriterXmlEmitter::visit( DocumentElement& elem, const std::list< Element* >::const_iterator&)
     317                 :            : {
     318 [ +  - ][ +  - ]:          3 :     m_rEmitContext.rEmitter.beginTag( "office:body", PropertyMap() );
                 [ +  - ]
     319 [ +  - ][ +  - ]:          3 :     m_rEmitContext.rEmitter.beginTag( "office:text", PropertyMap() );
                 [ +  - ]
     320                 :            : 
     321         [ +  + ]:          6 :     for( std::list< Element* >::iterator it = elem.Children.begin(); it != elem.Children.end(); ++it )
     322                 :            :     {
     323         [ -  + ]:          3 :         PageElement* pPage = dynamic_cast<PageElement*>(*it);
     324         [ +  - ]:          3 :         if( pPage )
     325                 :            :         {
     326                 :            :             // emit only page anchored objects
     327                 :            :             // currently these are only DrawElement types
     328         [ +  + ]:         48 :             for( std::list< Element* >::iterator child_it = pPage->Children.begin(); child_it != pPage->Children.end(); ++child_it )
     329                 :            :             {
     330 [ +  - ][ +  + ]:         45 :                 if( dynamic_cast<DrawElement*>(*child_it) != NULL )
                 [ +  + ]
     331         [ +  - ]:         42 :                     (*child_it)->visitedBy( *this, child_it );
     332                 :            :             }
     333                 :            :         }
     334                 :            :     }
     335                 :            : 
     336                 :            :     // do not emit page anchored objects, they are emitted before
     337                 :            :     // (must precede all pages in writer document) currently these are
     338                 :            :     // only DrawElement types
     339         [ +  + ]:          6 :     for( std::list< Element* >::iterator it = elem.Children.begin(); it != elem.Children.end(); ++it )
     340                 :            :     {
     341 [ +  - ][ +  - ]:          3 :         if( dynamic_cast<DrawElement*>(*it) == NULL )
                 [ +  - ]
     342         [ +  - ]:          3 :             (*it)->visitedBy( *this, it );
     343                 :            :     }
     344                 :            : 
     345                 :          3 :     m_rEmitContext.rEmitter.endTag( "office:text" );
     346                 :          3 :     m_rEmitContext.rEmitter.endTag( "office:body" );
     347                 :          3 : }
     348                 :            : 
     349                 :            : /////////////////////////////////////////////////////////////////
     350                 :            : 
     351                 :          0 : void WriterXmlOptimizer::visit( HyperlinkElement&, const std::list< Element* >::const_iterator& )
     352                 :            : {
     353                 :          0 : }
     354                 :            : 
     355                 :         33 : void WriterXmlOptimizer::visit( TextElement&, const std::list< Element* >::const_iterator&)
     356                 :            : {
     357                 :         33 : }
     358                 :            : 
     359                 :         33 : void WriterXmlOptimizer::visit( FrameElement& elem, const std::list< Element* >::const_iterator& )
     360                 :            : {
     361                 :         33 :     elem.applyToChildren(*this);
     362                 :         33 : }
     363                 :            : 
     364                 :          0 : void WriterXmlOptimizer::visit( ImageElement&, const std::list< Element* >::const_iterator& )
     365                 :            : {
     366                 :          0 : }
     367                 :            : 
     368                 :          9 : void WriterXmlOptimizer::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& )
     369                 :            : {
     370                 :            :     /* note: optimize two consecutive PolyPolyElements that
     371                 :            :      *  have the same path but one of which is a stroke while
     372                 :            :      *     the other is a fill
     373                 :            :      */
     374         [ +  - ]:          9 :     if( elem.Parent )
     375                 :            :     {
     376                 :            :         // find following PolyPolyElement in parent's children list
     377                 :          9 :         std::list< Element* >::iterator this_it = elem.Parent->Children.begin();
     378 [ +  - ][ +  + ]:         54 :         while( this_it != elem.Parent->Children.end() && *this_it != &elem )
         [ +  - ][ +  + ]
     379                 :         45 :             ++this_it;
     380                 :            : 
     381         [ +  - ]:          9 :         if( this_it != elem.Parent->Children.end() )
     382                 :            :         {
     383                 :          9 :             std::list< Element* >::iterator next_it = this_it;
     384         [ +  - ]:          9 :             if( ++next_it != elem.Parent->Children.end() )
     385                 :            :             {
     386         [ -  + ]:          9 :                 PolyPolyElement* pNext = dynamic_cast<PolyPolyElement*>(*next_it);
     387 [ +  + ][ +  - ]:          9 :                 if( pNext && pNext->PolyPoly == elem.PolyPoly )
         [ -  + ][ -  + ]
     388                 :            :                 {
     389                 :            :                     const GraphicsContext& rNextGC =
     390         [ #  # ]:          0 :                         m_rProcessor.getGraphicsContext( pNext->GCId );
     391                 :            :                     const GraphicsContext& rThisGC =
     392         [ #  # ]:          0 :                         m_rProcessor.getGraphicsContext( elem.GCId );
     393                 :            : 
     394 [ #  # ][ #  # ]:          0 :                     if( rThisGC.BlendMode      == rNextGC.BlendMode &&
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     395                 :            :                         rThisGC.Flatness       == rNextGC.Flatness &&
     396         [ #  # ]:          0 :                         rThisGC.Transformation == rNextGC.Transformation &&
     397         [ #  # ]:          0 :                         rThisGC.Clip           == rNextGC.Clip &&
     398                 :            :                         pNext->Action          == PATH_STROKE &&
     399                 :            :                         (elem.Action == PATH_FILL || elem.Action == PATH_EOFILL) )
     400                 :            :                     {
     401         [ #  # ]:          0 :                         GraphicsContext aGC = rThisGC;
     402                 :          0 :                         aGC.LineJoin  = rNextGC.LineJoin;
     403                 :          0 :                         aGC.LineCap   = rNextGC.LineCap;
     404                 :          0 :                         aGC.LineWidth = rNextGC.LineWidth;
     405                 :          0 :                         aGC.MiterLimit= rNextGC.MiterLimit;
     406         [ #  # ]:          0 :                         aGC.DashArray = rNextGC.DashArray;
     407                 :          0 :                         aGC.LineColor = rNextGC.LineColor;
     408         [ #  # ]:          0 :                         elem.GCId = m_rProcessor.getGCId( aGC );
     409                 :            : 
     410                 :          0 :                         elem.Action |= pNext->Action;
     411                 :            : 
     412         [ #  # ]:          0 :                         elem.Children.splice( elem.Children.end(), pNext->Children );
     413         [ #  # ]:          0 :                         elem.Parent->Children.erase( next_it );
     414 [ #  # ][ #  # ]:          9 :                         delete pNext;
                 [ #  # ]
     415                 :            :                     }
     416                 :            :                 }
     417                 :            :             }
     418                 :            :         }
     419                 :            :     }
     420                 :          9 : }
     421                 :            : 
     422                 :         33 : void WriterXmlOptimizer::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator& rParentIt)
     423                 :            : {
     424                 :         33 :     optimizeTextElements( elem );
     425                 :            : 
     426                 :         33 :     elem.applyToChildren(*this);
     427                 :            : 
     428 [ +  - ][ +  - ]:         33 :     if( elem.Parent && rParentIt != elem.Parent->Children.end() )
         [ +  - ][ +  - ]
                 [ +  - ]
     429                 :            :     {
     430                 :            :         // find if there is a previous paragraph that might be a heading for this one
     431                 :         33 :         std::list<Element*>::const_iterator prev = rParentIt;
     432                 :         33 :         ParagraphElement* pPrevPara = NULL;
     433         [ -  + ]:         33 :         while( prev != elem.Parent->Children.begin() )
     434                 :            :         {
     435                 :          0 :             --prev;
     436         [ #  # ]:          0 :             pPrevPara = dynamic_cast< ParagraphElement* >(*prev);
     437         [ #  # ]:          0 :             if( pPrevPara )
     438                 :            :             {
     439                 :            :                 /* What constitutes a heading ? current hints are:
     440                 :            :                  * - one line only
     441                 :            :                  * - not too far away from this paragraph (two heading height max ?)
     442                 :            :                  * - font larger or bold
     443                 :            :                  * this is of course incomplete
     444                 :            :                  * FIXME: improve hints for heading
     445                 :            :                  */
     446                 :            :                 // check for single line
     447 [ #  # ][ #  # ]:          0 :                 if( pPrevPara->isSingleLined( m_rProcessor ) )
     448                 :            :                 {
     449         [ #  # ]:          0 :                     double head_line_height = pPrevPara->getLineHeight( m_rProcessor );
     450         [ #  # ]:          0 :                     if( pPrevPara->y + pPrevPara->h + 2*head_line_height > elem.y )
     451                 :            :                     {
     452                 :            :                         // check for larger font
     453 [ #  # ][ #  # ]:          0 :                         if( head_line_height > elem.getLineHeight( m_rProcessor ) )
     454                 :            :                         {
     455                 :          0 :                             pPrevPara->Type = elem.Headline;
     456                 :            :                         }
     457                 :            :                         else
     458                 :            :                         {
     459                 :            :                             // check whether text of pPrevPara is bold (at least first text element)
     460                 :            :                             // and this para is not bold (dito)
     461         [ #  # ]:          0 :                             TextElement* pPrevText = pPrevPara->getFirstTextChild();
     462         [ #  # ]:          0 :                             TextElement* pThisText = elem.getFirstTextChild();
     463 [ #  # ][ #  # ]:          0 :                             if( pPrevText && pThisText )
     464                 :            :                             {
     465         [ #  # ]:          0 :                                 const FontAttributes& rPrevFont = m_rProcessor.getFont( pPrevText->FontId );
     466         [ #  # ]:          0 :                                 const FontAttributes& rThisFont = m_rProcessor.getFont( pThisText->FontId );
     467 [ #  # ][ #  # ]:          0 :                                 if( rPrevFont.isBold && ! rThisFont.isBold )
     468                 :          0 :                                     pPrevPara->Type = elem.Headline;
     469                 :            :                             }
     470                 :            :                         }
     471                 :            :                     }
     472                 :            :                 }
     473                 :          0 :                 break;
     474                 :            :             }
     475                 :            :         }
     476                 :            :     }
     477                 :         33 : }
     478                 :            : 
     479                 :          3 : void WriterXmlOptimizer::visit( PageElement& elem, const std::list< Element* >::const_iterator& )
     480                 :            : {
     481         [ -  + ]:          3 :     if( m_rProcessor.getStatusIndicator().is() )
     482 [ #  # ][ #  # ]:          0 :         m_rProcessor.getStatusIndicator()->setValue( elem.PageNumber );
     483                 :            : 
     484                 :            :     // resolve hyperlinks
     485         [ +  - ]:          3 :     elem.resolveHyperlinks();
     486                 :            : 
     487         [ +  - ]:          3 :     elem.resolveFontStyles( m_rProcessor ); // underlines and such
     488                 :            : 
     489                 :            :     // FIXME: until hyperlinks and font effects are adjusted for
     490                 :            :     // geometrical search handle them before sorting
     491         [ +  - ]:          3 :     m_rProcessor.sortElements( &elem );
     492                 :            : 
     493                 :            :     // find paragraphs in text
     494                 :          3 :     ParagraphElement* pCurPara = NULL;
     495                 :          3 :     std::list< Element* >::iterator page_element, next_page_element;
     496                 :          3 :     next_page_element = elem.Children.begin();
     497                 :          3 :     double fCurLineHeight = 0.0; // average height of text items in current para
     498                 :          3 :     int nCurLineElements = 0; // number of line contributing elements in current para
     499                 :          3 :     double line_left = elem.w, line_right = 0.0;
     500                 :          3 :     double column_width = elem.w*0.75; // estimate text width
     501                 :            :     // TODO: guess columns
     502         [ +  + ]:         45 :     while( next_page_element != elem.Children.end() )
     503                 :            :     {
     504                 :         42 :         page_element = next_page_element++;
     505         [ -  + ]:         42 :         ParagraphElement* pPagePara = dynamic_cast<ParagraphElement*>(*page_element);
     506         [ -  + ]:         42 :         if( pPagePara )
     507                 :            :         {
     508                 :          0 :             pCurPara = pPagePara;
     509                 :            :             // adjust line height and text items
     510                 :          0 :             fCurLineHeight = 0.0;
     511                 :          0 :             nCurLineElements = 0;
     512         [ #  # ]:          0 :             for( std::list< Element* >::iterator it = pCurPara->Children.begin();
     513                 :          0 :                  it != pCurPara->Children.end(); ++it )
     514                 :            :             {
     515         [ #  # ]:          0 :                 TextElement* pTestText = dynamic_cast<TextElement*>(*it);
     516         [ #  # ]:          0 :                 if( pTestText )
     517                 :            :                 {
     518                 :          0 :                     fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pTestText->h)/double(nCurLineElements+1);
     519                 :          0 :                     nCurLineElements++;
     520                 :            :                 }
     521                 :            :             }
     522                 :          0 :             continue;
     523                 :            :         }
     524                 :            : 
     525         [ -  + ]:         42 :         HyperlinkElement* pLink = dynamic_cast<HyperlinkElement*>(*page_element);
     526         [ -  + ]:         42 :         DrawElement* pDraw = dynamic_cast<DrawElement*>(*page_element);
     527 [ -  + ][ #  # ]:         42 :         if( ! pDraw && pLink && ! pLink->Children.empty() )
         [ #  # ][ -  + ]
     528 [ #  # ][ #  # ]:          0 :             pDraw = dynamic_cast<DrawElement*>(pLink->Children.front() );
     529         [ +  - ]:         42 :         if( pDraw )
     530                 :            :         {
     531                 :            :             // insert small drawing objects as character, else leave them page bound
     532                 :            : 
     533                 :         42 :             bool bInsertToParagraph = false;
     534                 :            :             // first check if this is either inside the paragraph
     535 [ -  + ][ #  # ]:         42 :             if( pCurPara && pDraw->y < pCurPara->y + pCurPara->h )
     536                 :            :             {
     537         [ #  # ]:          0 :                 if( pDraw->h < fCurLineHeight * 1.5 )
     538                 :            :                 {
     539                 :          0 :                     bInsertToParagraph = true;
     540                 :          0 :                     fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pDraw->h)/double(nCurLineElements+1);
     541                 :          0 :                     nCurLineElements++;
     542                 :            :                     // mark draw element as character
     543                 :          0 :                     pDraw->isCharacter = true;
     544                 :            :                 }
     545                 :            :             }
     546                 :            :             // or perhaps the draw element begins a new paragraph
     547         [ +  + ]:         42 :             else if( next_page_element != elem.Children.end() )
     548                 :            :             {
     549         [ -  + ]:         39 :                 TextElement* pText = dynamic_cast<TextElement*>(*next_page_element);
     550         [ +  - ]:         39 :                 if( ! pText )
     551                 :            :                 {
     552         [ -  + ]:         39 :                     ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(*next_page_element);
     553 [ -  + ][ #  # ]:         39 :                     if( pPara && ! pPara->Children.empty() )
                 [ -  + ]
     554 [ #  # ][ #  # ]:          0 :                         pText = dynamic_cast<TextElement*>(pPara->Children.front());
     555                 :            :                 }
     556 [ -  + ][ #  # ]:         39 :                 if( pText && // check there is a text
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     557                 :            :                     pDraw->h < pText->h*1.5 && // and it is approx the same height
     558                 :            :                     // and either upper or lower edge of pDraw is inside text's vertical range
     559                 :            :                     ( ( pDraw->y >= pText->y && pDraw->y <= pText->y+pText->h ) ||
     560                 :            :                       ( pDraw->y+pDraw->h >= pText->y && pDraw->y+pDraw->h <= pText->y+pText->h )
     561                 :            :                       )
     562                 :            :                     )
     563                 :            :                 {
     564                 :          0 :                     bInsertToParagraph = true;
     565                 :          0 :                     fCurLineHeight = pDraw->h;
     566                 :          0 :                     nCurLineElements = 1;
     567                 :          0 :                     line_left = pDraw->x;
     568                 :          0 :                     line_right = pDraw->x + pDraw->w;
     569                 :            :                     // begin a new paragraph
     570                 :          0 :                     pCurPara = NULL;
     571                 :            :                     // mark draw element as character
     572                 :          0 :                     pDraw->isCharacter = true;
     573                 :            :                 }
     574                 :            :             }
     575                 :            : 
     576         [ +  - ]:         42 :             if( ! bInsertToParagraph )
     577                 :            :             {
     578                 :         42 :                 pCurPara = NULL;
     579                 :         42 :                 continue;
     580                 :            :             }
     581                 :            :         }
     582                 :            : 
     583         [ #  # ]:          0 :         TextElement* pText = dynamic_cast<TextElement*>(*page_element);
     584 [ #  # ][ #  # ]:          0 :         if( ! pText && pLink && ! pLink->Children.empty() )
         [ #  # ][ #  # ]
     585 [ #  # ][ #  # ]:          0 :             pText = dynamic_cast<TextElement*>(pLink->Children.front());
     586         [ #  # ]:          0 :         if( pText )
     587                 :            :         {
     588                 :            :             Element* pGeo = pLink ? static_cast<Element*>(pLink) :
     589         [ #  # ]:          0 :                                     static_cast<Element*>(pText);
     590         [ #  # ]:          0 :             if( pCurPara )
     591                 :            :             {
     592                 :            :                 // there was already a text element, check for a new paragraph
     593         [ #  # ]:          0 :                 if( nCurLineElements > 0 )
     594                 :            :                 {
     595                 :            :                     // if the new text is significantly distant from the paragraph
     596                 :            :                     // begin a new paragraph
     597         [ #  # ]:          0 :                     if( pGeo->y > pCurPara->y+pCurPara->h + fCurLineHeight*0.5 )
     598                 :          0 :                         pCurPara = NULL; // insert new paragraph
     599         [ #  # ]:          0 :                     else if( pGeo->y > (pCurPara->y+pCurPara->h - fCurLineHeight*0.05) )
     600                 :            :                     {
     601                 :            :                         // new paragraph if either the last line of the paragraph
     602                 :            :                         // was significantly shorter than the paragraph as a whole
     603         [ #  # ]:          0 :                         if( (line_right - line_left) < pCurPara->w*0.75 )
     604                 :          0 :                             pCurPara = NULL;
     605                 :            :                         // or the last line was significantly smaller than the column width
     606         [ #  # ]:          0 :                         else if( (line_right - line_left) < column_width*0.75 )
     607                 :          0 :                             pCurPara = NULL;
     608                 :            :                     }
     609                 :            :                 }
     610                 :            :             }
     611                 :            :             // update line height/width
     612         [ #  # ]:          0 :             if( pCurPara )
     613                 :            :             {
     614                 :          0 :                 fCurLineHeight = (fCurLineHeight*double(nCurLineElements) + pGeo->h)/double(nCurLineElements+1);
     615                 :          0 :                 nCurLineElements++;
     616         [ #  # ]:          0 :                 if( pGeo->x < line_left )
     617                 :          0 :                     line_left = pGeo->x;
     618         [ #  # ]:          0 :                 if( pGeo->x+pGeo->w > line_right )
     619                 :          0 :                     line_right = pGeo->x+pGeo->w;
     620                 :            :             }
     621                 :            :             else
     622                 :            :             {
     623                 :          0 :                 fCurLineHeight = pGeo->h;
     624                 :          0 :                 nCurLineElements = 1;
     625                 :          0 :                 line_left = pGeo->x;
     626                 :          0 :                 line_right = pGeo->x + pGeo->w;
     627                 :            :             }
     628                 :            :         }
     629                 :            : 
     630                 :            :         // move element to current paragraph
     631         [ #  # ]:          0 :         if( ! pCurPara ) // new paragraph, insert one
     632                 :            :         {
     633 [ #  # ][ #  # ]:          0 :             pCurPara = m_rProcessor.getElementFactory()->createParagraphElement( NULL );
                 [ #  # ]
     634                 :            :             // set parent
     635                 :          0 :             pCurPara->Parent = &elem;
     636                 :            :             //insert new paragraph before current element
     637         [ #  # ]:          0 :             page_element = elem.Children.insert( page_element, pCurPara );
     638                 :            :             // forward iterator to current element again
     639                 :          0 :             ++ page_element;
     640                 :            :             // update next_element which is now invalid
     641                 :          0 :             next_page_element = page_element;
     642                 :          0 :             ++ next_page_element;
     643                 :            :         }
     644                 :          0 :         Element* pCurEle = *page_element;
     645         [ #  # ]:          0 :         pCurEle->setParent( page_element, pCurPara );
     646                 :            :         OSL_ENSURE( !pText || pCurEle == pText || pCurEle == pLink, "paragraph child list in disorder" );
     647 [ #  # ][ #  # ]:          0 :         if( pText || pDraw )
     648         [ #  # ]:          0 :             pCurPara->updateGeometryWith( pCurEle );
     649                 :            :     }
     650                 :            : 
     651                 :            :     // process children
     652         [ +  - ]:          3 :     elem.applyToChildren(*this);
     653                 :            : 
     654                 :            :     // find possible header and footer
     655         [ +  - ]:          3 :     checkHeaderAndFooter( elem );
     656                 :          3 : }
     657                 :            : 
     658                 :          3 : void WriterXmlOptimizer::checkHeaderAndFooter( PageElement& rElem )
     659                 :            : {
     660                 :            :     /* indicators for a header:
     661                 :            :      *  - single line paragrah at top of page (  inside 15% page height)
     662                 :            :      *  - at least linheight above the next paragr   aph
     663                 :            :      *
     664                 :            :      *  indicators for a footer likewise:
     665                 :            :      *  - single line paragraph at bottom of page (inside 15% page height)
     666                 :            :      *  - at least lineheight below the previous paragraph
     667                 :            :      */
     668                 :            : 
     669                 :            :     // detect header
     670                 :            :     // Note: the following assumes that the pages' chiuldren have been
     671                 :            :     // sorted geometrically
     672                 :          3 :     std::list< Element* >::iterator it = rElem.Children.begin();
     673         [ +  + ]:         45 :     while( it != rElem.Children.end() )
     674                 :            :     {
     675         [ -  + ]:         42 :         ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(*it);
     676         [ -  + ]:         42 :         if( pPara )
     677                 :            :         {
     678 [ #  # ][ #  # ]:          0 :             if( pPara->y+pPara->h < rElem.h*0.15 && pPara->isSingleLined( m_rProcessor ) )
         [ #  # ][ #  # ]
     679                 :            :             {
     680                 :          0 :                 std::list< Element* >::iterator next_it = it;
     681                 :          0 :                 ParagraphElement* pNextPara = NULL;
     682 [ #  # ][ #  # ]:          0 :                 while( ++next_it != rElem.Children.end() && pNextPara == NULL )
         [ #  # ][ #  # ]
     683                 :            :                 {
     684         [ #  # ]:          0 :                     pNextPara = dynamic_cast<ParagraphElement*>(*next_it);
     685                 :            :                 }
     686 [ #  # ][ #  # ]:          0 :                 if( pNextPara && pNextPara->y > pPara->y+pPara->h*2 )
     687                 :            :                 {
     688                 :          0 :                     rElem.HeaderElement = pPara;
     689                 :          0 :                     pPara->Parent = NULL;
     690         [ #  # ]:          0 :                     rElem.Children.remove( pPara );
     691                 :            :                 }
     692                 :            :             }
     693                 :          0 :             break;
     694                 :            :         }
     695                 :         42 :         ++it;
     696                 :            :     }
     697                 :            : 
     698                 :            :     // detect footer
     699                 :          3 :     std::list< Element* >::reverse_iterator rit = rElem.Children.rbegin();
     700 [ +  - ][ +  + ]:         45 :     while( rit != rElem.Children.rend() )
     701                 :            :     {
     702 [ +  - ][ -  + ]:         42 :         ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(*rit);
     703         [ -  + ]:         42 :         if( pPara )
     704                 :            :         {
     705 [ #  # ][ #  # ]:          0 :             if( pPara->y > rElem.h*0.85 && pPara->isSingleLined( m_rProcessor ) )
         [ #  # ][ #  # ]
     706                 :            :             {
     707                 :          0 :                 std::list< Element* >::reverse_iterator next_it = rit;
     708                 :          0 :                 ParagraphElement* pNextPara = NULL;
     709 [ #  # ][ #  # ]:          0 :                 while( ++next_it != rElem.Children.rend() && pNextPara == NULL )
         [ #  # ][ #  # ]
                 [ #  # ]
           [ #  #  #  # ]
     710                 :            :                 {
     711 [ #  # ][ #  # ]:          0 :                     pNextPara = dynamic_cast<ParagraphElement*>(*next_it);
     712                 :            :                 }
     713 [ #  # ][ #  # ]:          0 :                 if( pNextPara && pNextPara->y < pPara->y-pPara->h*2 )
     714                 :            :                 {
     715                 :          0 :                     rElem.FooterElement = pPara;
     716                 :          0 :                     pPara->Parent = NULL;
     717         [ #  # ]:          0 :                     rElem.Children.remove( pPara );
     718                 :            :                 }
     719                 :            :             }
     720                 :          0 :             break;
     721                 :            :         }
     722         [ +  - ]:         42 :         ++rit;
     723                 :            :     }
     724                 :          3 : }
     725                 :            : 
     726                 :         33 : void WriterXmlOptimizer::optimizeTextElements(Element& rParent)
     727                 :            : {
     728         [ +  - ]:         33 :     if( rParent.Children.empty() ) // this should not happen
     729                 :            :     {
     730                 :            :         OSL_FAIL( "empty paragraph optimized" );
     731                 :         33 :         return;
     732                 :            :     }
     733                 :            : 
     734                 :            :     // concatenate child elements with same font id
     735                 :         33 :     std::list< Element* >::iterator next = rParent.Children.begin();
     736                 :         33 :     std::list< Element* >::iterator it = next++;
     737         [ -  + ]:         33 :     FrameElement* pFrame = dynamic_cast<FrameElement*>(rParent.Parent);
     738                 :         33 :     bool bRotatedFrame = false;
     739         [ +  - ]:         33 :     if( pFrame )
     740                 :            :     {
     741         [ +  - ]:         33 :         const GraphicsContext& rFrameGC = m_rProcessor.getGraphicsContext( pFrame->GCId );
     742 [ +  - ][ -  + ]:         33 :         if( rFrameGC.isRotatedOrSkewed() )
     743                 :          0 :             bRotatedFrame = true;
     744                 :            :     }
     745         [ +  + ]:        312 :     while( next != rParent.Children.end() )
     746                 :            :     {
     747                 :        279 :         bool bConcat = false;
     748         [ -  + ]:        279 :         TextElement* pCur = dynamic_cast<TextElement*>(*it);
     749         [ +  - ]:        279 :         if( pCur )
     750                 :            :         {
     751         [ -  + ]:        279 :             TextElement* pNext = dynamic_cast<TextElement*>(*next);
     752         [ +  - ]:        279 :             if( pNext )
     753                 :            :             {
     754         [ +  - ]:        279 :                 const GraphicsContext& rCurGC = m_rProcessor.getGraphicsContext( pCur->GCId );
     755         [ +  - ]:        279 :                 const GraphicsContext& rNextGC = m_rProcessor.getGraphicsContext( pNext->GCId );
     756                 :            : 
     757                 :            :                 // line and space optimization; works only in strictly horizontal mode
     758                 :            : 
     759 [ +  - ][ +  - ]:       1881 :                 if( !bRotatedFrame
           [ +  -  +  -  
          +  +  +  -  +  
              + ][ +  + ]
     760         [ +  - ]:        279 :                     && ! rCurGC.isRotatedOrSkewed()
     761         [ +  - ]:        279 :                     && ! rNextGC.isRotatedOrSkewed()
     762                 :        279 :                     && pNext->Text.getLength() > 0
     763                 :        279 :                     && pNext->Text[0] != sal_Unicode(' ')
     764                 :        243 :                     && pCur->Text.getLength() >  0
     765                 :        243 :                     && pCur->Text[pCur->Text.getLength() - 1] != sal_Unicode(' ')
     766                 :            :                     )
     767                 :            :                 {
     768                 :            :                     // check for new line in paragraph
     769         [ -  + ]:        207 :                     if( pNext->y > pCur->y+pCur->h )
     770                 :            :                     {
     771                 :            :                         // new line begins
     772                 :            :                         // check whether a space would should be inserted or a hyphen removed
     773                 :          0 :                         sal_Unicode aLastCode = pCur->Text[pCur->Text.getLength() - 1];
     774 [ #  # ][ #  # ]:          0 :                         if( aLastCode == '-'
         [ #  # ][ #  # ]
                 [ #  # ]
     775                 :            :                             || aLastCode == 0x2010
     776                 :            :                             || (aLastCode >= 0x2012 && aLastCode <= 0x2015)
     777                 :            :                             || aLastCode == 0xff0d
     778                 :            :                         )
     779                 :            :                         {
     780                 :            :                             // cut a hyphen
     781         [ #  # ]:          0 :                             pCur->Text.setLength( pCur->Text.getLength()-1 );
     782                 :            :                         }
     783                 :            :                         // append a space unless there is a non breaking hyphen
     784         [ #  # ]:          0 :                         else if( aLastCode != 0x2011 )
     785                 :            :                         {
     786         [ #  # ]:          0 :                             pCur->Text.append( sal_Unicode( ' ' ) );
     787                 :            :                         }
     788                 :            :                     }
     789                 :            :                     else // we're continuing the same line
     790                 :            :                     {
     791                 :            :                         // check whether a space would should be inserted
     792                 :            :                         // check for a small horizontal offset
     793         [ +  - ]:        207 :                         if( pCur->x + pCur->w + pNext->h*0.15 < pNext->x )
     794                 :            :                         {
     795         [ +  - ]:        207 :                             pCur->Text.append( sal_Unicode(' ') );
     796                 :            :                         }
     797                 :            :                     }
     798                 :            :                 }
     799                 :            :                 // concatenate consecutive text elements unless there is a
     800                 :            :                 // font or text color or matrix change, leave a new span in that case
     801 [ +  - ][ +  - ]:        558 :                 if( pCur->FontId == pNext->FontId &&
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     802                 :            :                     rCurGC.FillColor.Red == rNextGC.FillColor.Red &&
     803                 :            :                     rCurGC.FillColor.Green == rNextGC.FillColor.Green &&
     804                 :            :                     rCurGC.FillColor.Blue == rNextGC.FillColor.Blue &&
     805                 :            :                     rCurGC.FillColor.Alpha == rNextGC.FillColor.Alpha &&
     806         [ +  - ]:        279 :                     rCurGC.Transformation == rNextGC.Transformation
     807                 :            :                     )
     808                 :            :                 {
     809         [ +  - ]:        279 :                     pCur->updateGeometryWith( pNext );
     810                 :            :                     // append text to current element
     811         [ +  - ]:        279 :                     pCur->Text.append( pNext->Text.getStr(), pNext->Text.getLength() );
     812                 :            :                     // append eventual children to current element
     813                 :            :                     // and clear children (else the children just
     814                 :            :                     // appended to pCur would be destroyed)
     815         [ +  - ]:        279 :                     pCur->Children.splice( pCur->Children.end(), pNext->Children );
     816                 :            :                     // get rid of the now useless element
     817         [ +  - ]:        279 :                     rParent.Children.erase( next );
     818 [ +  - ][ +  - ]:        279 :                     delete pNext;
     819                 :        279 :                     bConcat = true;
     820                 :            :                 }
     821                 :            :             }
     822                 :            :         }
     823 [ #  # ][ #  # ]:          0 :         else if( dynamic_cast<HyperlinkElement*>(*it) )
                 [ #  # ]
     824         [ #  # ]:          0 :             optimizeTextElements( **it );
     825         [ +  - ]:        279 :         if( bConcat )
     826                 :            :         {
     827                 :        279 :             next = it;
     828                 :        279 :             ++next;
     829                 :            :         }
     830                 :            :         else
     831                 :            :         {
     832                 :          0 :             ++it;
     833                 :          0 :             ++next;
     834                 :            :         }
     835                 :            :     }
     836                 :            : }
     837                 :            : 
     838                 :          3 : void WriterXmlOptimizer::visit( DocumentElement& elem, const std::list< Element* >::const_iterator&)
     839                 :            : {
     840                 :          3 :     elem.applyToChildren(*this);
     841                 :          3 : }
     842                 :            : 
     843                 :            : //////////////////////////////////////////////////////////////////////////////////
     844                 :            : 
     845                 :            : 
     846                 :          9 : void WriterXmlFinalizer::visit( PolyPolyElement& elem, const std::list< Element* >::const_iterator& )
     847                 :            : {
     848                 :            :     // xxx TODO copied from DrawElement
     849         [ +  - ]:          9 :     const GraphicsContext& rGC = m_rProcessor.getGraphicsContext(elem.GCId );
     850         [ +  - ]:          9 :     PropertyMap aProps;
     851 [ +  - ][ +  - ]:          9 :     aProps[ USTR( "style:family" ) ] = USTR( "graphic" );
                 [ +  - ]
     852                 :            : 
     853         [ +  - ]:          9 :     PropertyMap aGCProps;
     854                 :            : 
     855                 :            :     // TODO(F3): proper dash emulation
     856         [ +  + ]:          9 :     if( elem.Action & PATH_STROKE )
     857                 :            :     {
     858 [ +  + ][ +  - ]:          6 :         aGCProps[ USTR("draw:stroke") ] = rGC.DashArray.empty() ? USTR("solid") : USTR("dash");
         [ +  - ][ +  - ]
                 [ +  - ]
     859 [ +  - ][ +  - ]:          6 :         aGCProps[ USTR("svg:stroke-color") ] = getColorString( rGC.LineColor );
                 [ +  - ]
     860         [ +  + ]:          6 :         if( rGC.LineWidth != 0.0 )
     861                 :            :         {
     862                 :          3 :             ::basegfx::B2DVector aVec(rGC.LineWidth,0);
     863         [ +  - ]:          3 :             aVec *= rGC.Transformation;
     864                 :            : 
     865                 :          3 :             aVec.setX ( convPx2mmPrec2( aVec.getX() )*100.0 );
     866                 :          3 :             aVec.setY ( convPx2mmPrec2( aVec.getY() )*100.0 );
     867                 :            : 
     868 [ +  - ][ +  - ]:          3 :             aGCProps[ USTR("svg:stroke-width") ] = rtl::OUString::valueOf( aVec.getLength() );
                 [ +  - ]
     869                 :            :         }
     870                 :            :     }
     871                 :            :     else
     872                 :            :     {
     873 [ +  - ][ +  - ]:          3 :         aGCProps[ USTR("draw:stroke") ] = USTR("none");
                 [ +  - ]
     874                 :            :     }
     875                 :            : 
     876                 :            :     // TODO(F1): check whether stuff could be emulated by gradient/bitmap/hatch
     877         [ +  + ]:          9 :     if( elem.Action & (PATH_FILL | PATH_EOFILL) )
     878                 :            :     {
     879 [ +  - ][ +  - ]:          3 :         aGCProps[ USTR("draw:fill") ]   = USTR("solid");
                 [ +  - ]
     880 [ +  - ][ +  - ]:          3 :         aGCProps[ USTR("draw:fill-color") ] = getColorString( rGC.FillColor );
                 [ +  - ]
     881                 :            :     }
     882                 :            :     else
     883                 :            :     {
     884 [ +  - ][ +  - ]:          6 :         aGCProps[ USTR("draw:fill") ] = USTR("none");
                 [ +  - ]
     885                 :            :     }
     886                 :            : 
     887         [ +  - ]:          9 :     StyleContainer::Style aStyle( "style:style", aProps );
     888         [ +  - ]:          9 :     StyleContainer::Style aSubStyle( "style:graphic-properties", aGCProps );
     889         [ +  - ]:          9 :     aStyle.SubStyles.push_back( &aSubStyle );
     890                 :            : 
     891 [ +  - ][ +  - ]:          9 :     elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
         [ +  - ][ +  - ]
                 [ +  - ]
     892                 :          9 : }
     893                 :            : 
     894                 :          0 : void WriterXmlFinalizer::visit( HyperlinkElement&, const std::list< Element* >::const_iterator& )
     895                 :            : {
     896                 :          0 : }
     897                 :            : 
     898                 :         33 : void WriterXmlFinalizer::visit( TextElement& elem, const std::list< Element* >::const_iterator& )
     899                 :            : {
     900         [ +  - ]:         33 :     const FontAttributes& rFont = m_rProcessor.getFont( elem.FontId );
     901         [ +  - ]:         33 :     PropertyMap aProps;
     902 [ +  - ][ +  - ]:         33 :     aProps[ USTR( "style:family" ) ] = USTR( "text" );
                 [ +  - ]
     903                 :            : 
     904         [ +  - ]:         33 :     PropertyMap aFontProps;
     905                 :            : 
     906                 :            :     // family name
     907 [ +  - ][ +  - ]:         33 :     aFontProps[ USTR( "fo:font-family" ) ] = rFont.familyName;
     908                 :            :     // bold
     909         [ -  + ]:         33 :     if( rFont.isBold )
     910                 :            :     {
     911 [ #  # ][ #  # ]:          0 :         aFontProps[ USTR( "fo:font-weight" ) ]         = USTR( "bold" );
                 [ #  # ]
     912 [ #  # ][ #  # ]:          0 :         aFontProps[ USTR( "fo:font-weight-asian" ) ]   = USTR( "bold" );
                 [ #  # ]
     913 [ #  # ][ #  # ]:          0 :         aFontProps[ USTR( "fo:font-weight-complex" ) ] = USTR( "bold" );
                 [ #  # ]
     914                 :            :     }
     915                 :            :     // italic
     916         [ -  + ]:         33 :     if( rFont.isItalic )
     917                 :            :     {
     918 [ #  # ][ #  # ]:          0 :         aFontProps[ USTR( "fo:font-style" ) ]         = USTR( "italic" );
                 [ #  # ]
     919 [ #  # ][ #  # ]:          0 :         aFontProps[ USTR( "fo:font-style-asian" ) ]   = USTR( "italic" );
                 [ #  # ]
     920 [ #  # ][ #  # ]:          0 :         aFontProps[ USTR( "fo:font-style-complex" ) ] = USTR( "italic" );
                 [ #  # ]
     921                 :            :     }
     922                 :            :     // underline
     923         [ -  + ]:         33 :     if( rFont.isUnderline )
     924                 :            :     {
     925 [ #  # ][ #  # ]:          0 :         aFontProps[ USTR( "style:text-underline-style" ) ]  = USTR( "solid" );
                 [ #  # ]
     926 [ #  # ][ #  # ]:          0 :         aFontProps[ USTR( "style:text-underline-width" ) ]  = USTR( "auto" );
                 [ #  # ]
     927 [ #  # ][ #  # ]:          0 :         aFontProps[ USTR( "style:text-underline-color" ) ]  = USTR( "font-color" );
                 [ #  # ]
     928                 :            :     }
     929                 :            :     // outline
     930         [ -  + ]:         33 :     if( rFont.isOutline )
     931                 :            :     {
     932 [ #  # ][ #  # ]:          0 :         aFontProps[ USTR( "style:text-outline" ) ]  = USTR( "true" );
                 [ #  # ]
     933                 :            :     }
     934                 :            :     // size
     935                 :         33 :     rtl::OUStringBuffer aBuf( 32 );
     936         [ +  - ]:         33 :     aBuf.append( rFont.size*72/PDFI_OUTDEV_RESOLUTION );
     937         [ +  - ]:         33 :     aBuf.appendAscii( "pt" );
     938         [ +  - ]:         33 :     rtl::OUString aFSize = aBuf.makeStringAndClear();
     939 [ +  - ][ +  - ]:         33 :     aFontProps[ USTR( "fo:font-size" ) ]            = aFSize;
     940 [ +  - ][ +  - ]:         33 :     aFontProps[ USTR( "style:font-size-asian" ) ]   = aFSize;
     941 [ +  - ][ +  - ]:         33 :     aFontProps[ USTR( "style:font-size-complex" ) ] = aFSize;
     942                 :            :     // color
     943         [ +  - ]:         33 :     const GraphicsContext& rGC = m_rProcessor.getGraphicsContext( elem.GCId );
     944 [ -  + ][ +  - ]:         33 :     aFontProps[ USTR( "fo:color" ) ]                 =  getColorString( rFont.isOutline ? rGC.LineColor : rGC.FillColor );
         [ +  - ][ +  - ]
     945                 :            : 
     946         [ +  - ]:         33 :     StyleContainer::Style aStyle( "style:style", aProps );
     947         [ +  - ]:         33 :     StyleContainer::Style aSubStyle( "style:text-properties", aFontProps );
     948         [ +  - ]:         33 :     aStyle.SubStyles.push_back( &aSubStyle );
     949 [ +  - ][ +  - ]:         33 :     elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
         [ +  - ][ +  - ]
                 [ +  - ]
     950                 :         33 : }
     951                 :            : 
     952                 :         33 : void WriterXmlFinalizer::visit( ParagraphElement& elem, const std::list< Element* >::const_iterator& rParentIt )
     953                 :            : {
     954         [ +  - ]:         33 :     PropertyMap aParaProps;
     955                 :            : 
     956         [ +  - ]:         33 :     if( elem.Parent )
     957                 :            :     {
     958                 :            :         // check for center alignement
     959                 :            :         // criterion: paragraph is small relative to parent and distributed around its center
     960                 :         33 :         double p_x = elem.Parent->x;
     961                 :         33 :         double p_w = elem.Parent->w;
     962                 :            : 
     963         [ -  + ]:         33 :         PageElement* pPage = dynamic_cast<PageElement*>(elem.Parent);
     964         [ -  + ]:         33 :         if( pPage )
     965                 :            :         {
     966                 :          0 :             p_x += pPage->LeftMargin;
     967                 :          0 :             p_w -= pPage->LeftMargin+pPage->RightMargin;
     968                 :            :         }
     969                 :         33 :         bool bIsCenter = false;
     970         [ -  + ]:         33 :         if( elem.w < ( p_w/2) )
     971                 :            :         {
     972                 :          0 :             double delta = elem.w/4;
     973                 :            :             // allow very small paragraphs to deviate a little more
     974                 :            :             // relative to parent's center
     975         [ #  # ]:          0 :             if( elem.w <  p_w/8 )
     976                 :          0 :                 delta = elem.w;
     977 [ #  # ][ #  # ]:          0 :             if( fabs( elem.x+elem.w/2 - ( p_x+ p_w/2) ) <  delta ||
                 [ #  # ]
     978                 :          0 :                 (pPage && fabs( elem.x+elem.w/2 - (pPage->x + pPage->w/2) ) <  delta) )
     979                 :            :             {
     980                 :          0 :                 bIsCenter = true;
     981 [ #  # ][ #  # ]:          0 :                 aParaProps[ USTR( "fo:text-align" ) ] = USTR( "center" );
                 [ #  # ]
     982                 :            :             }
     983                 :            :         }
     984 [ +  - ][ -  + ]:         33 :         if( ! bIsCenter && elem.x > p_x + p_w/10 )
     985                 :            :         {
     986                 :            :             // indent
     987                 :          0 :             rtl::OUStringBuffer aBuf( 32 );
     988         [ #  # ]:          0 :             aBuf.append( convPx2mm( elem.x - p_x ) );
     989         [ #  # ]:          0 :             aBuf.appendAscii( "mm" );
     990 [ #  # ][ #  # ]:          0 :             aParaProps[ USTR( "fo:margin-left" ) ] = aBuf.makeStringAndClear();
                 [ #  # ]
     991                 :            :         }
     992                 :            : 
     993                 :            :         // check whether to leave some space to next paragraph
     994                 :            :         // find whether there is a next paragraph
     995                 :         33 :         std::list< Element* >::const_iterator it = rParentIt;
     996                 :         33 :         const ParagraphElement* pNextPara = NULL;
     997 [ -  + ][ #  # ]:         33 :         while( ++it != elem.Parent->Children.end() && ! pNextPara )
         [ +  - ][ +  - ]
                 [ -  + ]
     998         [ #  # ]:          0 :             pNextPara = dynamic_cast< const ParagraphElement* >(*it);
     999         [ -  + ]:         33 :         if( pNextPara )
    1000                 :            :         {
    1001         [ #  # ]:          0 :             if( pNextPara->y - (elem.y+elem.h) > convmm2Px( 10 ) )
    1002                 :            :             {
    1003                 :          0 :                 rtl::OUStringBuffer aBuf( 32 );
    1004         [ #  # ]:          0 :                 aBuf.append( convPx2mm( pNextPara->y - (elem.y+elem.h) ) );
    1005         [ #  # ]:          0 :                 aBuf.appendAscii( "mm" );
    1006 [ #  # ][ #  # ]:         33 :                 aParaProps[ USTR( "fo:margin-bottom" ) ] = aBuf.makeStringAndClear();
                 [ #  # ]
    1007                 :            :             }
    1008                 :            :         }
    1009                 :            :     }
    1010                 :            : 
    1011         [ -  + ]:         33 :     if( ! aParaProps.empty() )
    1012                 :            :     {
    1013         [ #  # ]:          0 :         PropertyMap aProps;
    1014 [ #  # ][ #  # ]:          0 :         aProps[ USTR( "style:family" ) ] = USTR( "paragraph" );
                 [ #  # ]
    1015         [ #  # ]:          0 :         StyleContainer::Style aStyle( "style:style", aProps );
    1016         [ #  # ]:          0 :         StyleContainer::Style aSubStyle( "style:paragraph-properties", aParaProps );
    1017         [ #  # ]:          0 :         aStyle.SubStyles.push_back( &aSubStyle );
    1018 [ #  # ][ #  # ]:          0 :         elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
         [ #  # ][ #  # ]
    1019                 :            :     }
    1020                 :            : 
    1021 [ +  - ][ +  - ]:         33 :     elem.applyToChildren(*this);
    1022                 :         33 : }
    1023                 :            : 
    1024                 :         33 : void WriterXmlFinalizer::visit( FrameElement& elem, const std::list< Element* >::const_iterator&)
    1025                 :            : {
    1026         [ +  - ]:         33 :     PropertyMap aProps;
    1027 [ +  - ][ +  - ]:         33 :     aProps[ USTR( "style:family" ) ] = USTR( "graphic" );
                 [ +  - ]
    1028                 :            : 
    1029         [ +  - ]:         33 :     PropertyMap aGCProps;
    1030                 :            : 
    1031 [ +  - ][ +  - ]:         33 :     aGCProps[ USTR("draw:stroke") ] = USTR("none");
                 [ +  - ]
    1032 [ +  - ][ +  - ]:         33 :     aGCProps[ USTR("draw:fill") ] = USTR("none");
                 [ +  - ]
    1033                 :            : 
    1034         [ +  - ]:         33 :     StyleContainer::Style aStyle( "style:style", aProps );
    1035         [ +  - ]:         33 :     StyleContainer::Style aSubStyle( "style:graphic-properties", aGCProps );
    1036         [ +  - ]:         33 :     aStyle.SubStyles.push_back( &aSubStyle );
    1037                 :            : 
    1038         [ +  - ]:         33 :     elem.StyleId = m_rStyleContainer.getStyleId( aStyle );
    1039 [ +  - ][ +  - ]:         33 :     elem.applyToChildren(*this);
         [ +  - ][ +  - ]
                 [ +  - ]
    1040                 :         33 : }
    1041                 :            : 
    1042                 :          0 : void WriterXmlFinalizer::visit( ImageElement&, const std::list< Element* >::const_iterator& )
    1043                 :            : {
    1044                 :          0 : }
    1045                 :            : 
    1046                 :          3 : void WriterXmlFinalizer::setFirstOnPage( ParagraphElement&    rElem,
    1047                 :            :                                          StyleContainer&      rStyles,
    1048                 :            :                                          const rtl::OUString& rMasterPageName )
    1049                 :            : {
    1050         [ +  - ]:          3 :     PropertyMap aProps;
    1051         [ -  + ]:          3 :     if( rElem.StyleId != -1 )
    1052                 :            :     {
    1053         [ #  # ]:          0 :         const PropertyMap* pProps = rStyles.getProperties( rElem.StyleId );
    1054         [ #  # ]:          0 :         if( pProps )
    1055         [ #  # ]:          0 :             aProps = *pProps;
    1056                 :            :     }
    1057                 :            : 
    1058 [ +  - ][ +  - ]:          3 :     aProps[ USTR( "style:family" ) ] = USTR( "paragraph" );
                 [ +  - ]
    1059 [ +  - ][ +  - ]:          3 :     aProps[ USTR( "style:master-page-name" ) ] = rMasterPageName;
    1060                 :            : 
    1061         [ -  + ]:          3 :     if( rElem.StyleId != -1 )
    1062         [ #  # ]:          0 :         rElem.StyleId = rStyles.setProperties( rElem.StyleId, aProps );
    1063                 :            :     else
    1064                 :            :     {
    1065         [ +  - ]:          3 :         StyleContainer::Style aStyle( "style:style", aProps );
    1066 [ +  - ][ +  - ]:          3 :         rElem.StyleId = rStyles.getStyleId( aStyle );
    1067         [ +  - ]:          3 :     }
    1068                 :          3 : }
    1069                 :            : 
    1070                 :          3 : void WriterXmlFinalizer::visit( PageElement& elem, const std::list< Element* >::const_iterator& )
    1071                 :            : {
    1072         [ -  + ]:          3 :     if( m_rProcessor.getStatusIndicator().is() )
    1073 [ #  # ][ #  # ]:          0 :         m_rProcessor.getStatusIndicator()->setValue( elem.PageNumber );
    1074                 :            : 
    1075                 :            :     // transform from pixel to mm
    1076                 :          3 :     double page_width = convPx2mm( elem.w ), page_height = convPx2mm( elem.h );
    1077                 :            : 
    1078                 :            :     // calculate page margins out of the relevant children (paragraphs)
    1079                 :          3 :     elem.TopMargin = elem.h, elem.BottomMargin = 0, elem.LeftMargin = elem.w, elem.RightMargin = 0;
    1080                 :            :     // first element should be a paragraphy
    1081                 :          3 :     ParagraphElement* pFirstPara = NULL;
    1082         [ +  + ]:         45 :     for( std::list< Element* >::const_iterator it = elem.Children.begin(); it != elem.Children.end(); ++it )
    1083                 :            :     {
    1084 [ +  - ][ -  + ]:         42 :         if( dynamic_cast<ParagraphElement*>( *it ) )
                 [ -  + ]
    1085                 :            :         {
    1086         [ #  # ]:          0 :             if( (*it)->x < elem.LeftMargin )
    1087                 :          0 :                 elem.LeftMargin = (*it)->x;
    1088         [ #  # ]:          0 :             if( (*it)->y < elem.TopMargin )
    1089                 :          0 :                 elem.TopMargin = (*it)->y;
    1090         [ #  # ]:          0 :             if( (*it)->x + (*it)->w > elem.w - elem.RightMargin )
    1091                 :          0 :                 elem.RightMargin = elem.w - ((*it)->x + (*it)->w);
    1092         [ #  # ]:          0 :             if( (*it)->y + (*it)->h > elem.h - elem.BottomMargin )
    1093                 :          0 :                 elem.BottomMargin = elem.h - ((*it)->y + (*it)->h);
    1094         [ #  # ]:          0 :             if( ! pFirstPara )
    1095         [ #  # ]:          0 :                 pFirstPara = dynamic_cast<ParagraphElement*>( *it );
    1096                 :            :         }
    1097                 :            :     }
    1098 [ -  + ][ #  # ]:          3 :     if( elem.HeaderElement && elem.HeaderElement->y < elem.TopMargin )
    1099                 :          0 :         elem.TopMargin = elem.HeaderElement->y;
    1100 [ -  + ][ #  # ]:          3 :     if( elem.FooterElement && elem.FooterElement->y+elem.FooterElement->h > elem.h - elem.BottomMargin )
    1101                 :          0 :         elem.BottomMargin = elem.h - (elem.FooterElement->y + elem.FooterElement->h);
    1102                 :            : 
    1103                 :            :     // transform margins to mm
    1104                 :          3 :     double left_margin     = convPx2mm( elem.LeftMargin );
    1105                 :          3 :     double right_margin    = convPx2mm( elem.RightMargin );
    1106                 :          3 :     double top_margin      = convPx2mm( elem.TopMargin );
    1107                 :          3 :     double bottom_margin   = convPx2mm( elem.BottomMargin );
    1108         [ +  - ]:          3 :     if( ! pFirstPara )
    1109                 :            :     {
    1110                 :            :         // use default page margins
    1111                 :          3 :         left_margin     = 10;
    1112                 :          3 :         right_margin    = 10;
    1113                 :          3 :         top_margin      = 10;
    1114                 :          3 :         bottom_margin   = 10;
    1115                 :            :     }
    1116                 :            : 
    1117                 :            :     // round left/top margin to nearest mm
    1118                 :          3 :     left_margin     = rtl_math_round( left_margin, 0, rtl_math_RoundingMode_Floor );
    1119                 :          3 :     top_margin      = rtl_math_round( top_margin, 0, rtl_math_RoundingMode_Floor );
    1120                 :            :     // round (fuzzy) right/bottom margin to nearest cm
    1121         [ +  - ]:          3 :     right_margin    = rtl_math_round( right_margin, right_margin >= 10 ? -1 : 0, rtl_math_RoundingMode_Floor );
    1122         [ +  - ]:          3 :     bottom_margin   = rtl_math_round( bottom_margin, bottom_margin >= 10 ? -1 : 0, rtl_math_RoundingMode_Floor );
    1123                 :            : 
    1124                 :            :     // set reasonable default in case of way too large margins
    1125                 :            :     // e.g. no paragraph case
    1126         [ -  + ]:          3 :     if( left_margin > page_width/2.0 - 10 )
    1127                 :          0 :         left_margin = 10;
    1128         [ -  + ]:          3 :     if( right_margin > page_width/2.0 - 10 )
    1129                 :          0 :         right_margin = 10;
    1130         [ -  + ]:          3 :     if( top_margin > page_height/2.0 - 10 )
    1131                 :          0 :         top_margin = 10;
    1132         [ -  + ]:          3 :     if( bottom_margin > page_height/2.0 - 10 )
    1133                 :          0 :         bottom_margin = 10;
    1134                 :            : 
    1135                 :            :     // catch the weird cases
    1136         [ -  + ]:          3 :     if( left_margin < 0 )
    1137                 :          0 :         left_margin = 0;
    1138         [ -  + ]:          3 :     if( right_margin < 0 )
    1139                 :          0 :         right_margin = 0;
    1140         [ -  + ]:          3 :     if( top_margin < 0 )
    1141                 :          0 :         top_margin = 0;
    1142         [ -  + ]:          3 :     if( bottom_margin < 0 )
    1143                 :          0 :         bottom_margin = 0;
    1144                 :            : 
    1145                 :            :     // widely differing margins are unlikely to be correct
    1146         [ -  + ]:          3 :     if( right_margin > left_margin*1.5 )
    1147                 :          0 :         right_margin = left_margin;
    1148                 :            : 
    1149                 :          3 :     elem.LeftMargin      = convmm2Px( left_margin );
    1150                 :          3 :     elem.RightMargin     = convmm2Px( right_margin );
    1151                 :          3 :     elem.TopMargin       = convmm2Px( top_margin );
    1152                 :          3 :     elem.BottomMargin    = convmm2Px( bottom_margin );
    1153                 :            : 
    1154                 :            :     // get styles for paragraphs
    1155         [ +  - ]:          3 :     PropertyMap aPageProps;
    1156         [ +  - ]:          3 :     PropertyMap aPageLayoutProps;
    1157                 :          3 :     rtl::OUStringBuffer aBuf( 64 );
    1158 [ +  - ][ +  - ]:          3 :     aPageLayoutProps[ USTR( "fo:page-width" ) ]     = unitMMString( page_width );
                 [ +  - ]
    1159 [ +  - ][ +  - ]:          3 :     aPageLayoutProps[ USTR( "fo:page-height" ) ]    = unitMMString( page_height );
                 [ +  - ]
    1160 [ +  - ][ +  - ]:          6 :     aPageLayoutProps[ USTR( "style:print-orientation" ) ]
    1161 [ #  # ][ +  - ]:          9 :         = elem.w < elem.h ? USTR( "portrait" ) : USTR( "landscape" );
                 [ -  + ]
    1162 [ +  - ][ +  - ]:          3 :     aPageLayoutProps[ USTR( "fo:margin-top" ) ]     = unitMMString( top_margin );
                 [ +  - ]
    1163 [ +  - ][ +  - ]:          3 :     aPageLayoutProps[ USTR( "fo:margin-bottom" ) ]  = unitMMString( bottom_margin );
                 [ +  - ]
    1164 [ +  - ][ +  - ]:          3 :     aPageLayoutProps[ USTR( "fo:margin-left" ) ]    = unitMMString( left_margin );
                 [ +  - ]
    1165 [ +  - ][ +  - ]:          3 :     aPageLayoutProps[ USTR( "fo:margin-right" ) ]   = unitMMString( right_margin );
                 [ +  - ]
    1166 [ +  - ][ +  - ]:          3 :     aPageLayoutProps[ USTR( "style:writing-mode" ) ]= USTR( "lr-tb" );
                 [ +  - ]
    1167                 :            : 
    1168         [ +  - ]:          3 :     StyleContainer::Style aStyle( "style:page-layout", aPageProps);
    1169         [ +  - ]:          3 :     StyleContainer::Style aSubStyle( "style:page-layout-properties", aPageLayoutProps);
    1170         [ +  - ]:          3 :     aStyle.SubStyles.push_back(&aSubStyle);
    1171         [ +  - ]:          3 :     sal_Int32 nPageStyle = m_rStyleContainer.impl_getStyleId( aStyle, false );
    1172                 :            : 
    1173                 :            :     // create master page
    1174         [ +  - ]:          3 :     rtl::OUString aMasterPageLayoutName = m_rStyleContainer.getStyleName( nPageStyle );
    1175 [ +  - ][ +  - ]:          3 :     aPageProps[ USTR( "style:page-layout-name" ) ] = aMasterPageLayoutName;
    1176         [ +  - ]:          3 :     StyleContainer::Style aMPStyle( "style:master-page", aPageProps );
    1177 [ +  - ][ +  - ]:          3 :     StyleContainer::Style aHeaderStyle( "style:header", PropertyMap() );
                 [ +  - ]
    1178 [ +  - ][ +  - ]:          3 :     StyleContainer::Style aFooterStyle( "style:footer", PropertyMap() );
                 [ +  - ]
    1179         [ -  + ]:          3 :     if( elem.HeaderElement )
    1180                 :            :     {
    1181         [ #  # ]:          0 :         elem.HeaderElement->visitedBy( *this, std::list<Element*>::iterator() );
    1182                 :          0 :         aHeaderStyle.ContainedElement = elem.HeaderElement;
    1183         [ #  # ]:          0 :         aMPStyle.SubStyles.push_back( &aHeaderStyle );
    1184                 :            :     }
    1185         [ -  + ]:          3 :     if( elem.FooterElement )
    1186                 :            :     {
    1187         [ #  # ]:          0 :         elem.FooterElement->visitedBy( *this, std::list<Element*>::iterator() );
    1188                 :          0 :         aFooterStyle.ContainedElement = elem.FooterElement;
    1189         [ #  # ]:          0 :         aMPStyle.SubStyles.push_back( &aFooterStyle );
    1190                 :            :     }
    1191         [ +  - ]:          3 :     elem.StyleId = m_rStyleContainer.impl_getStyleId( aMPStyle,false );
    1192                 :            : 
    1193                 :            : 
    1194         [ +  - ]:          3 :     rtl::OUString aMasterPageName = m_rStyleContainer.getStyleName( elem.StyleId );
    1195                 :            : 
    1196                 :            :     // create styles for children
    1197         [ +  - ]:          3 :     elem.applyToChildren(*this);
    1198                 :            : 
    1199                 :            :     // no paragraph or other elements before the first paragraph
    1200         [ +  - ]:          3 :     if( ! pFirstPara )
    1201                 :            :     {
    1202 [ +  - ][ +  - ]:          3 :         pFirstPara = m_rProcessor.getElementFactory()->createParagraphElement( NULL );
                 [ +  - ]
    1203                 :          3 :         pFirstPara->Parent = &elem;
    1204         [ +  - ]:          3 :         elem.Children.push_front( pFirstPara );
    1205                 :            :     }
    1206 [ +  - ][ +  - ]:          3 :     setFirstOnPage(*pFirstPara, m_rStyleContainer, aMasterPageName);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
    1207                 :          3 : }
    1208                 :            : 
    1209                 :          3 : void WriterXmlFinalizer::visit( DocumentElement& elem, const std::list< Element* >::const_iterator& )
    1210                 :            : {
    1211                 :          3 :     elem.applyToChildren(*this);
    1212                 :          3 : }
    1213                 :            : 
    1214                 :            : }
    1215                 :            : 
    1216                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10