LCOV - code coverage report
Current view: top level - sdext/source/pdfimport/tree - drawtreevisiting.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 437 610 71.6 %
Date: 2015-06-13 12:38:46 Functions: 27 31 87.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11