LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/sdext/source/pdfimport/tree - pdfiprocessor.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 398 501 79.4 %
Date: 2013-07-09 Functions: 41 51 80.4 %
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 "genericelements.hxx"
      26             : #include "style.hxx"
      27             : #include "treevisiting.hxx"
      28             : 
      29             : #include <rtl/string.hxx>
      30             : #include <rtl/strbuf.hxx>
      31             : 
      32             : #include <comphelper/sequence.hxx>
      33             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      34             : #include <basegfx/polygon/b2dpolygonclipper.hxx>
      35             : #include <basegfx/polygon/b2dpolygontools.hxx>
      36             : #include <basegfx/tools/canvastools.hxx>
      37             : #include <basegfx/matrix/b2dhommatrix.hxx>
      38             : #include <basegfx/range/b2irange.hxx>
      39             : #include <basegfx/range/b2drectangle.hxx>
      40             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      41             : #include <vcl/svapp.hxx>
      42             : 
      43             : #include <com/sun/star/rendering/XVolatileBitmap.hpp>
      44             : #include <com/sun/star/geometry/RealSize2D.hpp>
      45             : #include <com/sun/star/geometry/RealPoint2D.hpp>
      46             : #include <com/sun/star/geometry/RealRectangle2D.hpp>
      47             : 
      48             : 
      49             : using namespace com::sun::star;
      50             : 
      51             : 
      52             : namespace pdfi
      53             : {
      54             : 
      55           2 :  PDFIProcessor::PDFIProcessor( const uno::Reference< task::XStatusIndicator >& xStat ,
      56             :             com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext >  xContext) :
      57             : 
      58             :     m_xContext(xContext),
      59             :     fYPrevTextPosition(-10000.0),
      60             :     fPrevTextHeight(0.0),
      61             :     fXPrevTextPosition(0.0),
      62             :     fPrevTextWidth(0.0),
      63             :     m_pElFactory( new ElementFactory() ),
      64           2 :     m_pDocument( m_pElFactory->createDocumentElement() ),
      65             :     m_pCurPage(0),
      66             :     m_pCurElement(0),
      67             :     m_nNextFontId( 1 ),
      68             :     m_aIdToFont(),
      69             :     m_aFontToId(),
      70             :     m_aGCStack(),
      71             :     m_nNextGCId( 1 ),
      72             :     m_aIdToGC(),
      73             :     m_aGCToId(),
      74             :     m_aImages(),
      75             :     m_eTextDirection( LrTb ),
      76             :     m_nPages(0),
      77             :     m_nNextZOrder( 1 ),
      78             :     m_bIsWhiteSpaceInLine( false ),
      79             :     m_xStatusIndicator( xStat ),
      80           4 :     m_bHaveTextOnDocLevel(false)
      81             : {
      82           2 :     FontAttributes aDefFont;
      83           2 :     aDefFont.familyName = "Helvetica";
      84           2 :     aDefFont.isBold     = false;
      85           2 :     aDefFont.isItalic   = false;
      86           2 :     aDefFont.size       = 10*PDFI_OUTDEV_RESOLUTION/72;
      87           2 :     m_aIdToFont[ 0 ]    = aDefFont;
      88           2 :     m_aFontToId[ aDefFont ] = 0;
      89             : 
      90           4 :     GraphicsContext aDefGC;
      91           2 :     m_aGCStack.push_back( aDefGC );
      92           2 :     m_aIdToGC[ 0 ] = aDefGC;
      93           4 :     m_aGCToId[ aDefGC ] = 0;
      94           2 : }
      95             : 
      96           0 : void PDFIProcessor::enableToplevelText()
      97             : {
      98           0 :     m_bHaveTextOnDocLevel = true;
      99           0 : }
     100             : 
     101           2 : void PDFIProcessor::setPageNum( sal_Int32 nPages )
     102             : {
     103           2 :     m_nPages = nPages;
     104           2 : }
     105             : 
     106             : 
     107          32 : void PDFIProcessor::pushState()
     108             : {
     109          32 :     GraphicsContextStack::value_type const a(m_aGCStack.back());
     110          32 :     m_aGCStack.push_back(a);
     111          32 : }
     112             : 
     113          32 : void PDFIProcessor::popState()
     114             : {
     115          32 :     m_aGCStack.pop_back();
     116          32 : }
     117             : 
     118           2 : void PDFIProcessor::setFlatness( double value )
     119             : {
     120           2 :     getCurrentContext().Flatness = value;
     121           2 : }
     122             : 
     123           4 : void PDFIProcessor::setTransformation( const geometry::AffineMatrix2D& rMatrix )
     124             : {
     125             :     basegfx::unotools::homMatrixFromAffineMatrix(
     126           4 :         getCurrentContext().Transformation,
     127           4 :         rMatrix );
     128           4 : }
     129             : 
     130           4 : void PDFIProcessor::setLineDash( const uno::Sequence<double>& dashes,
     131             :                                  double                       /*start*/ )
     132             : {
     133             :     // TODO(F2): factor in start offset
     134           4 :     GraphicsContext& rContext( getCurrentContext() );
     135           4 :     comphelper::sequenceToContainer(rContext.DashArray,dashes);
     136           4 : }
     137             : 
     138           6 : void PDFIProcessor::setLineJoin(sal_Int8 nJoin)
     139             : {
     140           6 :     getCurrentContext().LineJoin = nJoin;
     141           6 : }
     142             : 
     143           6 : void PDFIProcessor::setLineCap(sal_Int8 nCap)
     144             : {
     145           6 :     getCurrentContext().LineCap = nCap;
     146           6 : }
     147             : 
     148           2 : void PDFIProcessor::setMiterLimit(double)
     149             : {
     150             :     OSL_TRACE("PDFIProcessor::setMiterLimit(): not supported by ODF");
     151           2 : }
     152             : 
     153           8 : void PDFIProcessor::setLineWidth(double nWidth)
     154             : {
     155           8 :     getCurrentContext().LineWidth = nWidth;
     156           8 : }
     157             : 
     158          28 : void PDFIProcessor::setFillColor( const rendering::ARGBColor& rColor )
     159             : {
     160          28 :     getCurrentContext().FillColor = rColor;
     161          28 : }
     162             : 
     163           8 : void PDFIProcessor::setStrokeColor( const rendering::ARGBColor& rColor )
     164             : {
     165           8 :     getCurrentContext().LineColor = rColor;
     166           8 : }
     167             : 
     168           0 : void PDFIProcessor::setBlendMode(sal_Int8)
     169             : {
     170             :     OSL_TRACE("PDFIProcessor::setBlendMode(): not supported by ODF");
     171           0 : }
     172             : 
     173          22 : void PDFIProcessor::setFont( const FontAttributes& i_rFont )
     174             : {
     175          22 :     FontAttributes aChangedFont( i_rFont );
     176          22 :     GraphicsContext& rGC=getCurrentContext();
     177             :     // for text render modes, please see PDF reference manual
     178          22 :     aChangedFont.isOutline = ( (rGC.TextRenderMode == 1) || (rGC. TextRenderMode == 2) );
     179          22 :     FontToIdMap::const_iterator it = m_aFontToId.find( aChangedFont );
     180          22 :     if( it != m_aFontToId.end() )
     181          14 :         rGC.FontId = it->second;
     182             :     else
     183             :     {
     184           8 :         m_aFontToId[ aChangedFont ] = m_nNextFontId;
     185           8 :         m_aIdToFont[ m_nNextFontId ] = aChangedFont;
     186           8 :         rGC.FontId = m_nNextFontId;
     187           8 :         m_nNextFontId++;
     188          22 :     }
     189          22 : }
     190             : 
     191           0 : void PDFIProcessor::setTextRenderMode( sal_Int32 i_nMode )
     192             : {
     193           0 :     GraphicsContext& rGC=getCurrentContext();
     194           0 :     rGC.TextRenderMode = i_nMode;
     195           0 :     IdToFontMap::iterator it = m_aIdToFont.find( rGC.FontId );
     196           0 :     if( it != m_aIdToFont.end() )
     197           0 :         setFont( it->second );
     198           0 : }
     199             : 
     200           0 : sal_Int32 PDFIProcessor::getFontId( const FontAttributes& rAttr ) const
     201             : {
     202           0 :     const sal_Int32 nCurFont = getCurrentContext().FontId;
     203           0 :     const_cast<PDFIProcessor*>(this)->setFont( rAttr );
     204           0 :     const sal_Int32 nFont = getCurrentContext().FontId;
     205           0 :     const_cast<PDFIProcessor*>(this)->getCurrentContext().FontId = nCurFont;
     206             : 
     207           0 :     return nFont;
     208             : }
     209             : 
     210             : // line diagnose block - start
     211          22 : void PDFIProcessor::processGlyphLine()
     212             : {
     213          22 :     if( m_GlyphsList.empty() )
     214          22 :         return;
     215             : 
     216          22 :     double fPreAvarageSpaceValue= 0.0;
     217          22 :     double fAvarageDiffCharSpaceValue= 0.0;
     218          22 :     double fMinPreSpaceValue= 0.0;
     219          22 :     double fMaxPreSpaceValue= 0.0;
     220          22 :     double fNullSpaceBreakerAvaregeSpaceValue = 0.0;
     221             : 
     222          22 :     unsigned int    nSpaceCount( 0 );
     223          22 :     unsigned int    nDiffSpaceCount( 0 );
     224          22 :     unsigned int    nNullSpaceBreakerCount=0;
     225          22 :     bool preSpaceNull(true);
     226             : 
     227         208 :     for ( unsigned int i=0; i<m_GlyphsList.size()-1; i++ ) // i=1 because the first glyph doesn't have a prevGlyphSpace value
     228             :     {
     229         186 :         if( m_GlyphsList[i].getPrevGlyphsSpace()>0.0 )
     230             :         {
     231          58 :            if( fMinPreSpaceValue>m_GlyphsList[i].getPrevGlyphsSpace() )
     232           0 :                fMinPreSpaceValue=m_GlyphsList[i].getPrevGlyphsSpace();
     233             : 
     234          58 :            if( fMaxPreSpaceValue<m_GlyphsList[i].getPrevGlyphsSpace() )
     235          14 :                fMaxPreSpaceValue=m_GlyphsList[i].getPrevGlyphsSpace();
     236             : 
     237          58 :            fPreAvarageSpaceValue+= m_GlyphsList[i].getPrevGlyphsSpace();
     238          58 :            nSpaceCount++;
     239             :         }
     240             :     }
     241             : 
     242          22 :     if( nSpaceCount!=0 )
     243          14 :      fPreAvarageSpaceValue= fPreAvarageSpaceValue/( nSpaceCount );
     244             : 
     245         208 :     for ( unsigned int i=0; i<m_GlyphsList.size()-1; i++ ) // i=1 because the first glyph doesn't have a prevGlyphSpace value
     246             :     {
     247         186 :        if ( m_GlyphsList[i].getPrevGlyphsSpace()==0.0 )
     248             :        {
     249         128 :             if (
     250         168 :                  ( m_GlyphsList[i+1].getPrevGlyphsSpace()>0.0)&&
     251          40 :                  ( fPreAvarageSpaceValue>m_GlyphsList[i+1].getPrevGlyphsSpace())
     252             :                )
     253             :             {
     254          26 :               fNullSpaceBreakerAvaregeSpaceValue+=m_GlyphsList[i+1].getPrevGlyphsSpace();
     255          26 :               nNullSpaceBreakerCount++;
     256             :             }
     257             :         }
     258             :     }
     259             : 
     260          22 :     if( ( fNullSpaceBreakerAvaregeSpaceValue!= 0.0 )&&
     261             :         ( fNullSpaceBreakerAvaregeSpaceValue < fPreAvarageSpaceValue )
     262             :       )
     263             :     {
     264          10 :         fPreAvarageSpaceValue = fNullSpaceBreakerAvaregeSpaceValue;
     265             :     }
     266             : 
     267         208 :     for ( unsigned int i=0; i<m_GlyphsList.size()-1; i++ ) // i=1 cose the first Glypth dont have prevGlyphSpace value
     268             :     {
     269         186 :         if  ( ( m_GlyphsList[i].getPrevGlyphsSpace()>0.0 )
     270             :             )
     271             :         {
     272          58 :           if (
     273         100 :               ( m_GlyphsList[i].getPrevGlyphsSpace()  <= fPreAvarageSpaceValue )&&
     274          42 :               ( m_GlyphsList[i+1].getPrevGlyphsSpace()<= fPreAvarageSpaceValue )
     275             :              )
     276             :           {
     277          40 :                double temp= m_GlyphsList[i].getPrevGlyphsSpace()-m_GlyphsList[i+1].getPrevGlyphsSpace();
     278             : 
     279          40 :                if(temp!=0.0)
     280             :                {
     281          38 :                  if( temp< 0.0)
     282           0 :                   temp= temp* -1.0;
     283             : 
     284          38 :                  fAvarageDiffCharSpaceValue+=temp;
     285          38 :                  nDiffSpaceCount++;
     286             :                }
     287             :           }
     288             :         }
     289             : 
     290             :     }
     291             : 
     292          22 :     if (
     293             :          ( nNullSpaceBreakerCount>0 )
     294             :        )
     295             :     {
     296          10 :        fNullSpaceBreakerAvaregeSpaceValue=fNullSpaceBreakerAvaregeSpaceValue/nNullSpaceBreakerCount;
     297             :     }
     298             : 
     299          22 :     if (
     300          14 :          ( nDiffSpaceCount>0 )&&(fAvarageDiffCharSpaceValue>0)
     301             :        )
     302             :     {
     303          14 :         fAvarageDiffCharSpaceValue= fAvarageDiffCharSpaceValue/ nDiffSpaceCount;
     304             :     }
     305             : 
     306          22 :     ParagraphElement* pPara= NULL ;
     307          22 :     FrameElement* pFrame= NULL ;
     308             : 
     309          22 :     if(!m_GlyphsList.empty())
     310             :     {
     311          22 :         pFrame = m_pElFactory->createFrameElement( m_GlyphsList[0].getCurElement(), getGCId( getTransformGlyphContext( m_GlyphsList[0])) );
     312          22 :         pFrame->ZOrder = m_nNextZOrder++;
     313          22 :         pPara = m_pElFactory->createParagraphElement( pFrame );
     314             : 
     315             :         processGlyph( 0,
     316          22 :                   m_GlyphsList[0],
     317             :                   pPara,
     318             :                   pFrame,
     319          44 :                   m_bIsWhiteSpaceInLine );
     320             :     }
     321             : 
     322             : 
     323          22 :     preSpaceNull=false;
     324             : 
     325         194 :     for ( unsigned int i=1; i<m_GlyphsList.size()-1; i++ )
     326             :     {
     327         172 :         double fPrevDiffCharSpace= m_GlyphsList[i].getPrevGlyphsSpace()-m_GlyphsList[i-1].getPrevGlyphsSpace();
     328         172 :         double fPostDiffCharSpace= m_GlyphsList[i].getPrevGlyphsSpace()-m_GlyphsList[i+1].getPrevGlyphsSpace();
     329             : 
     330             : 
     331         172 :          if(
     332         172 :              preSpaceNull && (m_GlyphsList[i].getPrevGlyphsSpace()!= 0.0)
     333             :             )
     334             :          {
     335          38 :                preSpaceNull=false;
     336          38 :               if( fNullSpaceBreakerAvaregeSpaceValue > m_GlyphsList[i].getPrevGlyphsSpace() )
     337             :               {
     338             :                 processGlyph( 0,
     339           8 :                                       m_GlyphsList[i],
     340             :                               pPara,
     341             :                               pFrame,
     342          16 :                               m_bIsWhiteSpaceInLine );
     343             : 
     344             :               }
     345             :               else
     346             :               {
     347             :                 processGlyph( 1,
     348          30 :                               m_GlyphsList[i],
     349             :                               pPara,
     350             :                               pFrame,
     351          60 :                               m_bIsWhiteSpaceInLine );
     352             : 
     353             :               }
     354             : 
     355             :          }
     356             :          else
     357             :          {
     358         134 :             if (
     359         264 :                 ( ( m_GlyphsList[i].getPrevGlyphsSpace()<= fPreAvarageSpaceValue )&&
     360         130 :                   ( fPrevDiffCharSpace<=fAvarageDiffCharSpaceValue )&&
     361             :                   ( fPostDiffCharSpace<=fAvarageDiffCharSpaceValue )
     362         142 :                 ) ||
     363           8 :                 ( m_GlyphsList[i].getPrevGlyphsSpace() == 0.0 )
     364             :             )
     365             :             {
     366         126 :                 preSpaceNull=true;
     367             : 
     368             :             processGlyph( 0,
     369         126 :                         m_GlyphsList[i],
     370             :                         pPara,
     371             :                         pFrame,
     372         252 :                         m_bIsWhiteSpaceInLine );
     373             : 
     374             :             }
     375             :             else
     376             :             {
     377             :                 processGlyph( 1,
     378           8 :                         m_GlyphsList[i],
     379             :                         pPara,
     380             :                         pFrame,
     381          16 :                         m_bIsWhiteSpaceInLine );
     382             : 
     383             :             }
     384             : 
     385             :          }
     386             : 
     387             :     }
     388             : 
     389          22 :     if(m_GlyphsList.size()>1)
     390             :      processGlyph( 0,
     391          14 :                   m_GlyphsList[m_GlyphsList.size()-1],
     392             :                   pPara,
     393             :                   pFrame,
     394          28 :                   m_bIsWhiteSpaceInLine );
     395             : 
     396          22 :     m_GlyphsList.clear();
     397             : }
     398             : 
     399         208 : void PDFIProcessor::processGlyph( double       fPreAvarageSpaceValue,
     400             :                                   CharGlyph&   aGlyph,
     401             :                                   ParagraphElement* pPara,
     402             :                                   FrameElement* pFrame,
     403             :                                   bool         bIsWhiteSpaceInLine
     404             :                                       )
     405             : {
     406         208 :     if( !bIsWhiteSpaceInLine )
     407             :     {
     408           0 :         bool flag=( 0 < fPreAvarageSpaceValue );
     409             : 
     410           0 :         drawCharGlyphs(  aGlyph.getGlyph(),
     411           0 :                          aGlyph.getRect(),
     412           0 :                          aGlyph.getGC(),
     413             :                          pPara,
     414             :                          pFrame,
     415           0 :                          flag);
     416             :     }
     417             :     else
     418             :     {
     419         208 :         drawCharGlyphs( aGlyph.getGlyph(),
     420         208 :                         aGlyph.getRect(),
     421         208 :                         aGlyph.getGC(),
     422             :                         pPara,
     423             :                         pFrame,
     424         208 :                         false );
     425             :     }
     426         208 : }
     427             : 
     428         208 : void PDFIProcessor::drawGlyphLine( const OUString&             rGlyphs,
     429             :                                    const geometry::RealRectangle2D& rRect,
     430             :                                    const geometry::Matrix2D&        rFontMatrix )
     431             : {
     432         208 :     double isFirstLine= fYPrevTextPosition+ fXPrevTextPosition+ fPrevTextHeight+ fPrevTextWidth ;
     433         208 :     if(
     434         396 :         (  ( ( fYPrevTextPosition!= rRect.Y1 ) ) ||
     435         376 :            ( ( fXPrevTextPosition > rRect.X2 ) ) ||
     436         188 :            ( ( fXPrevTextPosition+fPrevTextWidth*1.3)<rRect.X1 )
     437          22 :         )  && ( isFirstLine> 0.0 )
     438             :     )
     439             :     {
     440          20 :         processGlyphLine();
     441             :     }
     442             : 
     443             :     CharGlyph aGlyph(fXPrevTextPosition, fYPrevTextPosition, fPrevTextHeight, fPrevTextWidth,
     444         208 :                m_pCurElement, getCurrentContext(), rFontMatrix, rRect, rGlyphs);
     445             : 
     446             : 
     447         208 :     getGCId(getCurrentContext());
     448             : 
     449         208 :     m_GlyphsList.push_back( aGlyph );
     450             : 
     451         208 :     fYPrevTextPosition  = rRect.Y1;
     452         208 :     fXPrevTextPosition  = rRect.X2;
     453         208 :     fPrevTextHeight     = rRect.Y2-rRect.Y1;
     454         208 :     fPrevTextWidth      = rRect.X2-rRect.X1;
     455             : 
     456         208 :     if( !m_bIsWhiteSpaceInLine )
     457             :     {
     458           2 :         static OUString tempWhiteSpaceStr( 0x20 );
     459           2 :         static OUString tempWhiteSpaceNonBreakingStr( 0xa0 );
     460           2 :         m_bIsWhiteSpaceInLine=(rGlyphs.equals( tempWhiteSpaceStr ) || rGlyphs.equals( tempWhiteSpaceNonBreakingStr ));
     461         208 :     }
     462         208 : }
     463             : 
     464          22 : GraphicsContext& PDFIProcessor::getTransformGlyphContext( CharGlyph& rGlyph )
     465             : {
     466          22 :     geometry::RealRectangle2D   rRect = rGlyph.getRect();
     467          22 :     geometry::Matrix2D          rFontMatrix = rGlyph.getFontMatrix();
     468             : 
     469          22 :     basegfx::B2DHomMatrix aFontMatrix;
     470             :     basegfx::unotools::homMatrixFromMatrix(
     471             :         aFontMatrix,
     472          22 :         rFontMatrix );
     473             : 
     474          44 :     FontAttributes aFontAttrs = m_aIdToFont[ rGlyph.getGC().FontId ];
     475             : 
     476             :     // add transformation to GC
     477          44 :     basegfx::B2DHomMatrix aFontTransform(basegfx::tools::createTranslateB2DHomMatrix(-rRect.X1, -rRect.Y1));
     478          22 :     aFontTransform *= aFontMatrix;
     479          22 :     aFontTransform.translate( rRect.X1, rRect.Y1 );
     480             : 
     481             : 
     482          22 :     rGlyph.getGC().Transformation = rGlyph.getGC().Transformation * aFontTransform;
     483          22 :     getGCId(rGlyph.getGC());
     484             : 
     485          44 :   return rGlyph.getGC();
     486             : }
     487             : 
     488         208 : void PDFIProcessor::drawCharGlyphs( OUString&             rGlyphs,
     489             :                                     geometry::RealRectangle2D& rRect,
     490             :                                     const GraphicsContext& aGC,
     491             :                                     ParagraphElement* pPara,
     492             :                                     FrameElement* pFrame,
     493             :                                     bool bSpaceFlag )
     494             : {
     495             : 
     496             : 
     497         208 :     OUString tempStr( 32 );
     498         208 :     geometry::RealRectangle2D aRect(rRect);
     499             : 
     500         208 :     ::basegfx::B2DRange aRect2;
     501             :     calcTransformedRectBounds( aRect2,
     502             :                                               ::basegfx::unotools::b2DRectangleFromRealRectangle2D(aRect),
     503         208 :                                               aGC.Transformation );
     504             :    // check whether there was a previous draw frame
     505             : 
     506         208 :     TextElement* pText = m_pElFactory->createTextElement( pPara,
     507             :                                                           getGCId(aGC),
     508         208 :                                                           aGC.FontId );
     509         208 :     if( bSpaceFlag )
     510           0 :         pText->Text.append( tempStr );
     511             : 
     512         208 :     pText->Text.append( rGlyphs );
     513             : 
     514         208 :     pText->x = aRect2.getMinX() ;
     515         208 :     pText->y = aRect2.getMinY() ;
     516         208 :     pText->w = 0.0;  // ToDO P2: 1.1 is a hack for solving of size auto-grow problem
     517         208 :     pText->h = aRect2.getHeight(); // ToDO P2: 1.1 is a hack for solving of size auto-grow problem
     518             : 
     519         208 :     pPara->updateGeometryWith( pText );
     520             : 
     521         208 :     if( pFrame )
     522         208 :       pFrame->updateGeometryWith( pPara );
     523             : 
     524         208 : }
     525             : 
     526         208 : void PDFIProcessor::drawGlyphs( const OUString&             rGlyphs,
     527             :                                 const geometry::RealRectangle2D& rRect,
     528             :                                 const geometry::Matrix2D&        rFontMatrix )
     529             : {
     530         208 :      drawGlyphLine( rGlyphs, rRect, rFontMatrix );
     531         208 : }
     532             : 
     533          22 : void PDFIProcessor::endText()
     534             : {
     535          22 :     TextElement* pText = dynamic_cast<TextElement*>(m_pCurElement);
     536          22 :     if( pText )
     537           0 :         m_pCurElement = pText->Parent;
     538          22 : }
     539             : 
     540           2 : void PDFIProcessor::setupImage(ImageId nImage)
     541             : {
     542           2 :     const GraphicsContext& rGC( getCurrentContext() );
     543             : 
     544           2 :     basegfx::B2DHomMatrix aTrans( rGC.Transformation );
     545             : 
     546             :     // check for rotation, which is the other way around in ODF
     547           4 :     basegfx::B2DTuple aScale, aTranslation;
     548             :     double fRotate, fShearX;
     549           2 :     rGC.Transformation.decompose( aScale, aTranslation, fRotate, fShearX );
     550             :     // TODDO(F4): correcting rotation when fShearX != 0 ?
     551           2 :     if( fRotate != 0.0 )
     552             :     {
     553             : 
     554             :         // try to create a Transformation that corrects for the wrong rotation
     555           0 :         aTrans.identity();
     556           0 :         aTrans.scale( aScale.getX(), aScale.getY() );
     557           0 :         aTrans.rotate( -fRotate );
     558             : 
     559           0 :         basegfx::B2DRange aRect( 0, 0, 1, 1 );
     560           0 :         aRect.transform( aTrans );
     561             : 
     562             :         // TODO(F3) treat translation correctly
     563             :         // the corrections below work for multiples of 90 degree
     564             :         // which is a common case (landscape/portrait/seascape)
     565             :         // we need a general solution here; however this needs to
     566             :         // work in sync with DrawXmlEmitter::fillFrameProps and WriterXmlEmitter::fillFrameProps
     567             :         // admittedly this is a lame workaround and fails for arbitrary rotation
     568           0 :         double fQuadrant = fmod( fRotate, 2.0*M_PI ) / M_PI_2;
     569           0 :         int nQuadrant = (int)fQuadrant;
     570           0 :         if( nQuadrant < 0 )
     571           0 :             nQuadrant += 4;
     572           0 :         if( nQuadrant == 1 )
     573             :         {
     574           0 :             aTranslation.setX( aTranslation.getX() + aRect.getHeight() + aRect.getWidth());
     575           0 :             aTranslation.setY( aTranslation.getY() + aRect.getHeight() );
     576             :         }
     577           0 :         if( nQuadrant == 3 )
     578           0 :             aTranslation.setX( aTranslation.getX() - aRect.getHeight() );
     579             : 
     580             :         aTrans.translate( aTranslation.getX(),
     581           0 :                           aTranslation.getY() );
     582             :     }
     583             : 
     584           2 :     bool bMirrorVertical = aScale.getY() > 0;
     585             : 
     586             :     // transform unit rect to determine view box
     587           2 :     basegfx::B2DRange aRect( 0, 0, 1, 1 );
     588           2 :     aRect.transform( aTrans );
     589             : 
     590             :     // TODO(F3): Handle clip
     591           2 :     const sal_Int32 nGCId = getGCId(rGC);
     592           2 :     FrameElement* pFrame = m_pElFactory->createFrameElement( m_pCurElement, nGCId );
     593           2 :     ImageElement* pImageElement = m_pElFactory->createImageElement( pFrame, nGCId, nImage );
     594           2 :     pFrame->x = pImageElement->x = aRect.getMinX();
     595           2 :     pFrame->y = pImageElement->y = aRect.getMinY();
     596           2 :     pFrame->w = pImageElement->w = aRect.getWidth();
     597           2 :     pFrame->h = pImageElement->h = aRect.getHeight();
     598           2 :     pFrame->ZOrder = m_nNextZOrder++;
     599             : 
     600           2 :     if( bMirrorVertical )
     601             :     {
     602           0 :         pFrame->MirrorVertical = pImageElement->MirrorVertical = true;
     603           0 :         pFrame->x        += aRect.getWidth();
     604           0 :         pImageElement->x += aRect.getWidth();
     605           0 :         pFrame->y        += aRect.getHeight();
     606           0 :         pImageElement->y += aRect.getHeight();
     607           2 :     }
     608           2 : }
     609             : 
     610           0 : void PDFIProcessor::drawMask(const uno::Sequence<beans::PropertyValue>& xBitmap,
     611             :                              bool                                       /*bInvert*/ )
     612             : {
     613             :     // TODO(F3): Handle mask and inversion
     614           0 :     setupImage( m_aImages.addImage(xBitmap) );
     615           0 : }
     616             : 
     617           2 : void PDFIProcessor::drawImage(const uno::Sequence<beans::PropertyValue>& xBitmap )
     618             : {
     619           2 :     setupImage( m_aImages.addImage(xBitmap) );
     620           2 : }
     621             : 
     622           0 : void PDFIProcessor::drawColorMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
     623             :                                          const uno::Sequence<uno::Any>&             /*xMaskColors*/ )
     624             : {
     625             :     // TODO(F3): Handle mask colors
     626           0 :     setupImage( m_aImages.addImage(xBitmap) );
     627           0 : }
     628             : 
     629           0 : void PDFIProcessor::drawMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
     630             :                                     const uno::Sequence<beans::PropertyValue>& /*xMask*/,
     631             :                                     bool                                       /*bInvertMask*/)
     632             : {
     633             :     // TODO(F3): Handle mask and inversion
     634           0 :     setupImage( m_aImages.addImage(xBitmap) );
     635           0 : }
     636             : 
     637           0 : void PDFIProcessor::drawAlphaMaskedImage(const uno::Sequence<beans::PropertyValue>& xBitmap,
     638             :                                          const uno::Sequence<beans::PropertyValue>& /*xMask*/)
     639             : {
     640             :     // TODO(F3): Handle mask
     641             : 
     642           0 :     setupImage( m_aImages.addImage(xBitmap) );
     643             : 
     644           0 : }
     645             : 
     646           4 : void PDFIProcessor::strokePath( const uno::Reference< rendering::XPolyPolygon2D >& rPath )
     647             : {
     648           4 :     basegfx::B2DPolyPolygon aPoly=basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
     649           4 :     aPoly.transform(getCurrentContext().Transformation);
     650             : 
     651           4 :     PolyPolyElement* pPoly = m_pElFactory->createPolyPolyElement(
     652             :         m_pCurElement,
     653           4 :         getGCId(getCurrentContext()),
     654             :         aPoly,
     655           8 :         PATH_STROKE );
     656           4 :     pPoly->updateGeometry();
     657           4 :     pPoly->ZOrder = m_nNextZOrder++;
     658           4 : }
     659             : 
     660           0 : void PDFIProcessor::fillPath( const uno::Reference< rendering::XPolyPolygon2D >& rPath )
     661             : {
     662           0 :     basegfx::B2DPolyPolygon aPoly=basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
     663           0 :     aPoly.transform(getCurrentContext().Transformation);
     664             : 
     665           0 :     PolyPolyElement* pPoly = m_pElFactory->createPolyPolyElement(
     666             :         m_pCurElement,
     667           0 :         getGCId(getCurrentContext()),
     668             :         aPoly,
     669           0 :         PATH_FILL );
     670           0 :     pPoly->updateGeometry();
     671           0 :     pPoly->ZOrder = m_nNextZOrder++;
     672           0 : }
     673             : 
     674           2 : void PDFIProcessor::eoFillPath( const uno::Reference< rendering::XPolyPolygon2D >& rPath )
     675             : {
     676           2 :     basegfx::B2DPolyPolygon aPoly=basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
     677           2 :     aPoly.transform(getCurrentContext().Transformation);
     678             : 
     679           2 :     PolyPolyElement* pPoly = m_pElFactory->createPolyPolyElement(
     680             :         m_pCurElement,
     681           2 :         getGCId(getCurrentContext()),
     682             :         aPoly,
     683           4 :         PATH_EOFILL );
     684           2 :     pPoly->updateGeometry();
     685           2 :     pPoly->ZOrder = m_nNextZOrder++;
     686           2 : }
     687             : 
     688           2 : void PDFIProcessor::intersectClip(const uno::Reference< rendering::XPolyPolygon2D >& rPath)
     689             : {
     690             :     // TODO(F3): interpret fill mode
     691           2 :     basegfx::B2DPolyPolygon aNewClip = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
     692           2 :     aNewClip.transform(getCurrentContext().Transformation);
     693           4 :     basegfx::B2DPolyPolygon aCurClip = getCurrentContext().Clip;
     694             : 
     695           2 :     if( aCurClip.count() )  // #i92985# adapted API from (..., false, false) to (..., true, false)
     696           2 :         aNewClip = basegfx::tools::clipPolyPolygonOnPolyPolygon( aCurClip, aNewClip, true, false );
     697             : 
     698           4 :     getCurrentContext().Clip = aNewClip;
     699           2 : }
     700             : 
     701           2 : void PDFIProcessor::intersectEoClip(const uno::Reference< rendering::XPolyPolygon2D >& rPath)
     702             : {
     703             :     // TODO(F3): interpret fill mode
     704           2 :     basegfx::B2DPolyPolygon aNewClip = basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(rPath);
     705           2 :     aNewClip.transform(getCurrentContext().Transformation);
     706           4 :     basegfx::B2DPolyPolygon aCurClip = getCurrentContext().Clip;
     707             : 
     708           2 :     if( aCurClip.count() )  // #i92985# adapted API from (..., false, false) to (..., true, false)
     709           2 :         aNewClip = basegfx::tools::clipPolyPolygonOnPolyPolygon( aCurClip, aNewClip, true, false );
     710             : 
     711           4 :     getCurrentContext().Clip = aNewClip;
     712           2 : }
     713             : 
     714           2 : void PDFIProcessor::hyperLink( const geometry::RealRectangle2D& rBounds,
     715             :                                const OUString&           rURI )
     716             : {
     717           2 :     if( !rURI.isEmpty() )
     718             :     {
     719           2 :         HyperlinkElement* pLink = m_pElFactory->createHyperlinkElement(
     720             :             &m_pCurPage->Hyperlinks,
     721           2 :             rURI );
     722           2 :         pLink->x = rBounds.X1;
     723           2 :         pLink->y = rBounds.Y1;
     724           2 :         pLink->w = rBounds.X2-rBounds.X1;
     725           2 :         pLink->h = rBounds.Y2-rBounds.Y1;
     726             :     }
     727           2 : }
     728             : 
     729          22 : const FontAttributes& PDFIProcessor::getFont( sal_Int32 nFontId ) const
     730             : {
     731          22 :     IdToFontMap::const_iterator it = m_aIdToFont.find( nFontId );
     732          22 :     if( it == m_aIdToFont.end() )
     733           0 :         it = m_aIdToFont.find( 0 );
     734          22 :     return it->second;
     735             : }
     736             : 
     737         468 : sal_Int32 PDFIProcessor::getGCId( const GraphicsContext& rGC )
     738             : {
     739         468 :     sal_Int32 nGCId = 0;
     740         468 :     GCToIdMap::const_iterator it = m_aGCToId.find( rGC );
     741         468 :     if( it != m_aGCToId.end() )
     742         450 :         nGCId = it->second;
     743             :     else
     744             :     {
     745          18 :         m_aGCToId[ rGC ] = m_nNextGCId;
     746          18 :         m_aIdToGC[ m_nNextGCId ] = rGC;
     747          18 :         nGCId = m_nNextGCId;
     748          18 :         m_nNextGCId++;
     749             :     }
     750             : 
     751         468 :     return nGCId;
     752             : }
     753             : 
     754         456 : const GraphicsContext& PDFIProcessor::getGraphicsContext( sal_Int32 nGCId ) const
     755             : {
     756         456 :     IdToGCMap::const_iterator it = m_aIdToGC.find( nGCId );
     757         456 :     if( it == m_aIdToGC.end() )
     758           0 :         it = m_aIdToGC.find( 0 );
     759         456 :     return it->second;
     760             : }
     761             : 
     762           2 : void PDFIProcessor::endPage()
     763             : {
     764           2 :     processGlyphLine(); // draw last line
     765           4 :     if( m_xStatusIndicator.is()
     766           0 :         && m_pCurPage
     767           2 :         && m_pCurPage->PageNumber == m_nPages
     768             :     )
     769           0 :         m_xStatusIndicator->end();
     770           2 : }
     771             : 
     772           2 : void PDFIProcessor::startPage( const geometry::RealSize2D& rSize )
     773             : {
     774             :     // initial clip is to page bounds
     775           4 :     getCurrentContext().Clip = basegfx::B2DPolyPolygon(
     776             :         basegfx::tools::createPolygonFromRect(
     777           2 :             basegfx::B2DRange( 0, 0, rSize.Width, rSize.Height )));
     778             : 
     779           2 :     sal_Int32 nNextPageNr = m_pCurPage ? m_pCurPage->PageNumber+1 : 1;
     780           2 :     if( m_xStatusIndicator.is() )
     781             :     {
     782           0 :         if( nNextPageNr == 1 )
     783           0 :             startIndicator( OUString( " " ) );
     784           0 :         m_xStatusIndicator->setValue( nNextPageNr );
     785             :     }
     786           2 :     m_pCurPage = m_pElFactory->createPageElement(m_pDocument.get(), nNextPageNr);
     787           2 :     m_pCurElement = m_pCurPage;
     788           2 :     m_pCurPage->w = rSize.Width;
     789           2 :     m_pCurPage->h = rSize.Height;
     790           2 :     m_nNextZOrder = 1;
     791             : 
     792             : 
     793           2 : }
     794             : 
     795           2 : void PDFIProcessor::emit( XmlEmitter&               rEmitter,
     796             :                           const TreeVisitorFactory& rVisitorFactory )
     797             : {
     798             : #if OSL_DEBUG_LEVEL > 1
     799             :     m_pDocument->emitStructure( 0 );
     800             : #endif
     801             : 
     802             :     ElementTreeVisitorSharedPtr optimizingVisitor(
     803           2 :         rVisitorFactory.createOptimizingVisitor(*this));
     804             :     // FIXME: localization
     805           2 :     startIndicator( OUString( " " ) );
     806           2 :     m_pDocument->visitedBy( *optimizingVisitor, std::list<Element*>::const_iterator());
     807             : 
     808             : #if OSL_DEBUG_LEVEL > 1
     809             :     m_pDocument->emitStructure( 0 );
     810             : #endif
     811             : 
     812             :     // get styles
     813           4 :     StyleContainer aStyles;
     814             :     ElementTreeVisitorSharedPtr finalizingVisitor(
     815           4 :         rVisitorFactory.createStyleCollectingVisitor(aStyles,*this));
     816             :     // FIXME: localization
     817             : 
     818           2 :     m_pDocument->visitedBy( *finalizingVisitor, std::list<Element*>::const_iterator() );
     819             : 
     820           4 :     EmitContext aContext( rEmitter, aStyles, m_aImages, *this, m_xStatusIndicator, m_xContext );
     821             :     ElementTreeVisitorSharedPtr aEmittingVisitor(
     822           4 :         rVisitorFactory.createEmittingVisitor(aContext, *this));
     823             : 
     824           4 :     PropertyMap aProps;
     825             :     // document prolog
     826             :     #define OASIS_STR "urn:oasis:names:tc:opendocument:xmlns:"
     827           2 :     aProps[ "xmlns:office" ]      = OASIS_STR "office:1.0" ;
     828           2 :     aProps[ "xmlns:style" ]       = OASIS_STR "style:1.0" ;
     829           2 :     aProps[ "xmlns:text" ]        = OASIS_STR "text:1.0" ;
     830           2 :     aProps[ "xmlns:svg" ]         = OASIS_STR "svg-compatible:1.0" ;
     831           2 :     aProps[ "xmlns:table" ]       = OASIS_STR "table:1.0" ;
     832           2 :     aProps[ "xmlns:draw" ]        = OASIS_STR "drawing:1.0" ;
     833           2 :     aProps[ "xmlns:fo" ]          = OASIS_STR "xsl-fo-compatible:1.0" ;
     834           2 :     aProps[ "xmlns:xlink"]        = "http://www.w3.org/1999/xlink";
     835           2 :     aProps[ "xmlns:dc"]           = "http://purl.org/dc/elements/1.1/";
     836           2 :     aProps[ "xmlns:number"]       = OASIS_STR "datastyle:1.0" ;
     837           2 :     aProps[ "xmlns:presentation"] = OASIS_STR "presentation:1.0" ;
     838           2 :     aProps[ "xmlns:math"]         = "http://www.w3.org/1998/Math/MathML";
     839           2 :     aProps[ "xmlns:form"]         = OASIS_STR "form:1.0" ;
     840           2 :     aProps[ "xmlns:script"]       = OASIS_STR "script:1.0" ;
     841           2 :     aProps[ "xmlns:dom"]          = "http://www.w3.org/2001/xml-events";
     842           2 :     aProps[ "xmlns:xforms"]       = "http://www.w3.org/2002/xforms";
     843           2 :     aProps[ "xmlns:xsd"]          = "http://www.w3.org/2001/XMLSchema";
     844           2 :     aProps[ "xmlns:xsi"]          = "http://www.w3.org/2001/XMLSchema-instance";
     845           2 :     aProps[ "office:version" ]    = "1.0";
     846           2 :     aProps[ "office:version" ]    = "1.0";
     847             : 
     848           2 :     aContext.rEmitter.beginTag( "office:document", aProps );
     849             : 
     850             :     // emit style list
     851           2 :     aStyles.emit( aContext, *aEmittingVisitor );
     852             : 
     853           2 :     m_pDocument->visitedBy( *aEmittingVisitor, std::list<Element*>::const_iterator() );
     854           2 :     aContext.rEmitter.endTag( "office:document" );
     855           4 :     endIndicator();
     856           2 : }
     857             : 
     858           2 : void PDFIProcessor::startIndicator( const OUString& rText, sal_Int32 nElements )
     859             : {
     860           2 :     if( nElements == -1 )
     861           2 :         nElements = m_nPages;
     862           2 :     if( m_xStatusIndicator.is() )
     863             :     {
     864           0 :         sal_Int32 nUnicodes = rText.getLength();
     865           0 :         OUStringBuffer aStr( nUnicodes*2 );
     866           0 :         const sal_Unicode* pText = rText.getStr();
     867           0 :         for( int i = 0; i < nUnicodes; i++ )
     868             :         {
     869           0 :             if( nUnicodes-i > 1&&
     870           0 :                 pText[i]   == '%' &&
     871           0 :                 pText[i+1] == 'd'
     872             :             )
     873             :             {
     874           0 :                 aStr.append( nElements );
     875           0 :                 i++;
     876             :             }
     877             :             else
     878           0 :                 aStr.append( pText[i] );
     879             :         }
     880           0 :         m_xStatusIndicator->start( aStr.makeStringAndClear(), nElements );
     881             :     }
     882           2 : }
     883             : 
     884           2 : void PDFIProcessor::endIndicator()
     885             : {
     886           2 :     if( m_xStatusIndicator.is() )
     887           0 :         m_xStatusIndicator->end();
     888           2 : }
     889             : 
     890          88 : static bool lr_tb_sort( Element* pLeft, Element* pRight )
     891             : {
     892             :     // first: top-bottom sorting
     893             : 
     894             :     // Note: allow for 10% overlap on text lines since text lines are usually
     895             :     // of the same order as font height whereas the real paint area
     896             :     // of text is usually smaller
     897          88 :     double fudge_factor = 1.0;
     898          88 :     if( dynamic_cast< TextElement* >(pLeft) || dynamic_cast< TextElement* >(pRight) )
     899           0 :         fudge_factor = 0.9;
     900             : 
     901             :     // if left's lower boundary is above right's upper boundary
     902             :     // then left is smaller
     903          88 :     if( pLeft->y+pLeft->h*fudge_factor < pRight->y )
     904          22 :         return true;
     905             :     // if right's lower boundary is above left's upper boundary
     906             :     // then left is definitely not smaller
     907          66 :     if( pRight->y+pRight->h*fudge_factor < pLeft->y )
     908          42 :         return false;
     909             : 
     910             :     // by now we have established that left and right are inside
     911             :     // a "line", that is they have vertical overlap
     912             :     // second: left-right sorting
     913             :     // if left's right boundary is left to right's left boundary
     914             :     // then left is smaller
     915          24 :     if( pLeft->x+pLeft->w < pRight->x )
     916           6 :         return true;
     917             :     // if right's right boundary is left to left's left boundary
     918             :     // then left is definitely not smaller
     919          18 :     if( pRight->x+pRight->w < pLeft->x )
     920           6 :         return false;
     921             : 
     922             :     // here we have established vertical and horizontal overlap
     923             :     // so sort left first, top second
     924          12 :     if( pLeft->x < pRight->x )
     925           8 :         return true;
     926           4 :     if( pRight->x < pLeft->x )
     927           4 :         return false;
     928           0 :     if( pLeft->y < pRight->y )
     929           0 :         return true;
     930             : 
     931           0 :     return false;
     932             : }
     933             : 
     934           2 : void PDFIProcessor::sortElements( Element* pEle, bool bDeep )
     935             : {
     936           2 :     if( pEle->Children.empty() )
     937           2 :         return;
     938             : 
     939           2 :     if( bDeep )
     940             :     {
     941           0 :         for( std::list< Element* >::iterator it = pEle->Children.begin();
     942           0 :              it != pEle->Children.end(); ++it )
     943             :         {
     944           0 :             sortElements( *it, bDeep );
     945             :         }
     946             :     }
     947             :     // HACK: the stable sort member on std::list that takes a
     948             :     // strict weak ordering requires member templates - which we
     949             :     // do not have on all compilers. so we need to use std::stable_sort
     950             :     // here - which does need random access iterators which the
     951             :     // list iterators are not.
     952             :     // so we need to copy the Element* to an array, stable sort that and
     953             :     // copy them back.
     954           2 :     std::vector<Element*> aChildren;
     955          34 :     while( ! pEle->Children.empty() )
     956             :     {
     957          30 :         aChildren.push_back( pEle->Children.front() );
     958          30 :         pEle->Children.pop_front();
     959             :     }
     960           2 :     switch( m_eTextDirection )
     961             :     {
     962             :         case LrTb:
     963             :         default:
     964           2 :         std::stable_sort( aChildren.begin(), aChildren.end(), lr_tb_sort );
     965           2 :         break;
     966             :     }
     967           2 :     int nChildren = aChildren.size();
     968          32 :     for( int i = 0; i < nChildren; i++ )
     969          32 :         pEle->Children.push_back( aChildren[i] );
     970             : }
     971             : 
     972             : 
     973         208 : ::basegfx::B2DRange& PDFIProcessor::calcTransformedRectBounds( ::basegfx::B2DRange&         outRect,
     974             :                                                         const ::basegfx::B2DRange&      inRect,
     975             :                                                         const ::basegfx::B2DHomMatrix&  transformation )
     976             :         {
     977         208 :             outRect.reset();
     978             : 
     979         208 :             if( inRect.isEmpty() )
     980           0 :                 return outRect;
     981             : 
     982             :             // transform all four extremal points of the rectangle,
     983             :             // take bounding rect of those.
     984             : 
     985             :             // transform left-top point
     986         208 :             outRect.expand( transformation * inRect.getMinimum() );
     987             : 
     988             :             // transform bottom-right point
     989         208 :             outRect.expand( transformation * inRect.getMaximum() );
     990             : 
     991         208 :             ::basegfx::B2DPoint aPoint;
     992             : 
     993             :             // transform top-right point
     994         208 :             aPoint.setX( inRect.getMaxX() );
     995         208 :             aPoint.setY( inRect.getMinY() );
     996             : 
     997         208 :             aPoint *= transformation;
     998         208 :             outRect.expand( aPoint );
     999             : 
    1000             :             // transform bottom-left point
    1001         208 :             aPoint.setX( inRect.getMinX() );
    1002         208 :             aPoint.setY( inRect.getMaxY() );
    1003             : 
    1004         208 :             aPoint *= transformation;
    1005         208 :             outRect.expand( aPoint );
    1006             : 
    1007             :             // over and out.
    1008         208 :             return outRect;
    1009             :         }
    1010             : 
    1011             : // helper method: get a mirrored string
    1012           0 : OUString PDFIProcessor::mirrorString( const OUString& i_rString ) const
    1013             : {
    1014           0 :     const sal_Int32 nLen = i_rString.getLength();
    1015           0 :     OUStringBuffer aMirror( nLen );
    1016             : 
    1017           0 :     sal_Int32 i = 0;
    1018           0 :     while(i < nLen)
    1019             :     {
    1020             :         // read one code point
    1021           0 :         const sal_uInt32 nCodePoint = i_rString.iterateCodePoints( &i );
    1022             : 
    1023             :         // and append it mirrored
    1024           0 :         aMirror.appendUtf32( GetMirroredChar(nCodePoint) );
    1025             :     }
    1026           0 :     return aMirror.makeStringAndClear();
    1027             : }
    1028             : 
    1029           3 : }
    1030             : 
    1031             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10