LCOV - code coverage report
Current view: top level - filter/source/flash - swfwriter1.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 0 882 0.0 %
Date: 2014-04-11 Functions: 0 37 0.0 %
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             : #include <com/sun/star/i18n/BreakIterator.hpp>
      21             : #include <com/sun/star/i18n/ScriptType.hpp>
      22             : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
      23             : #include <comphelper/processfactory.hxx>
      24             : #include "swfwriter.hxx"
      25             : #include <vcl/metaact.hxx>
      26             : #include <vcl/gdimtf.hxx>
      27             : #include <vcl/bmpacc.hxx>
      28             : #include <vcl/virdev.hxx>
      29             : #include <vcl/metric.hxx>
      30             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      31             : #include <vcl/graphicfilter.hxx>
      32             : #include <vcl/graphictools.hxx>
      33             : 
      34             : #include <zlib.h>
      35             : 
      36             : #include <vcl/salbtype.hxx>
      37             : #include <basegfx/polygon/b2dpolygon.hxx>
      38             : #include <basegfx/polygon/b2dpolypolygon.hxx>
      39             : #include <boost/scoped_array.hpp>
      40             : 
      41             : using namespace ::swf;
      42             : using namespace ::std;
      43             : using namespace ::rtl;
      44             : using namespace ::com::sun::star::i18n;
      45             : using namespace ::com::sun::star::uno;
      46             : using namespace ::com::sun::star::lang;
      47             : using namespace ::com::sun::star::io;
      48             : using namespace ::com::sun::star::beans;
      49             : 
      50             : extern sal_uInt16 getMaxBitsUnsigned( sal_uInt32 nValue );
      51             : extern sal_uInt16 getMaxBitsSigned( sal_Int32 nValue );
      52             : 
      53           0 : static MapMode aTWIPSMode( MAP_TWIP );
      54           0 : static MapMode a100thmmMode( MAP_100TH_MM );
      55             : 
      56             : 
      57             : 
      58           0 : Point Writer::map( const Point& rPoint ) const
      59             : {
      60           0 :     const MapMode& aSourceMapMode = mpVDev->GetMapMode();
      61             : 
      62           0 :     Point retPoint = mpVDev->LogicToLogic( rPoint,  &aSourceMapMode, &aTWIPSMode );
      63             : 
      64             :     // AS: Produces a 'possible loss of data' warning that we can't fix without
      65             :     //  hurting code readability.
      66           0 :     retPoint.X() = (long)( retPoint.X() * mnDocXScale );
      67           0 :     retPoint.Y() = (long)( retPoint.Y() * mnDocYScale );
      68             : 
      69           0 :     return retPoint;
      70             : }
      71             : 
      72             : 
      73             : 
      74           0 : Size Writer::map( const Size& rSize ) const
      75             : {
      76           0 :     const MapMode& aSourceMapMode = mpVDev->GetMapMode();
      77             : 
      78           0 :     Size retSize = mpVDev->LogicToLogic( rSize,  &aSourceMapMode, &aTWIPSMode );
      79             : 
      80             :     // AS: Produces a 'possible loss of data' warning that we can't fix without
      81             :     //  hurting code readability.
      82           0 :     retSize.Width() = (long)( retSize.Width() * mnDocXScale );
      83           0 :     retSize.Height() = (long)( retSize.Height() * mnDocYScale );
      84             : 
      85           0 :     return retSize;
      86             : }
      87             : 
      88             : 
      89             : 
      90           0 : void Writer::map( PolyPolygon& rPolyPolygon ) const
      91             : {
      92           0 :     const sal_uInt16 nPolyCount = rPolyPolygon.Count();
      93           0 :     if( nPolyCount )
      94             :     {
      95             :         sal_uInt16 nPoly, nPoint, nPointCount;
      96           0 :         for( nPoly = 0; nPoly < nPolyCount; nPoly++ )
      97             :         {
      98           0 :             Polygon& rPoly = rPolyPolygon[nPoly];
      99           0 :             nPointCount = rPoly.GetSize();
     100             : 
     101           0 :             for( nPoint = 0; nPoint < nPointCount; nPoint++ )
     102             :             {
     103           0 :                 rPoly[nPoint] = map( rPoly[nPoint] );
     104             :             }
     105             :         }
     106             :     }
     107           0 : }
     108             : 
     109             : 
     110             : 
     111           0 : sal_Int32 Writer::mapRelative( sal_Int32 n100thMM ) const
     112             : {
     113           0 :     MapMode aSourceMapMode( mpVDev->GetMapMode() );
     114           0 :     aSourceMapMode.SetOrigin( Point() );
     115             : 
     116           0 :     sal_Int32 nTwips = mpVDev->LogicToLogic( Point( n100thMM, n100thMM ),  &aSourceMapMode, &aTWIPSMode ).X();
     117           0 :     return nTwips;
     118             : }
     119             : 
     120             : 
     121             : 
     122             : /**
     123             : */
     124           0 : void Writer::Impl_addPolygon( BitStream& rBits, const Polygon& rPoly, sal_Bool bFilled )
     125             : {
     126           0 :     Point aLastPoint( rPoly[0] );
     127             : 
     128           0 :     Impl_addShapeRecordChange( rBits, _Int16(aLastPoint.X()),_Int16(aLastPoint.Y()), bFilled );
     129             : 
     130           0 :     sal_uInt16 i = 0, nSize = rPoly.GetSize();
     131             : 
     132           0 :     double d = 16.0f;
     133             : 
     134             :     // points
     135           0 :     while( ( i + 1 ) < nSize )
     136             :     {
     137           0 :         if( ( i + 3 ) < nSize )
     138             :         {
     139           0 :             PolyFlags P1( rPoly.GetFlags( i ) );
     140           0 :             PolyFlags P4( rPoly.GetFlags( i + 3 ) );
     141             : 
     142           0 :             if( ( POLY_NORMAL == P1 || POLY_SMOOTH == P1 || POLY_SYMMTR == P1 ) &&
     143           0 :                 ( POLY_CONTROL == rPoly.GetFlags( i + 1 ) ) &&
     144           0 :                 ( POLY_CONTROL == rPoly.GetFlags( i + 2 ) ) &&
     145           0 :                 ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
     146             :             {
     147             :                 Impl_quadBezierApprox( rBits, aLastPoint, d*d,
     148           0 :                                       rPoly.GetPoint( i ).X(),   rPoly.GetPoint( i ).Y(),
     149           0 :                                       rPoly.GetPoint( i+1 ).X(), rPoly.GetPoint( i+1 ).Y(),
     150           0 :                                       rPoly.GetPoint( i+2 ).X(), rPoly.GetPoint( i+2 ).Y(),
     151           0 :                                       rPoly.GetPoint( i+3 ).X(), rPoly.GetPoint( i+3 ).Y() );
     152           0 :                 i += 3;
     153           0 :                 continue;
     154             :             }
     155             :         }
     156             : 
     157           0 :         ++i;
     158             : 
     159           0 :         const Point aPolyPoint( rPoly[ i ] );
     160           0 :         if( aPolyPoint != aLastPoint )
     161             :         {
     162           0 :             Impl_addStraightEdgeRecord( rBits, _Int16(aPolyPoint.X() - aLastPoint.X()),_Int16(aPolyPoint.Y() - aLastPoint.Y()));
     163           0 :             aLastPoint = aPolyPoint;
     164             :         }
     165             :     }
     166             : 
     167           0 :     if( bFilled && (rPoly[0] != rPoly[nSize-1]))
     168             :     {
     169           0 :         const Point aPolyPoint( rPoly[ 0 ] );
     170           0 :         if( aPolyPoint != aLastPoint )
     171             :         {
     172           0 :             Impl_addStraightEdgeRecord( rBits, _Int16(aPolyPoint.X() - aLastPoint.X()),_Int16(aPolyPoint.Y() - aLastPoint.Y()));
     173             :         }
     174             :     }
     175           0 : }
     176             : 
     177             : 
     178             : 
     179             : /** exports a style change record with a move to (x,y) and depending on bFilled a line style 1 or fill style 1
     180             : */
     181           0 : void Writer::Impl_addShapeRecordChange( BitStream& rBits, sal_Int16 dx, sal_Int16 dy, sal_Bool bFilled )
     182             : {
     183           0 :     rBits.writeUB( 0, 1 );          // TypeFlag
     184           0 :     rBits.writeUB( 0, 1 );          // StateNewStyles
     185           0 :     rBits.writeUB( sal_uInt32(!bFilled), 1 ); // StateLineStyle
     186           0 :     rBits.writeUB( 0, 1 );          // StateFillStyle0
     187           0 :     rBits.writeUB( bFilled, 1 );        // StateFillStyle1
     188           0 :     rBits.writeUB( 1, 1 );          // StateMoveTo
     189             : 
     190           0 :     sal_uInt16 nMoveBits = max( getMaxBitsSigned( dx ), getMaxBitsSigned( dy ) );
     191             : 
     192           0 :     rBits.writeUB( nMoveBits, 5 );  // Number of bits per value
     193             :                                     // TODO: Optimize horizontal and vertical lines
     194           0 :     rBits.writeSB( dx, nMoveBits ); // DeltaX
     195           0 :     rBits.writeSB( dy, nMoveBits ); // DeltaY
     196             : 
     197           0 :     rBits.writeUB( 1, 1 );          // set FillStyle1 or LineStyle to 1
     198           0 : }
     199             : 
     200             : 
     201             : 
     202             : /** exports a straight edge record
     203             : */
     204           0 : void Writer::Impl_addStraightEdgeRecord( BitStream& rBits, sal_Int16 dx, sal_Int16 dy )
     205             : {
     206           0 :     rBits.writeUB( 1, 1 );          // TypeFlag
     207           0 :     rBits.writeUB( 1, 1 );          // StraightFlag
     208             : 
     209           0 :     sal_uInt16 nBits = max( getMaxBitsSigned( dx ), getMaxBitsSigned( dy ) );
     210             : 
     211           0 :     rBits.writeUB( nBits - 2, 4 );  // Number of bits per value
     212             : 
     213           0 :     if( (dx != 0) && (dy != 0) )
     214             :     {
     215           0 :         rBits.writeUB( 1, 1 );          // GeneralLineFlag
     216           0 :         rBits.writeSB( dx, nBits );     // DeltaX
     217           0 :         rBits.writeSB( dy, nBits );     // DeltaY
     218             :     }
     219             :     else
     220             :     {
     221           0 :         rBits.writeUB( 0, 1 );
     222           0 :         rBits.writeUB( sal_uInt32( dx == 0 ), 1 );
     223           0 :         if( dx == 0 )
     224             :         {
     225           0 :             rBits.writeSB( dy, nBits );     // DeltaY
     226             :         }
     227             :         else
     228             :         {
     229           0 :             rBits.writeSB( dx, nBits );     // DeltaX
     230             :         }
     231             :     }
     232           0 : }
     233             : 
     234             : 
     235             : 
     236             : /** exports a curved edge record
     237             : */
     238           0 : void Writer::Impl_addCurvedEdgeRecord( BitStream& rBits, sal_Int16 control_dx, sal_Int16 control_dy, sal_Int16 anchor_dx, sal_Int16 anchor_dy )
     239             : {
     240           0 :     rBits.writeUB( 1, 1 );          // TypeFlag
     241           0 :     rBits.writeUB( 0, 1 );          // CurvedFlag
     242             : 
     243             :     sal_uInt8 nBits = static_cast<sal_uInt8>(
     244           0 :         max( getMaxBitsSigned( control_dx ),
     245           0 :             max( getMaxBitsSigned( control_dy ),
     246           0 :                 max( getMaxBitsSigned( anchor_dx ),
     247           0 :                     max( getMaxBitsSigned( anchor_dy ), (sal_uInt16)3 ) ) ) ) );
     248             : 
     249           0 :     rBits.writeUB( nBits - 2, 4 );  // Number of bits per value
     250             : 
     251           0 :     rBits.writeSB( control_dx, nBits );     // DeltaX
     252           0 :     rBits.writeSB( control_dy, nBits );     // DeltaY
     253           0 :     rBits.writeSB( anchor_dx, nBits );      // DeltaX
     254           0 :     rBits.writeSB( anchor_dy, nBits );      // DeltaY
     255           0 : }
     256             : 
     257             : 
     258             : 
     259             : /** exports a end shape record
     260             : */
     261           0 : void Writer::Impl_addEndShapeRecord( BitStream& rBits )
     262             : {
     263           0 :     rBits.writeUB( 0, 6 );
     264           0 : }
     265             : 
     266             : 
     267             : 
     268           0 : void Writer::Impl_writePolygon( const Polygon& rPoly, sal_Bool bFilled )
     269             : {
     270           0 :     PolyPolygon aPolyPoly( rPoly );
     271           0 :     Impl_writePolyPolygon( aPolyPoly, bFilled );
     272           0 : }
     273             : 
     274             : 
     275             : 
     276           0 : void Writer::Impl_writePolygon( const Polygon& rPoly, sal_Bool bFilled, const Color& rFillColor, const Color& rLineColor )
     277             : {
     278           0 :     PolyPolygon aPolyPoly( rPoly );
     279           0 :     Impl_writePolyPolygon( aPolyPoly, bFilled, rFillColor, rLineColor );
     280           0 : }
     281             : 
     282             : 
     283             : 
     284           0 : void Writer::Impl_writePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bFilled, sal_uInt8 nTransparence /* = 0 */ )
     285             : {
     286           0 :     Color aLineColor( mpVDev->GetLineColor() );
     287           0 :     if( 0 == aLineColor.GetTransparency() )
     288           0 :         aLineColor.SetTransparency( nTransparence );
     289           0 :     Color aFillColor( mpVDev->GetFillColor() );
     290           0 :     if( 0 == aFillColor.GetTransparency() )
     291           0 :         aFillColor.SetTransparency( nTransparence );
     292           0 :     Impl_writePolyPolygon(rPolyPoly, bFilled, aFillColor, aLineColor );
     293           0 : }
     294             : 
     295             : 
     296             : 
     297           0 : void Writer::Impl_writePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bFilled, const Color& rFillColor, const Color& rLineColor )
     298             : {
     299           0 :     PolyPolygon aPolyPoly( rPolyPoly );
     300             : 
     301           0 :     if( aPolyPoly.Count() )
     302             :     {
     303           0 :         map( aPolyPoly );
     304             : 
     305           0 :         if( mpClipPolyPolygon )
     306           0 :             rPolyPoly.GetIntersection( *mpClipPolyPolygon, aPolyPoly );
     307             : 
     308             :         sal_uInt16 nID;
     309           0 :         if( bFilled )
     310             :         {
     311           0 :             Color aFillColor( rFillColor );
     312           0 :             if( 0 != mnGlobalTransparency )
     313           0 :                 aFillColor.SetTransparency( mnGlobalTransparency );
     314             : 
     315           0 :             FillStyle aStyle( aFillColor );
     316           0 :             nID = defineShape( aPolyPoly, aStyle );
     317             :         }
     318             :         else
     319             :         {
     320           0 :             Color aLineColor( rLineColor );
     321           0 :             if( 0 != mnGlobalTransparency )
     322           0 :                 aLineColor.SetTransparency( mnGlobalTransparency );
     323             : 
     324           0 :             nID = defineShape( aPolyPoly, 1, aLineColor );
     325             :         }
     326           0 :         maShapeIds.push_back( nID );
     327           0 :     }
     328           0 : }
     329             : 
     330             : 
     331             : 
     332             : /** a gradient is a transition from one color to another, rendered inside a given polypolygon */
     333           0 : void Writer::Impl_writeGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient )
     334             : {
     335           0 :     if( rPolyPoly.Count() )
     336             :     {
     337           0 :         PolyPolygon aPolyPolygon( rPolyPoly );
     338           0 :         map( aPolyPolygon );
     339             : 
     340           0 :         if( (rGradient.GetStyle() == GradientStyle_LINEAR && rGradient.GetAngle() == 900) || (rGradient.GetStyle() == GradientStyle_RADIAL)  )
     341             :         {
     342           0 :             const Rectangle aBoundRect( aPolyPolygon.GetBoundRect() );
     343             : 
     344           0 :             FillStyle aFillStyle( aBoundRect, rGradient );
     345             : 
     346           0 :             sal_uInt16 nShapeId = defineShape( aPolyPolygon, aFillStyle );
     347           0 :             maShapeIds.push_back( nShapeId );
     348             :         }
     349             :         else
     350             :         {
     351           0 :             setClipping( &aPolyPolygon );
     352             : 
     353             :             // render the gradient filling to simple polygons
     354             :             {
     355           0 :                 GDIMetaFile aTmpMtf;
     356           0 :                 mpVDev->AddGradientActions( aPolyPolygon.GetBoundRect(), rGradient, aTmpMtf );
     357           0 :                 Impl_writeActions( aTmpMtf );
     358             :             }
     359             : 
     360           0 :             setClipping( NULL );
     361           0 :         }
     362             :     }
     363           0 : }
     364             : 
     365             : 
     366             : 
     367           0 : void Writer::setClipping( const PolyPolygon* pClipPolyPolygon )
     368             : {
     369           0 :     mpClipPolyPolygon = pClipPolyPolygon;
     370           0 : }
     371             : 
     372             : 
     373             : 
     374             : // AS: Just comparing fonts straight up is too literal.  There are some
     375             : //  differences in font that actually require different glyphs to be defined,
     376             : //  and some that don't.  This function is meant to capture all the differences
     377             : //  that we care about.
     378           0 : bool compare_fonts_for_me(const Font& rFont1, const Font& rFont2)
     379             : {
     380           0 :     return rFont1.GetName() == rFont2.GetName() &&
     381           0 :             rFont1.GetWeight() == rFont2.GetWeight() &&
     382           0 :             rFont1.GetItalic() == rFont2.GetItalic() &&
     383           0 :             rFont1.IsOutline() == rFont2.IsOutline() &&
     384           0 :             rFont1.IsShadow() == rFont2.IsShadow() &&
     385           0 :             rFont1.GetRelief() == rFont2.GetRelief();
     386             : }
     387             : 
     388             : 
     389             : 
     390           0 : FlashFont& Writer::Impl_getFont( const Font& rFont )
     391             : {
     392           0 :     FontMap::iterator aIter( maFonts.begin() );
     393           0 :     const FontMap::iterator aEnd( maFonts.end() );
     394             : 
     395           0 :     for(; aIter != aEnd; ++aIter)
     396             :     {
     397           0 :         const Font tempFont = (*aIter)->getFont();
     398           0 :         if( compare_fonts_for_me(tempFont, rFont) )
     399             :         {
     400           0 :             return **aIter;
     401             :         }
     402           0 :     }
     403             : 
     404           0 :     FlashFont* pFont = new FlashFont( rFont, createID() );
     405           0 :     maFonts.push_back( pFont );
     406           0 :     return *pFont;
     407             : }
     408             : 
     409             : 
     410             : 
     411           0 : void Writer::Impl_writeText( const Point& rPos, const OUString& rText, const sal_Int32* pDXArray, long nWidth )
     412             : {
     413           0 :     const FontMetric aMetric( mpVDev->GetFontMetric() );
     414             : 
     415           0 :     bool bTextSpecial = aMetric.IsShadow() || aMetric.IsOutline() || (aMetric.GetRelief() != RELIEF_NONE);
     416             : 
     417           0 :     if( !bTextSpecial )
     418             :     {
     419           0 :         Impl_writeText( rPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
     420             :     }
     421             :     else
     422             :     {
     423           0 :         if( aMetric.GetRelief() != RELIEF_NONE )
     424             :         {
     425           0 :             Color aReliefColor( COL_LIGHTGRAY );
     426           0 :             Color aTextColor( mpVDev->GetTextColor() );
     427             : 
     428           0 :             if ( aTextColor.GetColor() == COL_BLACK )
     429           0 :                 aTextColor = Color( COL_WHITE );
     430             : 
     431           0 :             if ( aTextColor.GetColor() == COL_WHITE )
     432           0 :                 aReliefColor = Color( COL_BLACK );
     433             : 
     434             : 
     435           0 :             Point aPos( rPos );
     436           0 :             Point aOffset( 6,6 );
     437             : 
     438           0 :             if ( aMetric.GetRelief() == RELIEF_ENGRAVED )
     439             :             {
     440           0 :                 aPos -= aOffset;
     441             :             }
     442             :             else
     443             :             {
     444           0 :                 aPos += aOffset;
     445             :             }
     446             : 
     447           0 :             Impl_writeText( aPos, rText, pDXArray, nWidth, aReliefColor );
     448           0 :             Impl_writeText( rPos, rText, pDXArray, nWidth, aTextColor );
     449             :         }
     450             :         else
     451             :         {
     452           0 :             if( aMetric.IsShadow() )
     453             :             {
     454           0 :                 long nOff = 1 + ((aMetric.GetLineHeight()-24)/24);
     455           0 :                 if ( aMetric.IsOutline() )
     456           0 :                     nOff += 6;
     457             : 
     458           0 :                 Color aTextColor( mpVDev->GetTextColor() );
     459           0 :                 Color aShadowColor = Color( COL_BLACK );
     460             : 
     461           0 :                 if ( (aTextColor.GetColor() == COL_BLACK) || (aTextColor.GetLuminance() < 8) )
     462           0 :                     aShadowColor = Color( COL_LIGHTGRAY );
     463             : 
     464           0 :                 Point aPos( rPos );
     465           0 :                 aPos += Point( nOff, nOff );
     466           0 :                 Impl_writeText( aPos, rText, pDXArray, nWidth, aShadowColor );
     467             : 
     468           0 :                 if( !aMetric.IsOutline() )
     469             :                 {
     470           0 :                     Impl_writeText( rPos, rText, pDXArray, nWidth, aTextColor );
     471             :                 }
     472             :             }
     473             : 
     474           0 :             if( aMetric.IsOutline() )
     475             :             {
     476           0 :                 Point aPos = rPos + Point( -6, -6 );
     477           0 :                 Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
     478           0 :                 aPos = rPos + Point(+6,+6);
     479           0 :                 Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
     480           0 :                 aPos = rPos + Point(-6,+0);
     481           0 :                 Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
     482           0 :                 aPos = rPos + Point(-6,+6);
     483           0 :                 Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
     484           0 :                 aPos = rPos + Point(+0,+6);
     485           0 :                 Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
     486           0 :                 aPos = rPos + Point(+0,-6);
     487           0 :                 Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
     488           0 :                 aPos = rPos + Point(+6,-1);
     489           0 :                 Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
     490           0 :                 aPos = rPos + Point(+6,+0);
     491           0 :                 Impl_writeText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
     492             : 
     493           0 :                 Impl_writeText( rPos, rText, pDXArray, nWidth, Color( COL_WHITE ) );
     494             :             }
     495             :         }
     496           0 :     }
     497           0 : }
     498             : 
     499           0 : void Writer::Impl_writeText( const Point& rPos, const OUString& rText, const sal_Int32* pDXArray, long nWidth, Color aTextColor )
     500             : {
     501           0 :     sal_Int32 nLen = rText.getLength();
     502             : 
     503           0 :     if( !nLen )
     504           0 :         return;
     505             : 
     506           0 :     const bool bRTL = (mpVDev->GetLayoutMode() & TEXT_LAYOUT_BIDI_RTL) != 0;
     507             : 
     508           0 :     sal_Int16 nScriptType = ScriptType::LATIN;
     509           0 :     Reference < XBreakIterator > xBI( Impl_GetBreakIterator() );
     510           0 :     if( xBI.is() )
     511             :     {
     512           0 :         const OUString oText( rText );
     513           0 :         nScriptType = xBI->getScriptType( oText, 0 );
     514             :     }
     515             : 
     516             :     // if the text is either right to left or complex or asian, we
     517             :     // ask the output device for a polygon representation.
     518             :     // On complex and asian text, each unicode character can have
     519             :     // different glyph representation, based on context. Also positioning
     520             :     // is not trivial so we let the output device do it for us.
     521           0 :     if( bRTL || (nScriptType != ScriptType::LATIN) )
     522             :     {
     523             :         // todo: optimize me as this will generate a huge amount of duplicate polygons
     524           0 :         PolyPolygon aPolyPoygon;
     525           0 :         mpVDev->GetTextOutline( aPolyPoygon, rText, 0, 0, (sal_uInt16)nLen, true, nWidth, pDXArray );
     526           0 :         aPolyPoygon.Translate( rPos );
     527           0 :         Impl_writePolyPolygon( aPolyPoygon, sal_True, aTextColor, aTextColor );
     528             :     }
     529             :     else
     530             :     {
     531           0 :         Size    aNormSize;
     532           0 :         boost::scoped_array<sal_Int32> pOwnArray;
     533             :         sal_Int32* pDX;
     534             : 
     535             :         // get text sizes
     536           0 :         if( pDXArray )
     537             :         {
     538           0 :             aNormSize = Size( mpVDev->GetTextWidth( rText ), 0 );
     539           0 :             pDX = (sal_Int32*) pDXArray;
     540             :         }
     541             :         else
     542             :         {
     543           0 :             pOwnArray.reset(new sal_Int32[ nLen ]);
     544           0 :             aNormSize = Size( mpVDev->GetTextArray( rText, pOwnArray.get() ), 0 );
     545           0 :             pDX = pOwnArray.get();
     546             :         }
     547             : 
     548           0 :         if( nLen > 1 )
     549             :         {
     550           0 :             aNormSize.Width() = pDX[ nLen - 2 ] + mpVDev->GetTextWidth( OUString(rText[nLen - 1]) );
     551             : 
     552           0 :             if( nWidth && aNormSize.Width() && ( nWidth != aNormSize.Width() ) )
     553             :             {
     554           0 :                 const double fFactor = (double) nWidth / aNormSize.Width();
     555             : 
     556           0 :                 for( sal_Int32 i = 0; i < ( nLen - 1 ); i++ )
     557           0 :                     pDX[ i ] = FRound( pDX[ i ] * fFactor );
     558             :             }
     559             :         }
     560             : 
     561           0 :         Font aOldFont( mpVDev->GetFont() );
     562           0 :         Point               aBaseLinePos( rPos );
     563             : 
     564           0 :         Font aFont(aOldFont);
     565           0 :         short nOrientation = aFont.GetOrientation();
     566           0 :         aFont.SetOrientation( 0 );
     567           0 :         aFont.SetUnderline(UNDERLINE_NONE);
     568           0 :         aFont.SetStrikeout(STRIKEOUT_NONE);
     569           0 :         mpVDev->SetFont( aFont );
     570             : 
     571           0 :         const FontMetric    aMetric( mpVDev->GetFontMetric() );
     572             : 
     573           0 :         FlashFont&          rFlashFont = Impl_getFont( aFont );
     574             : 
     575             :         // always adjust text position to match baseline alignment
     576           0 :         switch( aOldFont.GetAlign() )
     577             :         {
     578             :             case( ALIGN_TOP ):
     579           0 :                 aBaseLinePos.Y() += aMetric.GetAscent();
     580           0 :             break;
     581             : 
     582             :             case( ALIGN_BOTTOM ):
     583           0 :                 aBaseLinePos.Y() -= aMetric.GetDescent();
     584           0 :             break;
     585             : 
     586             :             default:
     587           0 :             break;
     588             :         }
     589             : 
     590             :         // get mapped text position
     591           0 :         const Point aPt( map( aBaseLinePos ) );
     592             : 
     593             :         // write text element
     594             : 
     595             : #if 0 // makes the calculated bound rect visible for debuging
     596             : {
     597             :         Polygon aTmpPoly( aPoly );
     598             :         sal_uInt16 nID = FlashGeometryExporter::writePolygonShape( aMovieStream, aTmpPoly, false, Color(COL_MAGENTA), Color(COL_MAGENTA), mpClipPolyPolygon  );
     599             :         ImplPlaceObject( nID );
     600             : }
     601             : #endif
     602             : 
     603             :         // CL: This is still a hack until we figure out how to calculate a correct bound rect
     604             :         //     for rotatet text
     605           0 :         Rectangle textBounds( 0, 0, static_cast<long>(mnDocWidth*mnDocXScale), static_cast<long>(mnDocHeight*mnDocYScale) );
     606           0 :         double scale = 1.0;
     607             : 
     608             :         // scale width if we have a stretched text
     609           0 :         if( 0 != aFont.GetSize().Width() )
     610             :         {
     611           0 :             Font aTmpFont( aFont );
     612           0 :             aTmpFont.SetWidth(0);
     613           0 :             mpVDev->SetFont( aTmpFont );
     614             : 
     615           0 :             const FontMetric aMetric2( mpVDev->GetFontMetric() );
     616           0 :             mpVDev->SetFont( aFont );
     617             : 
     618           0 :             const long n1 = aFont.GetSize().Width();
     619           0 :             const long n2 = aMetric2.GetSize().Width();
     620           0 :             scale =  (double)n1 / (double)n2;
     621             :         }
     622             : 
     623           0 :         basegfx::B2DHomMatrix m(basegfx::tools::createRotateB2DHomMatrix(static_cast<double>(nOrientation) * F_PI1800));
     624           0 :         m.translate( double(aPt.X() / scale), double(aPt.Y()) );
     625           0 :         m.scale( scale, scale );
     626             : 
     627           0 :         sal_Int16 nHeight = _Int16( map( Size( 0, aFont.GetHeight() ) ).Height() );
     628             : 
     629           0 :         startTag( TAG_DEFINETEXT );
     630             : 
     631           0 :         sal_uInt16 nTextId = createID();
     632             : 
     633           0 :         mpTag->addUI16( nTextId );
     634           0 :         mpTag->addRect( textBounds );
     635           0 :         mpTag->addMatrix( m );
     636             : 
     637           0 :         sal_uInt8 nGlyphBits = 16;
     638           0 :         sal_uInt8 nAdvanceBits = 16;
     639             : 
     640           0 :         mpTag->addUI8( nGlyphBits );
     641           0 :         mpTag->addUI8( nAdvanceBits );
     642             : 
     643             :         // text style change record
     644           0 :         mpTag->addUI8( 0x8c );
     645           0 :         mpTag->addUI16( rFlashFont.getID() );
     646           0 :         mpTag->addRGB( aTextColor );
     647           0 :         mpTag->addUI16( _uInt16( nHeight ) );
     648             : 
     649             :         DBG_ASSERT( nLen <= 127, "TODO: handle text with more than 127 characters" );
     650             : 
     651             :         // Glyph record
     652           0 :         mpTag->addUI8( (sal_uInt8) nLen );
     653             : 
     654           0 :         BitStream aBits;
     655             : 
     656           0 :         sal_Int32 nLastDX = 0;
     657             :         sal_Int32 nAdvance;
     658           0 :         for( sal_Int32 i = 0; i < nLen; i++  )
     659             :         {
     660           0 :             if( i < (nLen-1) )
     661             :             {
     662           0 :                 nAdvance = pDX[i] - nLastDX;
     663           0 :                 nLastDX = pDX[i];
     664             :             }
     665             :             else
     666             :             {
     667           0 :                 nAdvance = 0;
     668             :             }
     669             : 
     670           0 :             aBits.writeUB( rFlashFont.getGlyph(rText[i],mpVDev), nGlyphBits );
     671           0 :             aBits.writeSB( _Int16(map( Size( (long)( nAdvance / scale ), 0 ) ).Width() ), nAdvanceBits );
     672             :         }
     673             : 
     674           0 :         mpTag->addBits( aBits );
     675           0 :         mpTag->addUI8( 0 );
     676             : 
     677           0 :         endTag();
     678             : 
     679           0 :         maShapeIds.push_back( nTextId );
     680             : 
     681             :         // AS: Write strikeout and underline, if necessary.  This code was originally taken from the SVG
     682             :         //  export facility, although the positioning had to be tweaked a little.  I can't explain the
     683             :         //  numbers, but the flash lines up very well with the original OOo document.  All of this should
     684             :         //  probably be converted to polygons as part of the meta file, though, as we don't handle any
     685             :         //  fancy lines (like dashes).
     686           0 :         if( ( aOldFont.GetStrikeout() != STRIKEOUT_NONE ) || ( aOldFont.GetUnderline() != UNDERLINE_NONE ) )
     687             :         {
     688           0 :             Polygon     aPoly( 4 );
     689           0 :             const long  nLineHeight = std::max( (long) FRound( aMetric.GetLineHeight() * 0.05 ), (long) 1 );
     690             : 
     691           0 :             if( aOldFont.GetStrikeout() != STRIKEOUT_NONE )
     692             :             {
     693           0 :                 aPoly[ 0 ].X() = aBaseLinePos.X();
     694           0 :                 aPoly[ 0 ].Y() = aBaseLinePos.Y() - FRound( aMetric.GetAscent() * 0.26 ) - nLineHeight;
     695           0 :                 aPoly[ 1 ].X() = aPoly[ 0 ].X() + aNormSize.Width() - 1;
     696           0 :                 aPoly[ 1 ].Y() = aPoly[ 0 ].Y();
     697           0 :                 aPoly[ 2 ].X() = aPoly[ 1 ].X();
     698           0 :                 aPoly[ 2 ].Y() = aPoly[ 1 ].Y() + nLineHeight - 1;
     699           0 :                 aPoly[ 3 ].X() = aPoly[ 0 ].X();
     700           0 :                 aPoly[ 3 ].Y() = aPoly[ 2 ].Y();
     701             : 
     702           0 :                 Impl_writePolygon( aPoly, sal_True, aTextColor, aTextColor );
     703             :             }
     704             : 
     705             :             // AS: The factor of 1.5 on the nLineHeight is a magic number.  I'm not sure why it works,
     706             :             //  but it looks good to me.
     707           0 :             if( aOldFont.GetUnderline() != UNDERLINE_NONE )
     708             :             {
     709           0 :                 aPoly[ 0 ].X() = aBaseLinePos.X();
     710           0 :                 aPoly[ 0 ].Y() = static_cast<long>(aBaseLinePos.Y() + 1.5*nLineHeight);
     711           0 :                 aPoly[ 1 ].X() = aPoly[ 0 ].X() + aNormSize.Width() - 1;
     712           0 :                 aPoly[ 1 ].Y() = aPoly[ 0 ].Y();
     713           0 :                 aPoly[ 2 ].X() = aPoly[ 1 ].X();
     714           0 :                 aPoly[ 2 ].Y() = aPoly[ 1 ].Y() + nLineHeight - 1;
     715           0 :                 aPoly[ 3 ].X() = aPoly[ 0 ].X();
     716           0 :                 aPoly[ 3 ].Y() = aPoly[ 2 ].Y();
     717             : 
     718           0 :                 Impl_writePolygon( aPoly, sal_True, aTextColor, aTextColor );
     719           0 :             }
     720             :         }
     721             : 
     722           0 :         mpVDev->SetFont( aOldFont );
     723           0 :     }
     724             : }
     725             : 
     726             : 
     727             : // AS: Because JPEGs require the alpha channel provided separately (JPEG does not
     728             : //  natively support alpha channel, but SWF lets you provide it separately), we
     729             : //  extract the alpha channel into a separate array here.
     730           0 : void getBitmapData( const BitmapEx& aBmpEx, sal_uInt8*& tgadata, sal_uInt8*& tgaAlphadata, sal_uInt32& nWidth, sal_uInt32& nHeight )
     731             : {
     732           0 :     if( !aBmpEx.IsEmpty() )
     733             :     {
     734           0 :         Bitmap              aBmp( aBmpEx.GetBitmap() );
     735           0 :         BitmapReadAccess*   pRAcc = aBmp.AcquireReadAccess();
     736             : 
     737           0 :         if( pRAcc )
     738             :         {
     739           0 :             AlphaMask   aAlpha;
     740           0 :             nWidth = pRAcc->Width();
     741           0 :             nHeight = pRAcc->Height();
     742           0 :             tgadata = new sal_uInt8[nWidth*nHeight*4];
     743           0 :             tgaAlphadata = new sal_uInt8[nWidth*nHeight];
     744           0 :             sal_uInt8* p = tgadata, *pAlpha = tgaAlphadata;
     745             : 
     746             : 
     747           0 :             if( aBmpEx.IsAlpha() )
     748           0 :                 aAlpha = aBmpEx.GetAlpha();
     749           0 :             else if( aBmpEx.IsTransparent() )
     750           0 :                 aAlpha = aBmpEx.GetMask();
     751             :             else
     752             :             {
     753           0 :                 sal_uInt8 cAlphaVal = 0;
     754           0 :                 aAlpha = AlphaMask( aBmp.GetSizePixel(), &cAlphaVal );
     755             :             }
     756             : 
     757           0 :             BitmapReadAccess* pAAcc = aAlpha.AcquireReadAccess();
     758             : 
     759           0 :             if( pAAcc )
     760             :             {
     761           0 :                 for( sal_uInt32 nY = 0; nY < nHeight; nY++ )
     762             :                 {
     763           0 :                     for( sal_uInt32 nX = 0; nX < nWidth; nX++ )
     764             :                     {
     765           0 :                         const sal_uInt8     nAlpha = pAAcc->GetPixel( nY, nX ).GetIndex();
     766           0 :                         const BitmapColor   aPixelColor( pRAcc->GetColor( nY, nX ) );
     767             : 
     768           0 :                         if( nAlpha == 0xff )
     769             :                         {
     770           0 :                             *p++ = 0;
     771           0 :                             *p++ = 0;
     772           0 :                             *p++ = 0;
     773           0 :                             *p++ = 0;
     774             :                         }
     775             :                         else
     776             :                         {
     777           0 :                             *p++ = 0xff-nAlpha;
     778           0 :                             *p++ = aPixelColor.GetRed();
     779           0 :                             *p++ = aPixelColor.GetGreen();
     780           0 :                             *p++ = aPixelColor.GetBlue();
     781             :                         }
     782           0 :                         *pAlpha++ = 0xff - nAlpha;
     783           0 :                     }
     784             :                 }
     785             : 
     786           0 :                 aAlpha.ReleaseAccess( pAAcc );
     787             :             }
     788             : 
     789           0 :             aBmp.ReleaseAccess( pRAcc );
     790           0 :         }
     791             :     }
     792           0 : }
     793             : 
     794             : 
     795           0 : sal_uInt16 Writer::defineBitmap( const BitmapEx &bmpSource, sal_Int32 nJPEGQualityLevel )
     796             : {
     797           0 :     sal_uLong bmpChecksum = bmpSource.GetChecksum();
     798             : 
     799           0 :     ChecksumCache::iterator it = mBitmapCache.find(bmpChecksum);
     800             : 
     801             :     // AS: We already exported this bitmap, so just return its ID.
     802           0 :     if (mBitmapCache.end() != it)
     803           0 :         return it->second;
     804             : 
     805           0 :     sal_uInt16 nBitmapId = createID();
     806           0 :     mBitmapCache[bmpChecksum] = nBitmapId;
     807             : 
     808             :     // AS: OK, we have a good image, so now we decide whether or not to JPEG it or
     809             :     //  or Lossless compress it.
     810             : 
     811             :     //Figure out lossless size
     812             :     sal_uInt8 *pImageData, *pAlphaData;
     813             :     sal_uInt32 width, height;
     814             : 
     815           0 :     getBitmapData( bmpSource, pImageData, pAlphaData, width, height );
     816           0 :     sal_uInt32 raw_size = width * height * 4;
     817           0 :     uLongf compressed_size = raw_size + (sal_uInt32)(raw_size/100) + 12;
     818           0 :     boost::scoped_array<sal_uInt8> pCompressed(new sal_uInt8[ compressed_size ]);
     819             : 
     820             : #ifdef DBG_UTIL
     821             :     if(compress2(pCompressed.get(), &compressed_size, pImageData, raw_size, Z_BEST_COMPRESSION) != Z_OK)
     822             :     {
     823             :         DBG_ASSERT( false, "compress2 failed!" ); ((void)0);
     824             :     }
     825             : #else
     826           0 :     compress2(pCompressed.get(), &compressed_size, pImageData, raw_size, Z_BEST_COMPRESSION);
     827             : #endif
     828             : 
     829             :     // AS: SWF files let you provide an Alpha mask for JPEG images, but we have
     830             :     //  to ZLIB compress the alpha channel separately.
     831           0 :     uLong alpha_compressed_size = 0;
     832           0 :     boost::scoped_array<sal_uInt8> pAlphaCompressed;
     833           0 :     if (bmpSource.IsAlpha() || bmpSource.IsTransparent())
     834             :     {
     835           0 :         alpha_compressed_size = uLongf(width * height + (sal_uInt32)(raw_size/100) + 12);
     836           0 :         pAlphaCompressed.reset(new sal_uInt8[ compressed_size ]);
     837             : 
     838             : #ifdef DBG_UTIL
     839             :         if(compress2(pAlphaCompressed.get(), &alpha_compressed_size, pAlphaData, width * height, Z_BEST_COMPRESSION) != Z_OK)
     840             :         {
     841             :             DBG_ASSERT( false, "compress2 failed!" ); ((void)0);
     842             :         }
     843             : #else
     844           0 :         compress2(pAlphaCompressed.get(), &alpha_compressed_size, pAlphaData, width * height, Z_BEST_COMPRESSION);
     845             : #endif
     846             :     }
     847             : 
     848             :     //Figure out JPEG size
     849           0 :     const sal_uInt8* pJpgData = NULL;;
     850           0 :     sal_uInt32 nJpgDataLength = 0xffffffff;
     851             : 
     852           0 :     Graphic aGraphic( bmpSource );
     853           0 :     SvMemoryStream aDstStm( 65535, 65535 );
     854             : 
     855           0 :     GraphicFilter aFilter;
     856             : 
     857           0 :     Sequence< PropertyValue > aFilterData(sal_Int32(nJPEGQualityLevel != -1));
     858           0 :     if( nJPEGQualityLevel != -1 )
     859             :     {
     860           0 :         aFilterData[0].Name = "Quality";
     861           0 :         aFilterData[0].Value <<= nJPEGQualityLevel;
     862             :     }
     863             : 
     864           0 :     if( aFilter.ExportGraphic( aGraphic, OUString(), aDstStm,
     865           0 :                                 aFilter.GetExportFormatNumberForShortName( OUString(JPG_SHORTNAME) ), &aFilterData ) == ERRCODE_NONE )
     866             :     {
     867           0 :         pJpgData = reinterpret_cast<const sal_uInt8*>(aDstStm.GetData());
     868           0 :         nJpgDataLength = aDstStm.Seek( STREAM_SEEK_TO_END );
     869             :     }
     870             : 
     871             :     // AS: Ok, now go ahead and use whichever is smaller.  If JPEG is smaller, then
     872             :     //  we have to export as TAG_DEFINEBITSJPEG3 in the case that there is alpha
     873             :     //  channel data.
     874           0 :     if ( pJpgData && ( nJpgDataLength + alpha_compressed_size < compressed_size) )
     875           0 :         Impl_writeJPEG(nBitmapId, pJpgData, nJpgDataLength, pAlphaCompressed.get(), alpha_compressed_size );
     876             :     else
     877           0 :         Impl_writeBmp( nBitmapId, width, height, pCompressed.get(), compressed_size );
     878             : 
     879           0 :     delete[] pImageData;
     880           0 :     delete[] pAlphaData;
     881             : 
     882           0 :     return nBitmapId;
     883             : }
     884             : 
     885             : 
     886             : 
     887           0 : void Writer::Impl_writeImage( const BitmapEx& rBmpEx, const Point& rPt, const Size& rSz, const Point& /* rSrcPt */, const Size& /* rSrcSz */, const Rectangle& rClipRect, bool bNeedToMapClipRect )
     888             : {
     889           0 :     if( !!rBmpEx )
     890             :     {
     891           0 :         BitmapEx bmpSource( rBmpEx );
     892             : 
     893           0 :         Rectangle originalPixelRect = Rectangle(Point(), bmpSource.GetSizePixel());
     894             : 
     895           0 :         Point srcPt( map(rPt) );
     896           0 :         Size srcSize( map(rSz) );
     897           0 :         Rectangle destRect( srcPt, srcSize );
     898             : 
     899             :         // AS: Christian, my scaling factors are different than yours, and work better for me.
     900             :         //  However, I can't explain why exactly.  I got some of this by trial and error.
     901           0 :         double XScale = static_cast<double>(originalPixelRect.GetWidth())/destRect.GetWidth();
     902           0 :         double YScale = static_cast<double>(originalPixelRect.GetHeight())/destRect.GetHeight();
     903             : 
     904             :         // AS: If rClipRect has a value set, then we need to crop the bmp appropriately.
     905             :         //  If a map event already occurred in the metafile, then we do not need to map
     906             :         //  the clip rect as it's already been done.
     907           0 :         if (!rClipRect.IsEmpty())
     908             :         {
     909             :             // AS: Christian, I also don't understand why bNeedToMapClipRect is necessary, but it
     910             :             //  works like a charm.  Usually, the map event in the meta file does not cause the
     911             :             //  clipping rectangle to get mapped.  However, sometimes there are multiple layers
     912             :             //  of mapping which eventually do cause the clipping rect to be mapped.
     913           0 :             Size clipSize( bNeedToMapClipRect ? map(rClipRect.GetSize()) : rClipRect.GetSize() );
     914           0 :             Rectangle clipRect = Rectangle(Point(), clipSize);
     915           0 :             destRect.Intersection( clipRect );
     916             : 
     917           0 :             Rectangle cropRect(destRect);
     918             : 
     919             :             // AS: The bmp origion is always 0,0 so we have to adjust before we crop.
     920           0 :             cropRect.Move(-srcPt.X(), -srcPt.Y());
     921             :             // AS: Rectangle has no scale function (?!) so I do it manually...
     922           0 :             Rectangle cropPixelRect(static_cast<long>(cropRect.Left()*XScale),
     923           0 :                                     static_cast<long>(cropRect.Top()*YScale),
     924           0 :                                     static_cast<long>(cropRect.Right()*XScale),
     925           0 :                                     static_cast<long>(cropRect.Bottom()*YScale));
     926             : 
     927           0 :             bmpSource.Crop(cropPixelRect);
     928             :         }
     929             : 
     930           0 :         if( !!bmpSource )
     931             :         {
     932             :             // #105949# fix images that are under 16 pixels width or height by
     933             :             //          expanding them. Some swf players can't display such small
     934             :             //          bitmaps
     935           0 :             const Size& rSizePixel = bmpSource.GetSizePixel();
     936           0 :             if( (rSizePixel.Width() < 16) || (rSizePixel.Height() < 16) )
     937             :             {
     938           0 :                 const sal_uInt32 nDX = rSizePixel.Width() < 16 ? 16 - rSizePixel.Width() : 0;
     939           0 :                 const sal_uInt32 nDY = rSizePixel.Height() < 16 ? 16 - rSizePixel.Height() : 0;
     940           0 :                 bmpSource.Expand( nDX, nDY );
     941             :             }
     942             : 
     943           0 :             sal_Int32 nJPEGQuality = mnJPEGCompressMode;
     944             : 
     945           0 :             Size szDestPixel = mpVDev->LogicToPixel(srcSize, aTWIPSMode);
     946             : 
     947           0 :             double pixXScale = static_cast<double>(szDestPixel.Width()) / originalPixelRect.GetWidth();
     948           0 :             double pixYScale = static_cast<double>(szDestPixel.Height()) / originalPixelRect.GetHeight();
     949             : 
     950             :             // AS: If the image has been scaled down, then scale down the quality
     951             :             //   that we use for JPEG compression.
     952           0 :             if (pixXScale < 1.0 && pixYScale < 1.0)
     953             :             {
     954             : 
     955           0 :                 double qualityScale = (pixXScale + pixYScale)/2;
     956             : 
     957           0 :                 nJPEGQuality = (sal_Int32)( nJPEGQuality * qualityScale );
     958             : 
     959           0 :                 if (nJPEGQuality < 10)
     960           0 :                     nJPEGQuality += 3;
     961             :             }
     962             : 
     963           0 :             sal_uInt16 nBitmapId = defineBitmap(bmpSource, nJPEGQuality);
     964             : 
     965           0 :             Polygon aPoly( destRect );
     966             : 
     967             :             // AS: Since images are being cropped now, no translation is normally necessary.
     968             :             //  However, some things like graphical bullet points are still get translated.
     969           0 :             ::basegfx::B2DHomMatrix m; // #i73264#
     970           0 :             m.scale(1.0/XScale, 1.0/YScale );
     971           0 :             if (destRect.Left() || destRect.Top())
     972           0 :                 m.translate(destRect.Left(), destRect.Top());
     973             : 
     974           0 :             FillStyle aFillStyle( nBitmapId, true, m );
     975             : 
     976           0 :             sal_uInt16 nShapeId = defineShape( aPoly, aFillStyle );
     977             : 
     978           0 :             maShapeIds.push_back( nShapeId );
     979           0 :         }
     980             :     }
     981           0 : }
     982             : 
     983             : 
     984           0 : void Writer::Impl_writeBmp( sal_uInt16 nBitmapId, sal_uInt32 width, sal_uInt32 height, sal_uInt8 *pCompressed, sal_uInt32 compressed_size )
     985             : {
     986           0 :     startTag( TAG_DEFINEBITSLOSSLESS2 );
     987             : 
     988           0 :     mpTag->addUI16( nBitmapId );
     989           0 :     mpTag->addUI8( 5 );
     990           0 :     mpTag->addUI16( _uInt16(width) );
     991           0 :     mpTag->addUI16( _uInt16(height) );
     992             : 
     993           0 :     mpTag->Write( pCompressed, compressed_size );
     994             : 
     995           0 :     endTag();
     996           0 : }
     997             : 
     998             : 
     999             : 
    1000           0 : void Writer::Impl_writeJPEG(sal_uInt16 nBitmapId, const sal_uInt8* pJpgData, sal_uInt32 nJpgDataLength, sal_uInt8 *pAlphaCompressed, sal_uInt32 alpha_compressed_size )
    1001             : {
    1002             :     // AS: Go through the actuall JPEG bits, separating out the
    1003             :     //  header fields from the actual image fields.  Fields are
    1004             :     //  identifed by 0xFFXX where XX is the field type.  Both
    1005             :     //  the header and the image need start and stop (D8 and D9),
    1006             :     //  so that's why you see those written to both.  I don't
    1007             :     //  really know what the rest of these are, I got it to work
    1008             :     //  kind of by trial and error and by comparing with known
    1009             :     //  good SWF files.
    1010           0 :     sal_uInt8 cType = 0x01;
    1011           0 :     const sal_uInt8* pJpgSearch = pJpgData;
    1012             : 
    1013           0 :     int nLength = 0;
    1014             : 
    1015           0 :     SvMemoryStream EncodingTableStream;
    1016           0 :     SvMemoryStream ImageBitsStream;
    1017           0 :     for (;pJpgSearch < pJpgData + nJpgDataLength; pJpgSearch += nLength)
    1018             :     {
    1019             : 
    1020             : #ifdef DBG_UTIL
    1021             :         if (0xFF != *pJpgSearch)
    1022             :         {
    1023             :             OSL_FAIL( "Expected JPEG marker." ); ((void)0);
    1024             :         }
    1025             : #endif
    1026             : 
    1027           0 :         cType = *(pJpgSearch + 1);
    1028             : 
    1029           0 :         if (0xD8 == cType || 0xD9 == cType)
    1030             :         {
    1031           0 :             nLength = 2;
    1032             :         }
    1033           0 :         else if (0xDA == cType)
    1034             :         {
    1035             :             //AS: This is the actual image data, and runs to the
    1036             :             // end of the file (as best I know), minus 2 bytes
    1037             :             // for the closing 0xFFD9.
    1038           0 :             nLength = nJpgDataLength - (pJpgSearch - pJpgData) - 2;
    1039             :         }
    1040             :         else
    1041             :         {
    1042             :             // AS: Lengths are big endian.
    1043             : 
    1044             :             // Beware. pJpgSearch is not necessarily word-aligned,
    1045             :             // so we access it byte-wise.
    1046             : 
    1047             :             // AS: Add 2 to the length to include the 0xFFXX itself.
    1048           0 :             nLength = 2 + (pJpgSearch[2]<<8) + pJpgSearch[3];
    1049             :         }
    1050             : 
    1051             :         // AS: I'm refering to libjpeg for a list of what these
    1052             :         //  markers are.  See jdmarker.c for a list.
    1053             :         // AS: I'm ignoring application specific markers 0xE1...0xEF
    1054             :         //  and comments 0xFE.  I don't know what
    1055             :         //  0xF0 or 0xFD are for, and they don't come up.
    1056             :         //  Additionally, 0xDE and 0xDF aren't clear to me.
    1057           0 :         switch(cType)
    1058             :         {
    1059             :         case 0xD8:
    1060             :         case 0xD9:
    1061           0 :             EncodingTableStream.Write( pJpgSearch, nLength );
    1062           0 :             ImageBitsStream.Write( pJpgSearch, nLength );
    1063           0 :             break;
    1064             : 
    1065             :         case 0x01:
    1066             :         case 0xDB:
    1067             :         case 0xDC:
    1068             :         case 0xDD:
    1069             :         case 0xC4:
    1070           0 :             EncodingTableStream.Write( pJpgSearch, nLength );
    1071           0 :             break;
    1072             : 
    1073             :         case 0xC0:
    1074             :         case 0xC1:
    1075             :         case 0xC2:
    1076             :         case 0xC3:
    1077             :         case 0xC5:
    1078             :         case 0xC6:
    1079             :         case 0xC7:
    1080             : //      case 0xC8: Apparently reserved for JPEG extensions?
    1081             :         case 0xC9:
    1082             :         case 0xCA:
    1083             :         case 0xCB:
    1084             :         case 0xCD:
    1085             :         case 0xCE:
    1086             :         case 0xCF:
    1087             :         case 0xDA:
    1088             :         case 0xE0:
    1089           0 :             ImageBitsStream.Write( pJpgSearch, nLength );
    1090           0 :             break;
    1091             : 
    1092             :         default:
    1093             :             OSL_FAIL( "JPEG marker I didn't handle!" );
    1094             : 
    1095             :         }
    1096             :     }
    1097             : 
    1098           0 :     EncodingTableStream.Seek( STREAM_SEEK_TO_END );
    1099           0 :     sal_uInt32 nEncodingTableSize = EncodingTableStream.Tell();
    1100           0 :     EncodingTableStream.Seek( STREAM_SEEK_TO_BEGIN );
    1101             : 
    1102           0 :     ImageBitsStream.Seek( STREAM_SEEK_TO_END );
    1103           0 :     sal_uInt32 nImageBitsSize = ImageBitsStream.Tell();
    1104           0 :     ImageBitsStream.Seek( STREAM_SEEK_TO_BEGIN );
    1105             : 
    1106             :     // AS: If we need alpha support, use TAG_DEFINEBITSJPEG3.
    1107           0 :     if (alpha_compressed_size > 0)
    1108             :     {
    1109           0 :         startTag( TAG_DEFINEBITSJPEG3 );
    1110             : 
    1111           0 :         mpTag->addUI16( nBitmapId );
    1112             : 
    1113           0 :         mpTag->addUI32( nEncodingTableSize + nImageBitsSize );
    1114             : 
    1115           0 :         mpTag->Write(EncodingTableStream.GetData(), nEncodingTableSize);
    1116           0 :         mpTag->Write(ImageBitsStream.GetData(), nImageBitsSize);
    1117             : 
    1118           0 :         mpTag->Write( pAlphaCompressed, alpha_compressed_size );
    1119             : 
    1120           0 :         endTag();
    1121             :     }
    1122             :     else
    1123             :     {
    1124           0 :         startTag( TAG_DEFINEBITSJPEG2 );
    1125             : 
    1126           0 :         mpTag->addUI16( nBitmapId );
    1127             : 
    1128           0 :         mpTag->Write(EncodingTableStream.GetData(), nEncodingTableSize);
    1129           0 :         mpTag->Write(ImageBitsStream.GetData(), nImageBitsSize);
    1130             : 
    1131           0 :         endTag();
    1132           0 :     }
    1133           0 : }
    1134             : 
    1135             : 
    1136             : 
    1137           0 : void Writer::Impl_writeLine( const Point& rPt1, const Point& rPt2, const Color* pLineColor )
    1138             : {
    1139           0 :     Color aOldColor( mpVDev->GetLineColor() );
    1140           0 :     if( pLineColor )
    1141           0 :         mpVDev->SetLineColor( *pLineColor );
    1142             : 
    1143           0 :     const Point aPtAry[2] = { rPt1, rPt2 };
    1144           0 :     Polygon aPoly( 2, aPtAry );
    1145           0 :     Impl_writePolyPolygon( aPoly, false );
    1146             : 
    1147           0 :     mpVDev->SetLineColor( aOldColor );
    1148           0 : }
    1149             : 
    1150             : 
    1151             : 
    1152           0 : void Writer::Impl_writeRect( const Rectangle& rRect, long nRadX, long nRadY )
    1153             : {
    1154           0 :     if( (rRect.Top() == rRect.Bottom()) || (rRect.Left() == rRect.Right()) )
    1155             :     {
    1156           0 :         Color aColor( mpVDev->GetFillColor() );
    1157           0 :         Impl_writeLine( rRect.TopLeft(), rRect.BottomRight(), &aColor );
    1158             :     }
    1159             :     else
    1160             :     {
    1161           0 :         Polygon aPoly( rRect, nRadX, nRadY );
    1162           0 :         Impl_writePolyPolygon( aPoly, true );
    1163             :     }
    1164           0 : }
    1165             : 
    1166             : 
    1167             : 
    1168           0 : void Writer::Impl_writeEllipse( const Point& rCenter, long nRadX, long nRadY )
    1169             : {
    1170           0 :     Polygon aPoly( rCenter, nRadX, nRadY );
    1171           0 :     Impl_writePolyPolygon( aPoly, false );
    1172           0 : }
    1173             : 
    1174             : 
    1175             : /** writes the stroke defined by SvtGraphicStroke and returns true or it returns
    1176             :     false if it can't handle this stroke.
    1177             : */
    1178           0 : bool Writer::Impl_writeStroke( SvtGraphicStroke& rStroke )
    1179             : {
    1180           0 :     Polygon aPolygon;
    1181           0 :     rStroke.getPath( aPolygon );
    1182           0 :     PolyPolygon aPolyPolygon( aPolygon );
    1183             : 
    1184           0 :     map( aPolyPolygon );
    1185             : 
    1186             :     // as log as not LINESTYLE2 and DefineShape4 is used (which
    1187             :     // added support for LineJoin), only round LineJoins are
    1188             :     // supported. Fallback to META_POLYLINE_ACTION and META_LINE_ACTION
    1189           0 :     if(SvtGraphicStroke::joinRound != rStroke.getJoinType())
    1190           0 :         return false;
    1191             : 
    1192           0 :     PolyPolygon aStartArrow;
    1193           0 :     rStroke.getStartArrow( aStartArrow );
    1194           0 :     if( 0 != aStartArrow.Count() )
    1195           0 :         return false;       // todo: Implement line ends
    1196             : 
    1197           0 :     PolyPolygon aEndArrow;
    1198           0 :     rStroke.getEndArrow( aEndArrow );
    1199           0 :     if( 0 != aEndArrow.Count() )
    1200           0 :         return false;       // todo: Implement line ends
    1201             : 
    1202           0 :     SvtGraphicStroke::DashArray aDashArray;
    1203           0 :     rStroke.getDashArray( aDashArray );
    1204           0 :     if( 0 != aDashArray.size() )
    1205           0 :         return false;       // todo: implement dashes
    1206             : 
    1207           0 :     Color aColor( mpVDev->GetLineColor() );
    1208             : 
    1209           0 :     if( 0.0 != rStroke.getTransparency() )
    1210           0 :         aColor.SetTransparency( sal::static_int_cast<sal_uInt8>( MinMax( (long int)( rStroke.getTransparency() * 0xff ), 0, 0xff ) ) );
    1211             : 
    1212           0 :     sal_uInt16 nShapeId = defineShape( aPolyPolygon, sal::static_int_cast<sal_uInt16>( mapRelative( (sal_Int32)( rStroke.getStrokeWidth() ) ) ), aColor );
    1213           0 :     maShapeIds.push_back( nShapeId );
    1214           0 :     return true;
    1215             : }
    1216             : 
    1217             : 
    1218             : 
    1219             : /** writes the filling defined by SvtGraphicFill and returns true or it returns
    1220             :     false if it can't handle this filling.
    1221             : */
    1222           0 : bool Writer::Impl_writeFilling( SvtGraphicFill& rFilling )
    1223             : {
    1224           0 :     PolyPolygon aPolyPolygon;
    1225           0 :     rFilling.getPath( aPolyPolygon );
    1226             : 
    1227           0 :     Rectangle aOldRect( aPolyPolygon.GetBoundRect() );
    1228             : 
    1229           0 :     map( aPolyPolygon );
    1230             : 
    1231           0 :     Rectangle aNewRect( aPolyPolygon.GetBoundRect() );
    1232             : 
    1233           0 :     switch( rFilling.getFillType() )
    1234             :     {
    1235             :     case SvtGraphicFill::fillSolid:
    1236             :         {
    1237           0 :             Color aColor( rFilling.getFillColor() );
    1238             : 
    1239           0 :             if( 0.0 != rFilling.getTransparency() )
    1240           0 :                 aColor.SetTransparency( sal::static_int_cast<sal_uInt8>( MinMax( (long int)( rFilling.getTransparency() * 0xff ) , 0, 0xff ) ) );
    1241             : 
    1242           0 :             FillStyle aFillStyle( aColor );
    1243             : 
    1244           0 :             sal_uInt16 nShapeId = defineShape( aPolyPolygon, aFillStyle );
    1245           0 :             maShapeIds.push_back( nShapeId );
    1246             :         }
    1247           0 :         break;
    1248             :     case SvtGraphicFill::fillGradient:
    1249           0 :         return false;
    1250             :     case SvtGraphicFill::fillHatch:
    1251           0 :         return false;
    1252             :     case SvtGraphicFill::fillTexture:
    1253             :         {
    1254           0 :             Graphic aGraphic;
    1255           0 :             rFilling.getGraphic( aGraphic );
    1256             : 
    1257             :             // CL->AS: Should we also scale down the quality here depending on image scale?
    1258           0 :             sal_uInt16 nBitmapId = defineBitmap( aGraphic.GetBitmapEx(), mnJPEGCompressMode );
    1259             : 
    1260           0 :             ::basegfx::B2DHomMatrix aMatrix; // #i73264#
    1261             : 
    1262           0 :             SvtGraphicFill::Transform aTransform;
    1263             : 
    1264           0 :             rFilling.getTransform( aTransform );
    1265             : 
    1266             :             sal_uInt16 a,b;
    1267           0 :             for( a = 0; a < 2; a++ )
    1268             :             {
    1269           0 :                 for( b = 0; b < 3; b++ )
    1270             :                 {
    1271           0 :                     aMatrix.set(a, b, aTransform.matrix[a*3+b]);
    1272             :                 }
    1273             :             }
    1274           0 :             aMatrix.set(2, 0, 0.0);
    1275           0 :             aMatrix.set(2, 1, 0.0);
    1276           0 :             aMatrix.set(2, 2, 1.0);
    1277             : 
    1278             :             // scale bitmap
    1279           0 :             double XScale = (double)aNewRect.GetWidth()/aOldRect.GetWidth();
    1280           0 :             double YScale = (double)aNewRect.GetHeight()/aOldRect.GetHeight();
    1281             : 
    1282           0 :             aMatrix.scale( XScale, YScale );
    1283             : 
    1284           0 :             FillStyle aFillStyle( nBitmapId, !rFilling.IsTiling(), aMatrix );
    1285             : 
    1286           0 :             sal_uInt16 nShapeId = defineShape( aPolyPolygon, aFillStyle );
    1287           0 :             maShapeIds.push_back( nShapeId );
    1288             :         }
    1289           0 :         break;
    1290             :     }
    1291           0 :     return true;
    1292             : }
    1293             : 
    1294             : 
    1295             : 
    1296             : /* CL: The idea was to export page fields as text fields that get theire
    1297             :    string from a variable set with actionscript by each page. This didn't
    1298             :    work out since the formatting is always wrong when text follows the
    1299             :    page number field since pages greater one may require more space than
    1300             :    page 1
    1301             : */
    1302             : #if 0
    1303             : bool Writer::Impl_writePageField( Rectangle& rTextBounds )
    1304             : {
    1305             :     startTag( TAG_DEFINEEDITTEXT );
    1306             : 
    1307             :     sal_uInt16 nTextId = createID();
    1308             : 
    1309             :     mpTag->addUI16( nTextId );
    1310             :     mpTag->addRect( rTextBounds );
    1311             : 
    1312             :     BitStream aBits;
    1313             :     aBits.writeUB( 1, 1 );                  // HasText
    1314             :     aBits.writeUB( 0, 1 );                  // WordWrap
    1315             :     aBits.writeUB( 0, 1 );                  // MultiLine
    1316             :     aBits.writeUB( 0, 1 );                  // Password
    1317             :     aBits.writeUB( 1, 1 );                  // HasTextColor
    1318             :     aBits.writeUB( 0, 1 );                  // HasMaxLength
    1319             :     aBits.writeUB( 0, 1 );                  // HasFont
    1320             :     aBits.writeUB( 0, 1 );                  // Reserved
    1321             :     aBits.writeUB( 0, 1 );                  // AutoSize
    1322             :     aBits.writeUB( 0, 1 );                  // HasLayout
    1323             :     aBits.writeUB( 1, 1 );                  // NoSelect
    1324             :     aBits.writeUB( 1, 1 );                  // Border
    1325             :     aBits.writeUB( 0, 1 );                  // Reserved
    1326             :     aBits.writeUB( 0, 1 );                  // HTML
    1327             :     aBits.writeUB( 0, 1 );                  // UseOutlines
    1328             :     mpTag->addBits( aBits );
    1329             : 
    1330             :     Color aColor( COL_BLACK );
    1331             :     mpTag->addRGB( aColor );
    1332             :     mpTag->addString( "PageNumber" );
    1333             :     mpTag->addString( "XXX" );
    1334             : 
    1335             :     endTag();
    1336             : 
    1337             :     maShapeIds.push_back( nTextId );
    1338             : 
    1339             :     return true;
    1340             : }
    1341             : #endif
    1342             : 
    1343             : 
    1344             : 
    1345           0 : void Writer::Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon)
    1346             : {
    1347           0 :     if(rLinePolygon.count())
    1348             :     {
    1349           0 :         basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon);
    1350           0 :         basegfx::B2DPolyPolygon aFillPolyPolygon;
    1351             : 
    1352           0 :         rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon);
    1353             : 
    1354           0 :         if(aLinePolyPolygon.count())
    1355             :         {
    1356           0 :             for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++)
    1357             :             {
    1358           0 :                 const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a));
    1359           0 :                 Impl_writePolygon(Polygon(aCandidate), sal_False );
    1360           0 :             }
    1361             :         }
    1362             : 
    1363           0 :         if(aFillPolyPolygon.count())
    1364             :         {
    1365           0 :             const Color aOldLineColor(mpVDev->GetLineColor());
    1366           0 :             const Color aOldFillColor(mpVDev->GetFillColor());
    1367             : 
    1368           0 :             mpVDev->SetLineColor();
    1369           0 :             mpVDev->SetFillColor(aOldLineColor);
    1370             : 
    1371           0 :             for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++)
    1372             :             {
    1373           0 :                 const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a));
    1374           0 :                 Impl_writePolyPolygon(PolyPolygon(Polygon(aPolygon)), sal_True );
    1375           0 :             }
    1376             : 
    1377           0 :             mpVDev->SetLineColor(aOldLineColor);
    1378           0 :             mpVDev->SetFillColor(aOldFillColor);
    1379           0 :         }
    1380             :     }
    1381           0 : }
    1382             : 
    1383             : 
    1384             : 
    1385           0 : void Writer::Impl_writeActions( const GDIMetaFile& rMtf )
    1386             : {
    1387           0 :     Rectangle clipRect;
    1388           0 :     int bMap = 0;
    1389           0 :     for( size_t i = 0, nCount = rMtf.GetActionSize(); i < nCount; i++ )
    1390             :     {
    1391           0 :         const MetaAction*   pAction = rMtf.GetAction( i );
    1392           0 :         const sal_uInt16        nType = pAction->GetType();
    1393             : 
    1394           0 :         switch( nType )
    1395             :         {
    1396             :             case( META_PIXEL_ACTION ):
    1397             :             {
    1398           0 :                 const MetaPixelAction* pA = (const MetaPixelAction*) pAction;
    1399             : 
    1400           0 :                 Impl_writeLine( pA->GetPoint(), pA->GetPoint(), &pA->GetColor() );
    1401             :             }
    1402           0 :             break;
    1403             : 
    1404             :             case( META_POINT_ACTION ):
    1405             :             {
    1406           0 :                 const MetaPointAction* pA = (const MetaPointAction*) pAction;
    1407             : 
    1408           0 :                 Impl_writeLine( pA->GetPoint(), pA->GetPoint() );
    1409             :             }
    1410           0 :             break;
    1411             : 
    1412             :             case( META_LINE_ACTION ):
    1413             :             {
    1414           0 :                 const MetaLineAction* pA = (const MetaLineAction*) pAction;
    1415             : 
    1416           0 :                 if(pA->GetLineInfo().IsDefault())
    1417             :                 {
    1418           0 :                     Impl_writeLine( pA->GetStartPoint(), pA->GetEndPoint() );
    1419             :                 }
    1420             :                 else
    1421             :                 {
    1422             :                     // LineInfo used; handle Dash/Dot and fat lines
    1423           0 :                     basegfx::B2DPolygon aPolygon;
    1424           0 :                     aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y()));
    1425           0 :                     aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y()));
    1426           0 :                     Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon);
    1427             :                 }
    1428             :             }
    1429           0 :             break;
    1430             : 
    1431             :             case( META_RECT_ACTION ):
    1432             :             {
    1433           0 :                 Impl_writeRect( ( (const MetaRectAction*) pAction )->GetRect(), 0, 0 );
    1434             :             }
    1435           0 :             break;
    1436             : 
    1437             :             case( META_ROUNDRECT_ACTION ):
    1438             :             {
    1439           0 :                 const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pAction;
    1440             : 
    1441           0 :                 Impl_writeRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
    1442             :             }
    1443           0 :             break;
    1444             : 
    1445             :             case( META_ELLIPSE_ACTION ):
    1446             :             {
    1447           0 :                 const MetaEllipseAction*    pA = (const MetaEllipseAction*) pAction;
    1448           0 :                 const Rectangle&            rRect = pA->GetRect();
    1449             : 
    1450           0 :                 Impl_writeEllipse( rRect.Center(), rRect.GetWidth() >> 1, rRect.GetHeight() >> 1 );
    1451             :             }
    1452           0 :             break;
    1453             : 
    1454             :             case( META_ARC_ACTION ):
    1455             :             case( META_PIE_ACTION ):
    1456             :             case( META_CHORD_ACTION ):
    1457             :             case( META_POLYGON_ACTION ):
    1458             :             {
    1459           0 :                 Polygon aPoly;
    1460             : 
    1461           0 :                 switch( nType )
    1462             :                 {
    1463             :                     case( META_ARC_ACTION ):
    1464             :                     {
    1465           0 :                         const MetaArcAction* pA = (const MetaArcAction*) pAction;
    1466           0 :                         aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC );
    1467             :                     }
    1468           0 :                     break;
    1469             : 
    1470             :                     case( META_PIE_ACTION ):
    1471             :                     {
    1472           0 :                         const MetaPieAction* pA = (const MetaPieAction*) pAction;
    1473           0 :                         aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE );
    1474             :                     }
    1475           0 :                     break;
    1476             : 
    1477             :                     case( META_CHORD_ACTION ):
    1478             :                     {
    1479           0 :                         const MetaChordAction* pA = (const MetaChordAction*) pAction;
    1480           0 :                         aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD );
    1481             :                     }
    1482           0 :                     break;
    1483             : 
    1484             :                     case( META_POLYGON_ACTION ):
    1485           0 :                         aPoly = ( (const MetaPolygonAction*) pAction )->GetPolygon();
    1486           0 :                     break;
    1487             :                 }
    1488             : 
    1489           0 :                 if( aPoly.GetSize() )
    1490             :                 {
    1491           0 :                     Impl_writePolygon( aPoly, sal_True );
    1492           0 :                 }
    1493             :             }
    1494           0 :             break;
    1495             : 
    1496             :             case( META_POLYLINE_ACTION ):
    1497             :             {
    1498           0 :                 const MetaPolyLineAction*   pA = (const MetaPolyLineAction*) pAction;
    1499           0 :                 const Polygon&              rPoly = pA->GetPolygon();
    1500             : 
    1501           0 :                 if( rPoly.GetSize() )
    1502             :                 {
    1503           0 :                     if(pA->GetLineInfo().IsDefault())
    1504             :                     {
    1505           0 :                         Impl_writePolygon( rPoly, sal_False );
    1506             :                     }
    1507             :                     else
    1508             :                     {
    1509             :                         // LineInfo used; handle Dash/Dot and fat lines
    1510           0 :                         Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon());
    1511             :                     }
    1512             :                 }
    1513             :             }
    1514           0 :             break;
    1515             : 
    1516             :             case( META_POLYPOLYGON_ACTION ):
    1517             :             {
    1518           0 :                 const MetaPolyPolygonAction*    pA = (const MetaPolyPolygonAction*) pAction;
    1519           0 :                 const PolyPolygon&              rPolyPoly = pA->GetPolyPolygon();
    1520             : 
    1521           0 :                 if( rPolyPoly.Count() )
    1522           0 :                     Impl_writePolyPolygon( rPolyPoly, sal_True );
    1523             :             }
    1524           0 :             break;
    1525             : 
    1526             :             case( META_GRADIENT_ACTION ):
    1527             :             {
    1528           0 :                 const MetaGradientAction*   pA = (const MetaGradientAction*) pAction;
    1529             : 
    1530           0 :                 Polygon aPoly( pA->GetRect() );
    1531           0 :                 Impl_writeGradientEx( aPoly, pA->GetGradient() );
    1532             :             }
    1533           0 :             break;
    1534             : 
    1535             :             case( META_GRADIENTEX_ACTION ):
    1536             :             {
    1537           0 :                 const MetaGradientExAction* pA = (const MetaGradientExAction*) pAction;
    1538           0 :                 Impl_writeGradientEx( pA->GetPolyPolygon(), pA->GetGradient() );
    1539             :             }
    1540           0 :             break;
    1541             : 
    1542             :             case META_HATCH_ACTION:
    1543             :             {
    1544           0 :                 const MetaHatchAction*  pA = (const MetaHatchAction*) pAction;
    1545           0 :                 GDIMetaFile             aTmpMtf;
    1546             : 
    1547           0 :                 mpVDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
    1548           0 :                 Impl_writeActions( aTmpMtf );
    1549             :             }
    1550           0 :             break;
    1551             : 
    1552             :             case( META_TRANSPARENT_ACTION ):
    1553             :             {
    1554           0 :                 const MetaTransparentAction*    pA = (const MetaTransparentAction*) pAction;
    1555           0 :                 const PolyPolygon&              rPolyPoly = pA->GetPolyPolygon();
    1556             : 
    1557           0 :                 if( rPolyPoly.Count() )
    1558             :                 {
    1559             :                     // convert transparence from percent into 0x00 - 0xff
    1560           0 :                     sal_uInt8 nTransparence = (sal_uInt8) MinMax( FRound( pA->GetTransparence() * 2.55 ), 0, 255 );
    1561           0 :                     Impl_writePolyPolygon( rPolyPoly, sal_True, nTransparence );
    1562             :                 }
    1563             :             }
    1564           0 :             break;
    1565             : 
    1566             :             case( META_FLOATTRANSPARENT_ACTION ):
    1567             :             {
    1568           0 :                 const MetaFloatTransparentAction*   pA = (const MetaFloatTransparentAction*) pAction;
    1569           0 :                 GDIMetaFile                         aTmpMtf( pA->GetGDIMetaFile() );
    1570           0 :                 Point                               aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
    1571           0 :                 const Size                          aSrcSize( aTmpMtf.GetPrefSize() );
    1572           0 :                 const Point                         aDestPt( pA->GetPoint() );
    1573           0 :                 const Size                          aDestSize( pA->GetSize() );
    1574           0 :                 const double                        fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
    1575           0 :                 const double                        fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
    1576             :                 long                                nMoveX, nMoveY;
    1577             : 
    1578           0 :                 if( fScaleX != 1.0 || fScaleY != 1.0 )
    1579             :                 {
    1580           0 :                     aTmpMtf.Scale( fScaleX, fScaleY );
    1581           0 :                     aSrcPt.X() = FRound( aSrcPt.X() * fScaleX );
    1582           0 :                     aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
    1583             :                 }
    1584             : 
    1585           0 :                 nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y();
    1586             : 
    1587           0 :                 if( nMoveX || nMoveY )
    1588           0 :                     aTmpMtf.Move( nMoveX, nMoveY );
    1589             : 
    1590           0 :                 const Gradient& rGradient = pA->GetGradient();
    1591           0 :                 sal_uInt32 nLuminance = ((sal_Int32)rGradient.GetStartColor().GetLuminance() + (sal_Int32)rGradient.GetEndColor().GetLuminance() ) >> 1;
    1592             : 
    1593           0 :                 sal_uInt8 nOldGlobalTransparency = mnGlobalTransparency;
    1594           0 :                 mnGlobalTransparency = (sal_uInt8)MinMax( nLuminance, 0, 0xff );
    1595             : 
    1596           0 :                 mpVDev->Push();
    1597           0 :                 Impl_writeActions( aTmpMtf );
    1598           0 :                 mpVDev->Pop();
    1599             : 
    1600           0 :                 mnGlobalTransparency = nOldGlobalTransparency;
    1601             :             }
    1602           0 :             break;
    1603             : 
    1604             :             case( META_EPS_ACTION ):
    1605             :             {
    1606           0 :                 const MetaEPSAction*    pA = (const MetaEPSAction*) pAction;
    1607           0 :                 const GDIMetaFile       aGDIMetaFile( pA->GetSubstitute() );
    1608           0 :                 sal_Bool                bFound = sal_False;
    1609             : 
    1610           0 :                 for( size_t j = 0, nC = aGDIMetaFile.GetActionSize(); ( j < nC ) && !bFound; j++ )
    1611             :                 {
    1612           0 :                     const MetaAction* pSubstAct = aGDIMetaFile.GetAction( j );
    1613             : 
    1614           0 :                     if( pSubstAct->GetType() == META_BMPSCALE_ACTION )
    1615             :                     {
    1616           0 :                         bFound = sal_True;
    1617           0 :                         const MetaBmpScaleAction* pBmpScaleAction = (const MetaBmpScaleAction*) pSubstAct;
    1618           0 :                         Impl_writeImage( pBmpScaleAction->GetBitmap(),
    1619           0 :                                       pA->GetPoint(), pA->GetSize(),
    1620           0 :                                       Point(), pBmpScaleAction->GetBitmap().GetSizePixel(), clipRect, 1 == bMap  );
    1621             :                     }
    1622           0 :                 }
    1623             :             }
    1624           0 :             break;
    1625             : 
    1626             :             case( META_COMMENT_ACTION ):
    1627             :             {
    1628           0 :                 const MetaCommentAction*    pA = (const MetaCommentAction*) pAction;
    1629           0 :                 const sal_uInt8*                pData = pA->GetData();
    1630             : 
    1631           0 :                 if( pA->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN") )
    1632             :                 {
    1633           0 :                     const MetaGradientExAction* pGradAction = NULL;
    1634           0 :                     sal_Bool                    bDone = sal_False;
    1635             : 
    1636           0 :                     while( !bDone && ( ++i < nCount ) )
    1637             :                     {
    1638           0 :                         pAction = rMtf.GetAction( i );
    1639             : 
    1640           0 :                         if( pAction->GetType() == META_GRADIENTEX_ACTION )
    1641           0 :                             pGradAction = (const MetaGradientExAction*) pAction;
    1642           0 :                         else if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
    1643           0 :                                  ( ( (const MetaCommentAction*) pAction )->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_END") ) )
    1644             :                         {
    1645           0 :                             bDone = sal_True;
    1646             :                         }
    1647             :                     }
    1648             : 
    1649           0 :                     if( pGradAction )
    1650           0 :                         Impl_writeGradientEx( pGradAction->GetPolyPolygon(), pGradAction->GetGradient());
    1651             :                 }
    1652           0 :                 else if( pA->GetComment().equalsIgnoreAsciiCase("XPATHFILL_SEQ_BEGIN") &&  pData )
    1653             :                 {
    1654             : 
    1655             :                     // this comment encapsulates all high level information for a filling that caused
    1656             :                     // the meta actions between the "XPATHFILL_SEQ_BEGIN" and "XPATHFILL_SEQ_END" comment.
    1657             : 
    1658           0 :                     SvtGraphicFill  aFilling;
    1659           0 :                     SvMemoryStream  aMemStm( (void*)pData, pA->GetDataSize(), STREAM_READ );
    1660             : 
    1661             :                     // read the fill info
    1662           0 :                     ReadSvtGraphicFill( aMemStm, aFilling );
    1663             : 
    1664             :                     // if impl_writeFilling can handle this high level filling, it returns true and we
    1665             :                     // skip all meta actions until "XPATHFILL_SEQ_END"
    1666           0 :                     if( Impl_writeFilling( aFilling ) )
    1667             :                     {
    1668           0 :                         bool bDone = false;
    1669             : 
    1670           0 :                         while( !bDone && ( ++i < nCount ) )
    1671             :                         {
    1672           0 :                             pAction = rMtf.GetAction( i );
    1673             : 
    1674           0 :                             if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
    1675           0 :                                      ( ( (const MetaCommentAction*) pAction )->GetComment().equalsIgnoreAsciiCase("XPATHFILL_SEQ_END") ) )
    1676             :                             {
    1677           0 :                                 bDone = true;
    1678             :                             }
    1679             :                         }
    1680           0 :                     }
    1681             :                 }
    1682           0 :                 else if( pA->GetComment().equalsIgnoreAsciiCase("XPATHSTROKE_SEQ_BEGIN") && pData )
    1683             :                 {
    1684             : 
    1685             :                     // this comment encapsulates all high level information for a filling that caused
    1686             :                     // the meta actions between the "XPATHFILL_SEQ_BEGIN" and "XPATHFILL_SEQ_END" comment.
    1687             : 
    1688           0 :                     SvtGraphicStroke aStroke;
    1689           0 :                     SvMemoryStream  aMemStm( (void*)pData, pA->GetDataSize(), STREAM_READ );
    1690             : 
    1691             :                     // read the fill info
    1692           0 :                     ReadSvtGraphicStroke( aMemStm, aStroke );
    1693             : 
    1694             :                     // if impl_writeStroke can handle this high level stroke, it returns true and we
    1695             :                     // skip all meta actions until "XPATHSTROKE_SEQ_END"
    1696           0 :                     if( Impl_writeStroke( aStroke ) )
    1697             :                     {
    1698           0 :                         bool bDone = false;
    1699             : 
    1700           0 :                         while( !bDone && ( ++i < nCount ) )
    1701             :                         {
    1702           0 :                             pAction = rMtf.GetAction( i );
    1703             : 
    1704           0 :                             if( ( pAction->GetType() == META_COMMENT_ACTION ) &&
    1705           0 :                                      ( ( (const MetaCommentAction*) pAction )->GetComment().equalsIgnoreAsciiCase("XPATHSTROKE_SEQ_END") ) )
    1706             :                             {
    1707           0 :                                 bDone = true;
    1708             :                             }
    1709             :                         }
    1710           0 :                     }
    1711             :                 }
    1712             :             }
    1713           0 :             break;
    1714             : 
    1715             :             case( META_BMPSCALE_ACTION ):
    1716             :             {
    1717           0 :                 const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction;
    1718             : 
    1719           0 :                 Impl_writeImage( pA->GetBitmap(),
    1720           0 :                           pA->GetPoint(), pA->GetSize(),
    1721           0 :                           Point(), pA->GetBitmap().GetSizePixel(), clipRect, 1 == bMap );
    1722             :             }
    1723           0 :             break;
    1724             : 
    1725             :             case( META_BMP_ACTION ):
    1726             :             {
    1727           0 :                 const MetaBmpAction* pA = (const MetaBmpAction*) pAction;
    1728           0 :                 Impl_writeImage( pA->GetBitmap(),
    1729           0 :                           pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmap().GetSizePixel()),
    1730           0 :                           Point(), pA->GetBitmap().GetSizePixel(), clipRect, 1 ==bMap );
    1731             :             }
    1732           0 :             break;
    1733             : 
    1734             :             case( META_BMPSCALEPART_ACTION ):
    1735             :             {
    1736           0 :                 const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pAction;
    1737           0 :                 Impl_writeImage( pA->GetBitmap(),
    1738           0 :                           pA->GetDestPoint(), pA->GetDestSize(),
    1739           0 :                           pA->GetSrcPoint(), pA->GetSrcSize(), clipRect, 1 == bMap );
    1740             :             }
    1741           0 :             break;
    1742             : 
    1743             :             case( META_BMPEX_ACTION ):
    1744             :             {
    1745           0 :                 const MetaBmpExAction*  pA = (const MetaBmpExAction*) pAction;
    1746           0 :                 Impl_writeImage( pA->GetBitmapEx(),
    1747           0 :                           pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmapEx().GetSizePixel() ),
    1748           0 :                           Point(), pA->GetBitmapEx().GetSizePixel(), clipRect, 1 == bMap );
    1749             :             }
    1750           0 :             break;
    1751             : 
    1752             :             case( META_BMPEXSCALE_ACTION ):
    1753             :             {
    1754           0 :                 const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction;
    1755           0 :                 Impl_writeImage( pA->GetBitmapEx(),
    1756           0 :                           pA->GetPoint(), pA->GetSize(),
    1757           0 :                           Point(), pA->GetBitmapEx().GetSizePixel(), clipRect, 1 == bMap );
    1758             :             }
    1759           0 :             break;
    1760             : 
    1761             :             case( META_BMPEXSCALEPART_ACTION ):
    1762             :             {
    1763           0 :                 const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pAction;
    1764           0 :                 Impl_writeImage( pA->GetBitmapEx(),
    1765           0 :                           pA->GetDestPoint(), pA->GetDestSize(),
    1766           0 :                           pA->GetSrcPoint(), pA->GetSrcSize(), clipRect, 1 == bMap );
    1767             :             }
    1768           0 :             break;
    1769             : 
    1770             :             case( META_TEXT_ACTION ):
    1771             :             {
    1772           0 :                 const MetaTextAction* pA = (const MetaTextAction*) pAction;
    1773           0 :                 Impl_writeText( pA->GetPoint(),  pA->GetText().copy( pA->GetIndex(), pA->GetLen() ), NULL, 0);
    1774             :             }
    1775           0 :             break;
    1776             : 
    1777             :             case( META_TEXTRECT_ACTION ):
    1778             :             {
    1779           0 :                 const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction;
    1780           0 :                 Impl_writeText( pA->GetRect().TopLeft(), pA->GetText(), NULL, 0  );
    1781             :             }
    1782           0 :             break;
    1783             : 
    1784             :             case( META_TEXTARRAY_ACTION ):
    1785             :             {
    1786           0 :                 const MetaTextArrayAction*  pA = (const MetaTextArrayAction*) pAction;
    1787           0 :                 Impl_writeText( pA->GetPoint(), pA->GetText().copy( pA->GetIndex(), pA->GetLen() ), pA->GetDXArray(), 0 );
    1788             :             }
    1789           0 :             break;
    1790             : 
    1791             :             case( META_STRETCHTEXT_ACTION ):
    1792             :             {
    1793           0 :                 const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction;
    1794           0 :                 Impl_writeText( pA->GetPoint(), pA->GetText().copy( pA->GetIndex(), pA->GetLen() ), NULL, pA->GetWidth() );
    1795             :             }
    1796           0 :             break;
    1797             : 
    1798             :             case( META_ISECTRECTCLIPREGION_ACTION ):
    1799             :             {
    1800           0 :                 const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*) pAction;
    1801           0 :                 clipRect = pA->GetRect();
    1802             :             }
    1803             :             // fall-through
    1804             :             case( META_CLIPREGION_ACTION ):
    1805             :             case( META_ISECTREGIONCLIPREGION_ACTION ):
    1806             :             case( META_MOVECLIPREGION_ACTION ):
    1807             :             {
    1808           0 :                 ( (MetaAction*) pAction )->Execute( mpVDev );
    1809             :             }
    1810           0 :             break;
    1811             : 
    1812             :             case( META_MAPMODE_ACTION ):
    1813             :             {
    1814           0 :                 bMap++;
    1815             :             }
    1816             :             // fall-through
    1817             :             case( META_REFPOINT_ACTION ):
    1818             :             case( META_LINECOLOR_ACTION ):
    1819             :             case( META_FILLCOLOR_ACTION ):
    1820             :             case( META_TEXTLINECOLOR_ACTION ):
    1821             :             case( META_TEXTFILLCOLOR_ACTION ):
    1822             :             case( META_TEXTCOLOR_ACTION ):
    1823             :             case( META_TEXTALIGN_ACTION ):
    1824             :             case( META_FONT_ACTION ):
    1825             :             case( META_PUSH_ACTION ):
    1826             :             case( META_POP_ACTION ):
    1827             :             case( META_LAYOUTMODE_ACTION ):
    1828             :             {
    1829           0 :                 ( (MetaAction*) pAction )->Execute( mpVDev );
    1830             :             }
    1831           0 :             break;
    1832             : 
    1833             :             case( META_RASTEROP_ACTION ):
    1834             :             case( META_MASK_ACTION ):
    1835             :             case( META_MASKSCALE_ACTION ):
    1836             :             case( META_MASKSCALEPART_ACTION ):
    1837             :             case( META_WALLPAPER_ACTION ):
    1838             :             case( META_TEXTLINE_ACTION ):
    1839             :             {
    1840             :                 // !!! >>> we don't want to support these actions
    1841             :             }
    1842           0 :             break;
    1843             : 
    1844             :             default:
    1845           0 :             break;
    1846             :         }
    1847             :     }
    1848           0 : }
    1849             : 
    1850             : 
    1851             : 
    1852             : 
    1853             : 
    1854           0 : void Writer::Impl_addStraightLine( BitStream& rBits, Point& rLastPoint,
    1855             :                                    const double P2x, const double P2y )
    1856             : {
    1857           0 :     Point aPoint( FRound(P2x), FRound(P2y) );
    1858             : 
    1859           0 :     Impl_addStraightEdgeRecord( rBits, _Int16(aPoint.X() - rLastPoint.X()),_Int16(aPoint.Y() - rLastPoint.Y()));
    1860           0 :     rLastPoint = aPoint;
    1861             : 
    1862           0 : }
    1863             : 
    1864             : 
    1865             : 
    1866           0 : void Writer::Impl_addQuadBezier( BitStream& rBits, Point& rLastPoint,
    1867             :                                  const double P2x, const double P2y,
    1868             :                                  const double P3x, const double P3y )
    1869             : {
    1870             : 
    1871           0 :     Point aControlPoint( FRound(P2x), FRound(P2y) );
    1872           0 :     Point aAnchorPoint( FRound(P3x), FRound(P3y) );
    1873             : 
    1874             :     Impl_addCurvedEdgeRecord( rBits,
    1875           0 :                                 _Int16(aControlPoint.X() - rLastPoint.X()),_Int16(aControlPoint.Y() - rLastPoint.Y()),
    1876           0 :                                 _Int16(aAnchorPoint.X() - aControlPoint.X()),_Int16(aAnchorPoint.Y() - aControlPoint.Y()) );
    1877           0 :     rLastPoint = aAnchorPoint;
    1878           0 : }
    1879             : 
    1880             : 
    1881             : 
    1882             : /* Approximate given cubic bezier curve by quadratic bezier segments */
    1883           0 : void Writer::Impl_quadBezierApprox( BitStream& rBits,
    1884             :                                    Point& rLastPoint,
    1885             :                                    const double d2,
    1886             :                                    const double P1x, const double P1y,
    1887             :                                    const double P2x, const double P2y,
    1888             :                                    const double P3x, const double P3y,
    1889             :                                    const double P4x, const double P4y )
    1890             : {
    1891             :     // Check for degenerate case, where the given cubic bezier curve
    1892             :     // is already quadratic: P4 == 3P3 - 3P2 + P1
    1893           0 :     if( P4x == 3.0*P3x - 3.0*P2x + P1x &&
    1894           0 :         P4y == 3.0*P3y - 3.0*P2y + P1y )
    1895             :     {
    1896             :         Impl_addQuadBezier( rBits, rLastPoint,
    1897           0 :                            3.0/2.0*P2x - 1.0/2.0*P1x, 3.0/2.0*P2y - 1.0/2.0*P1y,
    1898           0 :                            P4x, P4y);
    1899             :     }
    1900             :     else
    1901             :     {
    1902             :         // Create quadratic segment for given cubic:
    1903             :         // Start and end point must coincide, determine quadratic control
    1904             :         // point in such a way that it lies on the intersection of the
    1905             :         // tangents at start and end point, resp. Thus, both cubic and
    1906             :         // quadratic curve segments will match in 0th and 1st derivative
    1907             :         // at the start and end points
    1908             : 
    1909             :         // Intersection of P2P1 and P4P3
    1910             :         //           (P2y-P4y)(P3x-P4x)-(P2x-P4x)(P3y-P4y)
    1911             :         //  lambda = -------------------------------------
    1912             :         //           (P1x-P2x)(P3y-P4y)-(P1y-P2y)(P3x-P4x)
    1913             :         //
    1914             :         // Intersection point IP is now
    1915             :         // IP = P2 + lambda(P1-P2)
    1916             :         //
    1917           0 :         const double nominator( (P2y-P4y)*(P3x-P4x) - (P2x-P4x)*(P3y-P4y) );
    1918           0 :         const double denominator( (P1x-P2x)*(P3y-P4y) - (P1y-P2y)*(P3x-P4x) );
    1919           0 :         const double lambda( nominator / denominator );
    1920             : 
    1921           0 :         const double IPx( P2x + lambda*( P1x - P2x) );
    1922           0 :         const double IPy( P2y + lambda*( P1y - P2y) );
    1923             : 
    1924             :         // Introduce some alias names: quadratic start point is P1, end
    1925             :         // point is P4, control point is IP
    1926           0 :         const double QP1x( P1x );
    1927           0 :         const double QP1y( P1y );
    1928           0 :         const double QP2x( IPx );
    1929           0 :         const double QP2y( IPy );
    1930           0 :         const double QP3x( P4x );
    1931           0 :         const double QP3y( P4y );
    1932             : 
    1933             :         // Adapted bezier flatness test (lecture notes from R. Schaback,
    1934             :         // Mathematics of Computer-Aided Design, Uni Goettingen, 2000)
    1935             :         //
    1936             :         // ||C(t) - Q(t)|| <= max     ||c_j - q_j||
    1937             :         //                    0<=j<=n
    1938             :         //
    1939             :         // In this case, we don't need the distance from the cubic bezier
    1940             :         // to a straight line, but to a quadratic bezier. The c_j's are
    1941             :         // the cubic bezier's bernstein coefficients, the q_j's the
    1942             :         // quadratic bezier's. We have the c_j's given, the q_j's can be
    1943             :         // calculated from QPi like this (sorry, mixed index notation, we
    1944             :         // use [1,n], formulas use [0,n-1]):
    1945             :         //
    1946             :         // q_0 = QP1 = P1
    1947             :         // q_1 = 1/3 QP1 + 2/3 QP2
    1948             :         // q_2 = 2/3 QP2 + 1/3 QP3
    1949             :         // q_3 = QP3 = P4
    1950             :         //
    1951             :         // We can drop case 0 and 3, since there the curves coincide
    1952             :         // (distance is zero)
    1953             : 
    1954             :         // calculate argument of max for j=1 and j=2
    1955           0 :         const double fJ1x( P2x - 1.0/3.0*QP1x - 2.0/3.0*QP2x );
    1956           0 :         const double fJ1y( P2y - 1.0/3.0*QP1y - 2.0/3.0*QP2y );
    1957           0 :         const double fJ2x( P3x - 2.0/3.0*QP2x - 1.0/3.0*QP3x );
    1958           0 :         const double fJ2y( P3y - 2.0/3.0*QP2y - 1.0/3.0*QP3y );
    1959             : 
    1960             :         // stop if distance from cubic curve is guaranteed to be bounded by d
    1961             :         // Should denominator be 0: then P1P2 and P3P4 are parallel (P1P2^T R[90,P3P4] = 0.0),
    1962             :         // meaning that either we have a straight line or an inflexion point (see else block below)
    1963           0 :         if( 0.0 != denominator &&
    1964           0 :             ::std::max( fJ1x*fJ1x + fJ1y*fJ1y,
    1965           0 :                         fJ2x*fJ2x + fJ2y*fJ2y) < d2 )
    1966             :         {
    1967             :             // requested resolution reached.
    1968             :             // Add end points to output file.
    1969             :             // order is preserved, since this is so to say depth first traversal.
    1970             :             Impl_addQuadBezier( rBits, rLastPoint,
    1971             :                                 QP2x, QP2y,
    1972           0 :                                 QP3x, QP3y);
    1973             :         }
    1974             :         else
    1975             :         {
    1976             :             // Maybe subdivide further
    1977             : 
    1978             :             // This is for robustness reasons, since the line intersection
    1979             :             // method below gets instable if the curve gets closer to a
    1980             :             // straight line. If the given cubic bezier does not deviate by
    1981             :             // more than d/4 from a straight line, either:
    1982             :             //  - take the line (that's what we do here)
    1983             :             //  - express the line by a quadratic bezier
    1984             : 
    1985             :             // Perform bezier flatness test (lecture notes from R. Schaback,
    1986             :             // Mathematics of Computer-Aided Design, Uni Goettingen, 2000)
    1987             :             //
    1988             :             // ||P(t) - L(t)|| <= max     ||b_j - b_0 - j/n(b_n - b_0)||
    1989             :             //                    0<=j<=n
    1990             :             //
    1991             :             // What is calculated here is an upper bound to the distance from
    1992             :             // a line through b_0 and b_3 (P1 and P4 in our notation) and the
    1993             :             // curve. We can drop 0 and n from the running indices, since the
    1994             :             // argument of max becomes zero for those cases.
    1995           0 :             const double fJ1x2( P2x - P1x - 1.0/3.0*(P4x - P1x) );
    1996           0 :             const double fJ1y2( P2y - P1y - 1.0/3.0*(P4y - P1y) );
    1997           0 :             const double fJ2x2( P3x - P1x - 2.0/3.0*(P4x - P1x) );
    1998           0 :             const double fJ2y2( P3y - P1y - 2.0/3.0*(P4y - P1y) );
    1999             : 
    2000             :             // stop if distance from line is guaranteed to be bounded by d/4
    2001           0 :             if( ::std::max( fJ1x2*fJ1x2 + fJ1y2*fJ1y2,
    2002           0 :                             fJ2x2*fJ2x2 + fJ2y2*fJ2y2) < d2/16.0 )
    2003             :             {
    2004             :                 // do not subdivide further, add straight line instead
    2005           0 :                 Impl_addStraightLine( rBits, rLastPoint, P4x, P4y);
    2006             :             }
    2007             :             else
    2008             :             {
    2009             :                 // deCasteljau bezier arc, split at t=0.5
    2010             :                 // Foley/vanDam, p. 508
    2011           0 :                 const double L1x( P1x ),             L1y( P1y );
    2012           0 :                 const double L2x( (P1x + P2x)*0.5 ), L2y( (P1y + P2y)*0.5 );
    2013           0 :                 const double Hx ( (P2x + P3x)*0.5 ), Hy ( (P2y + P3y)*0.5 );
    2014           0 :                 const double L3x( (L2x + Hx)*0.5 ),  L3y( (L2y + Hy)*0.5 );
    2015           0 :                 const double R4x( P4x ),             R4y( P4y );
    2016           0 :                 const double R3x( (P3x + P4x)*0.5 ), R3y( (P3y + P4y)*0.5 );
    2017           0 :                 const double R2x( (Hx + R3x)*0.5 ),  R2y( (Hy + R3y)*0.5 );
    2018           0 :                 const double R1x( (L3x + R2x)*0.5 ), R1y( (L3y + R2y)*0.5 );
    2019           0 :                 const double L4x( R1x ),             L4y( R1y );
    2020             : 
    2021             :                 // subdivide further
    2022           0 :                 Impl_quadBezierApprox(rBits, rLastPoint, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y);
    2023           0 :                 Impl_quadBezierApprox(rBits, rLastPoint, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y);
    2024             :             }
    2025             :         }
    2026             :     }
    2027           0 : }
    2028             : 
    2029           0 : Reference < XBreakIterator > Writer::Impl_GetBreakIterator()
    2030             : {
    2031           0 :     if ( !mxBreakIterator.is() )
    2032             :     {
    2033           0 :         Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
    2034           0 :         mxBreakIterator = BreakIterator::create(xContext);
    2035             :     }
    2036           0 :     return mxBreakIterator;
    2037           0 : }
    2038             : 
    2039             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10