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

Generated by: LCOV version 1.10