LCOV - code coverage report
Current view: top level - cppcanvas/source/mtfrenderer - textaction.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1 493 0.2 %
Date: 2014-11-03 Functions: 2 76 2.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include <canvas/debug.hxx>
      22             : #include <tools/diagnose_ex.h>
      23             : #include <canvas/verbosetrace.hxx>
      24             : 
      25             : #include <com/sun/star/rendering/PathCapType.hpp>
      26             : #include <com/sun/star/rendering/PathJoinType.hpp>
      27             : #include <com/sun/star/rendering/XCanvas.hpp>
      28             : #include <com/sun/star/rendering/XCanvasFont.hpp>
      29             : 
      30             : #include <basegfx/numeric/ftools.hxx>
      31             : #include <basegfx/matrix/b2dhommatrix.hxx>
      32             : #include <basegfx/range/b2drectangle.hxx>
      33             : #include <basegfx/vector/b2dsize.hxx>
      34             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      35             : #include <basegfx/polygon/b2dpolygontools.hxx>
      36             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      37             : 
      38             : #include <tools/gen.hxx>
      39             : #include <vcl/canvastools.hxx>
      40             : #include <vcl/virdev.hxx>
      41             : 
      42             : #include <basegfx/tools/canvastools.hxx>
      43             : #include <canvas/canvastools.hxx>
      44             : 
      45             : #include <boost/scoped_array.hpp>
      46             : #include <boost/bind.hpp>
      47             : #include <boost/utility.hpp>
      48             : 
      49             : #include "textaction.hxx"
      50             : #include "outdevstate.hxx"
      51             : #include "mtftools.hxx"
      52             : 
      53             : 
      54             : using namespace ::com::sun::star;
      55             : 
      56             : namespace cppcanvas
      57             : {
      58             :     namespace internal
      59             :     {
      60             :         namespace
      61             :         {
      62           0 :             void init( rendering::RenderState&                  o_rRenderState,
      63             :                        const ::basegfx::B2DPoint&               rStartPoint,
      64             :                        const OutDevState&                       rState,
      65             :                        const CanvasSharedPtr&                   rCanvas      )
      66             :             {
      67           0 :                 tools::initRenderState(o_rRenderState,rState);
      68             : 
      69             :                 // #i36950# Offset clip back to origin (as it's also moved
      70             :                 // by rStartPoint)
      71             :                 // #i53964# Also take VCL font rotation into account,
      72             :                 // since this, opposed to the FontMatrix rotation
      73             :                 // elsewhere, _does_ get incorporated into the render
      74             :                 // state transform.
      75             :                 tools::modifyClip( o_rRenderState,
      76             :                                    rState,
      77             :                                    rCanvas,
      78             :                                    rStartPoint,
      79             :                                    NULL,
      80           0 :                                    &rState.fontRotation );
      81             : 
      82           0 :                 basegfx::B2DHomMatrix aLocalTransformation(basegfx::tools::createRotateB2DHomMatrix(rState.fontRotation));
      83             :                 aLocalTransformation.translate( rStartPoint.getX(),
      84           0 :                                                 rStartPoint.getY() );
      85             :                 ::canvas::tools::appendToRenderState( o_rRenderState,
      86           0 :                                                       aLocalTransformation );
      87             : 
      88           0 :                 o_rRenderState.DeviceColor = rState.textColor;
      89           0 :             }
      90             : 
      91           0 :             void init( rendering::RenderState&                  o_rRenderState,
      92             :                        const ::basegfx::B2DPoint&               rStartPoint,
      93             :                        const OutDevState&                       rState,
      94             :                        const CanvasSharedPtr&                   rCanvas,
      95             :                        const ::basegfx::B2DHomMatrix&           rTextTransform  )
      96             :             {
      97           0 :                 init( o_rRenderState, rStartPoint, rState, rCanvas );
      98             : 
      99             :                 // TODO(F2): Also inversely-transform clip with
     100             :                 // rTextTransform (which is actually rather hard, as the
     101             :                 // text transform is _prepended_ to the render state)!
     102             : 
     103             :                 // prepend extra font transform to render state
     104             :                 // (prepend it, because it's interpreted in the unit
     105             :                 // rect coordinate space)
     106             :                 ::canvas::tools::prependToRenderState( o_rRenderState,
     107           0 :                                                        rTextTransform );
     108           0 :             }
     109             : 
     110           0 :             void init( rendering::RenderState&                      o_rRenderState,
     111             :                        uno::Reference< rendering::XCanvasFont >&    o_rFont,
     112             :                        const ::basegfx::B2DPoint&                   rStartPoint,
     113             :                        const OutDevState&                           rState,
     114             :                        const CanvasSharedPtr&                       rCanvas      )
     115             :             {
     116             :                 // ensure that o_rFont is valid. It is possible that
     117             :                 // text actions are generated without previously
     118             :                 // setting a font. Then, just take a default font
     119           0 :                 if( !o_rFont.is() )
     120             :                 {
     121             :                     // Use completely default FontRequest
     122           0 :                     const rendering::FontRequest aFontRequest;
     123             : 
     124           0 :                     geometry::Matrix2D aFontMatrix;
     125           0 :                     ::canvas::tools::setIdentityMatrix2D( aFontMatrix );
     126             : 
     127           0 :                     o_rFont = rCanvas->getUNOCanvas()->createFont(
     128             :                         aFontRequest,
     129             :                         uno::Sequence< beans::PropertyValue >(),
     130           0 :                         aFontMatrix );
     131             :                 }
     132             : 
     133             :                 init( o_rRenderState,
     134             :                       rStartPoint,
     135             :                       rState,
     136           0 :                       rCanvas );
     137           0 :             }
     138             : 
     139           0 :             void init( rendering::RenderState&                      o_rRenderState,
     140             :                        uno::Reference< rendering::XCanvasFont >&    o_rFont,
     141             :                        const ::basegfx::B2DPoint&                   rStartPoint,
     142             :                        const OutDevState&                           rState,
     143             :                        const CanvasSharedPtr&                       rCanvas,
     144             :                        const ::basegfx::B2DHomMatrix&               rTextTransform  )
     145             :             {
     146           0 :                 init( o_rRenderState, o_rFont, rStartPoint, rState, rCanvas );
     147             : 
     148             :                 // TODO(F2): Also inversely-transform clip with
     149             :                 // rTextTransform (which is actually rather hard, as the
     150             :                 // text transform is _prepended_ to the render state)!
     151             : 
     152             :                 // prepend extra font transform to render state
     153             :                 // (prepend it, because it's interpreted in the unit
     154             :                 // rect coordinate space)
     155             :                 ::canvas::tools::prependToRenderState( o_rRenderState,
     156           0 :                                                        rTextTransform );
     157           0 :             }
     158             : 
     159           0 :             ::basegfx::B2DPolyPolygon textLinesFromLogicalOffsets( const uno::Sequence< double >&   rOffsets,
     160             :                                                                    const tools::TextLineInfo&       rTextLineInfo )
     161             :             {
     162             :                 return tools::createTextLinesPolyPolygon(
     163             :                     0.0,
     164             :                     // extract character cell furthest to the right
     165             :                     *(::std::max_element(
     166             :                           rOffsets.getConstArray(),
     167           0 :                           rOffsets.getConstArray() + rOffsets.getLength() )),
     168           0 :                     rTextLineInfo );
     169             :             }
     170             : 
     171           0 :             uno::Sequence< double > setupDXArray( const long*   pCharWidths,
     172             :                                                   sal_Int32          nLen,
     173             :                                                   const OutDevState& rState )
     174             :             {
     175             :                 // convert character widths from logical units
     176           0 :                 uno::Sequence< double > aCharWidthSeq( nLen );
     177           0 :                 double*                 pOutputWidths( aCharWidthSeq.getArray() );
     178             : 
     179             :                 // #143885# maintain (nearly) full precision of DX
     180             :                 // array, by circumventing integer-based
     181             :                 // OutDev-mapping
     182           0 :                 const double nScale( rState.mapModeTransform.get(0,0) );
     183           0 :                 for( int i = 0; i < nLen; ++i )
     184             :                 {
     185             :                     // TODO(F2): use correct scale direction
     186           0 :                     *pOutputWidths++ = *pCharWidths++ * nScale;
     187             :                 }
     188             : 
     189           0 :                 return aCharWidthSeq;
     190             :             }
     191             : 
     192           0 :             uno::Sequence< double > setupDXArray( const OUString&    rText,
     193             :                                                   sal_Int32          nStartPos,
     194             :                                                   sal_Int32          nLen,
     195             :                                                   VirtualDevice&     rVDev,
     196             :                                                   const OutDevState& rState )
     197             :             {
     198             :                 // no external DX array given, create one from given
     199             :                 // string
     200           0 :                 ::boost::scoped_array< long > pCharWidths( new long[nLen] );
     201             : 
     202             :                 rVDev.GetTextArray( rText, pCharWidths.get(),
     203           0 :                                     nStartPos, nLen );
     204             : 
     205           0 :                 return setupDXArray( pCharWidths.get(), nLen, rState );
     206             :             }
     207             : 
     208           0 :             ::basegfx::B2DPoint adaptStartPoint( const ::basegfx::B2DPoint&     rStartPoint,
     209             :                                                  const OutDevState&             rState,
     210             :                                                  const uno::Sequence< double >& rOffsets )
     211             :             {
     212           0 :                 ::basegfx::B2DPoint aLocalPoint( rStartPoint );
     213             : 
     214           0 :                 if( rState.textAlignment )
     215             :                 {
     216             :                     // text origin is right, not left. Modify start point
     217             :                     // accordingly, because XCanvas::drawTextLayout()
     218             :                     // always aligns left!
     219             : 
     220           0 :                     const double nOffset( rOffsets[ rOffsets.getLength()-1 ] );
     221             : 
     222             :                     // correct start point for rotated text: rotate around
     223             :                     // former start point
     224           0 :                     aLocalPoint.setX( aLocalPoint.getX() + cos( rState.fontRotation )*nOffset );
     225           0 :                     aLocalPoint.setY( aLocalPoint.getY() + sin( rState.fontRotation )*nOffset );
     226             :                 }
     227             : 
     228           0 :                 return aLocalPoint;
     229             :             }
     230             : 
     231             :             /** Perform common setup for array text actions
     232             : 
     233             :                 This method creates the XTextLayout object and
     234             :                 initializes it, e.g. with the logical advancements.
     235             :              */
     236           0 :             void initArrayAction( rendering::RenderState&                   o_rRenderState,
     237             :                                   uno::Reference< rendering::XTextLayout >& o_rTextLayout,
     238             :                                   const ::basegfx::B2DPoint&                rStartPoint,
     239             :                                   const OUString&                    rText,
     240             :                                   sal_Int32                                 nStartPos,
     241             :                                   sal_Int32                                 nLen,
     242             :                                   const uno::Sequence< double >&            rOffsets,
     243             :                                   const CanvasSharedPtr&                    rCanvas,
     244             :                                   const OutDevState&                        rState,
     245             :                                   const ::basegfx::B2DHomMatrix*            pTextTransform )
     246             :             {
     247           0 :                 ENSURE_OR_THROW( rOffsets.getLength(),
     248             :                                   "::cppcanvas::internal::initArrayAction(): zero-length DX array" );
     249             : 
     250             :                 const ::basegfx::B2DPoint aLocalStartPoint(
     251           0 :                     adaptStartPoint( rStartPoint, rState, rOffsets ) );
     252             : 
     253           0 :                 uno::Reference< rendering::XCanvasFont > xFont( rState.xFont );
     254             : 
     255           0 :                 if( pTextTransform )
     256           0 :                     init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas, *pTextTransform );
     257             :                 else
     258           0 :                     init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas );
     259             : 
     260           0 :                 o_rTextLayout = xFont->createTextLayout(
     261             :                     rendering::StringContext( rText, nStartPos, nLen ),
     262             :                     rState.textDirection,
     263           0 :                     0 );
     264             : 
     265           0 :                 ENSURE_OR_THROW( o_rTextLayout.is(),
     266             :                                   "::cppcanvas::internal::initArrayAction(): Invalid font" );
     267             : 
     268           0 :                 o_rTextLayout->applyLogicalAdvancements( rOffsets );
     269           0 :             }
     270             : 
     271           0 :             double getLineWidth( ::VirtualDevice&                rVDev,
     272             :                                  const OutDevState&              rState,
     273             :                                  const rendering::StringContext& rStringContext )
     274             :             {
     275             :                 // TODO(F2): use correct scale direction
     276             :                 const ::basegfx::B2DSize aSize( rVDev.GetTextWidth( rStringContext.Text,
     277             :                                                                     static_cast<sal_uInt16>(rStringContext.StartPosition),
     278           0 :                                                                     static_cast<sal_uInt16>(rStringContext.Length) ),
     279           0 :                                     0 );
     280             : 
     281           0 :                 return (rState.mapModeTransform * aSize).getX();
     282             :             }
     283             : 
     284             :             uno::Sequence< double >
     285           0 :                 calcSubsetOffsets( rendering::RenderState&                          io_rRenderState,
     286             :                                    double&                                          o_rMinPos,
     287             :                                    double&                                          o_rMaxPos,
     288             :                                    const uno::Reference< rendering::XTextLayout >&  rOrigTextLayout,
     289             :                                    const ::cppcanvas::internal::Action::Subset&     rSubset )
     290             :             {
     291           0 :                 ENSURE_OR_THROW( rSubset.mnSubsetEnd > rSubset.mnSubsetBegin,
     292             :                                   "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
     293             : 
     294           0 :                 uno::Sequence< double > aOrigOffsets( rOrigTextLayout->queryLogicalAdvancements() );
     295           0 :                 const double*           pOffsets( aOrigOffsets.getConstArray() );
     296             : 
     297           0 :                 ENSURE_OR_THROW( aOrigOffsets.getLength() >= rSubset.mnSubsetEnd,
     298             :                                   "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
     299             : 
     300             :                 // TODO(F3): It currently seems that for RTL text, the
     301             :                 // DX offsets are nevertheless increasing in logical
     302             :                 // text order (I'd expect they are decreasing,
     303             :                 // mimicking the fact that the text is output
     304             :                 // right-to-left). This breaks text effects for ALL
     305             :                 // RTL languages.
     306             : 
     307             :                 // determine leftmost position in given subset range -
     308             :                 // as the DX array contains the output positions
     309             :                 // starting with the second character (the first is
     310             :                 // assumed to have output position 0), correct begin
     311             :                 // iterator.
     312           0 :                 const double nMinPos( rSubset.mnSubsetBegin <= 0 ? 0 :
     313           0 :                                       *(::std::min_element( pOffsets+rSubset.mnSubsetBegin-1,
     314           0 :                                                             pOffsets+rSubset.mnSubsetEnd )) );
     315             : 
     316             :                 // determine rightmost position in given subset range
     317             :                 // - as the DX array contains the output positions
     318             :                 // starting with the second character (the first is
     319             :                 // assumed to have output position 0), correct begin
     320             :                 // iterator.
     321             :                 const double nMaxPos(
     322           0 :                     *(::std::max_element( pOffsets + (rSubset.mnSubsetBegin <= 0 ?
     323           0 :                                                       0 : rSubset.mnSubsetBegin-1),
     324           0 :                                           pOffsets + rSubset.mnSubsetEnd )) );
     325             : 
     326             : 
     327             :                 // adapt render state, to move text output to given offset
     328             : 
     329             : 
     330             :                 // TODO(F1): Strictly speaking, we also have to adapt
     331             :                 // the clip here, which normally should _not_ move
     332             :                 // with the output offset. Neglected for now, as it
     333             :                 // does not matter for drawing layer output
     334             : 
     335           0 :                 if( rSubset.mnSubsetBegin > 0 )
     336             :                 {
     337           0 :                     ::basegfx::B2DHomMatrix aTranslation;
     338           0 :                     if( rOrigTextLayout->getFont()->getFontRequest().FontDescription.IsVertical )
     339             :                     {
     340             :                         // vertical text -> offset in y direction
     341           0 :                         aTranslation.translate( 0.0, nMinPos );
     342             :                     }
     343             :                     else
     344             :                     {
     345             :                         // horizontal text -> offset in x direction
     346           0 :                         aTranslation.translate( nMinPos, 0.0 );
     347             :                     }
     348             : 
     349             :                     ::canvas::tools::appendToRenderState( io_rRenderState,
     350           0 :                                                           aTranslation );
     351             :                 }
     352             : 
     353             : 
     354             :                 // reduce DX array to given substring
     355             : 
     356             : 
     357           0 :                 const sal_Int32         nNewElements( rSubset.mnSubsetEnd - rSubset.mnSubsetBegin );
     358           0 :                 uno::Sequence< double > aAdaptedOffsets( nNewElements );
     359           0 :                 double*                 pAdaptedOffsets( aAdaptedOffsets.getArray() );
     360             : 
     361             :                 // move to new output position (subtract nMinPos,
     362             :                 // which is the new '0' position), copy only the range
     363             :                 // as given by rSubset.
     364             :                 ::std::transform( pOffsets + rSubset.mnSubsetBegin,
     365             :                                   pOffsets + rSubset.mnSubsetEnd,
     366             :                                   pAdaptedOffsets,
     367             :                                   ::boost::bind( ::std::minus<double>(),
     368             :                                                  _1,
     369           0 :                                                  nMinPos ) );
     370             : 
     371           0 :                 o_rMinPos = nMinPos;
     372           0 :                 o_rMaxPos = nMaxPos;
     373             : 
     374           0 :                 return aAdaptedOffsets;
     375             :             }
     376             : 
     377             :             uno::Reference< rendering::XTextLayout >
     378           0 :                 createSubsetLayout( const rendering::StringContext&                 rOrigContext,
     379             :                                     const ::cppcanvas::internal::Action::Subset&    rSubset,
     380             :                                     const uno::Reference< rendering::XTextLayout >& rOrigTextLayout )
     381             :             {
     382             :                 // create temporary new text layout with subset string
     383             : 
     384             : 
     385           0 :                 const sal_Int32 nNewStartPos( rOrigContext.StartPosition + ::std::min(
     386           0 :                                                   rSubset.mnSubsetBegin, rOrigContext.Length-1 ) );
     387             :                 const sal_Int32 nNewLength( ::std::max(
     388             :                                                 ::std::min(
     389           0 :                                                     rSubset.mnSubsetEnd - rSubset.mnSubsetBegin,
     390           0 :                                                     rOrigContext.Length ),
     391           0 :                                                 sal_Int32( 0 ) ) );
     392             : 
     393             :                 const rendering::StringContext aContext( rOrigContext.Text,
     394             :                                                          nNewStartPos,
     395           0 :                                                          nNewLength );
     396             : 
     397             :                 uno::Reference< rendering::XTextLayout > xTextLayout(
     398           0 :                     rOrigTextLayout->getFont()->createTextLayout( aContext,
     399           0 :                                                                   rOrigTextLayout->getMainTextDirection(),
     400           0 :                                                                   0 ),
     401           0 :                     uno::UNO_QUERY_THROW );
     402             : 
     403           0 :                 return xTextLayout;
     404             :             }
     405             : 
     406             :             /** Setup subset text layout
     407             : 
     408             :                 @param io_rTextLayout
     409             :                 Must contain original (full set) text layout on input,
     410             :                 will contain subsetted text layout (or empty
     411             :                 reference, for empty subsets) on output.
     412             : 
     413             :                 @param io_rRenderState
     414             :                 Must contain original render state on input, will
     415             :                 contain shifted render state concatenated with
     416             :                 rTransformation on output.
     417             : 
     418             :                 @param rTransformation
     419             :                 Additional transformation, to be prepended to render
     420             :                 state
     421             : 
     422             :                 @param rSubset
     423             :                 Subset to prepare
     424             :              */
     425           0 :             void createSubsetLayout( uno::Reference< rendering::XTextLayout >&  io_rTextLayout,
     426             :                                      rendering::RenderState&                    io_rRenderState,
     427             :                                      double&                                    o_rMinPos,
     428             :                                      double&                                    o_rMaxPos,
     429             :                                      const ::basegfx::B2DHomMatrix&             rTransformation,
     430             :                                      const Action::Subset&                      rSubset )
     431             :             {
     432           0 :                 ::canvas::tools::prependToRenderState(io_rRenderState, rTransformation);
     433             : 
     434           0 :                 if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd )
     435             :                 {
     436             :                      // empty range, empty layout
     437           0 :                     io_rTextLayout.clear();
     438             : 
     439           0 :                     return;
     440             :                 }
     441             : 
     442           0 :                 ENSURE_OR_THROW( io_rTextLayout.is(),
     443             :                                   "createSubsetLayout(): Invalid input layout" );
     444             : 
     445           0 :                 const rendering::StringContext& rOrigContext( io_rTextLayout->getText() );
     446             : 
     447           0 :                 if( rSubset.mnSubsetBegin == 0 &&
     448           0 :                     rSubset.mnSubsetEnd == rOrigContext.Length )
     449             :                 {
     450             :                     // full range, no need for subsetting
     451           0 :                     return;
     452             :                 }
     453             : 
     454             :                 uno::Reference< rendering::XTextLayout > xTextLayout(
     455           0 :                     createSubsetLayout( rOrigContext, rSubset, io_rTextLayout ) );
     456             : 
     457           0 :                 if( xTextLayout.is() )
     458             :                 {
     459           0 :                     xTextLayout->applyLogicalAdvancements(
     460             :                         calcSubsetOffsets( io_rRenderState,
     461             :                                            o_rMinPos,
     462             :                                            o_rMaxPos,
     463             :                                            io_rTextLayout,
     464           0 :                                            rSubset ) );
     465             :                 }
     466             : 
     467           0 :                 io_rTextLayout = xTextLayout;
     468             :             }
     469             : 
     470             : 
     471             :             /** Interface for renderEffectText functor below.
     472             : 
     473             :                 This is interface is used from the renderEffectText()
     474             :                 method below, to call the client implementation.
     475             :              */
     476           0 :             class TextRenderer
     477             :             {
     478             :             public:
     479           0 :                 virtual ~TextRenderer() {}
     480             : 
     481             :                 /// Render text with given RenderState
     482             :                 virtual bool operator()( const rendering::RenderState& rRenderState ) const = 0;
     483             :             };
     484             : 
     485             :             /** Render effect text.
     486             : 
     487             :                 @param rRenderer
     488             :                 Functor object, will be called to render the actual
     489             :                 part of the text effect (the text itself and the means
     490             :                 to render it are unknown to this method)
     491             :              */
     492           0 :             bool renderEffectText( const TextRenderer&                          rRenderer,
     493             :                                    const rendering::RenderState&                rRenderState,
     494             :                                    const rendering::ViewState&                  /*rViewState*/,
     495             :                                    const uno::Reference< rendering::XCanvas >&  xCanvas,
     496             :                                    const ::Color&                               rShadowColor,
     497             :                                    const ::basegfx::B2DSize&                    rShadowOffset,
     498             :                                    const ::Color&                               rReliefColor,
     499             :                                    const ::basegfx::B2DSize&                    rReliefOffset )
     500             :             {
     501           0 :                 ::Color aEmptyColor( COL_AUTO );
     502             :                 uno::Reference<rendering::XColorSpace> xColorSpace(
     503           0 :                     xCanvas->getDevice()->getDeviceColorSpace() );
     504             : 
     505             :                 // draw shadow text, if enabled
     506           0 :                 if( rShadowColor != aEmptyColor )
     507             :                 {
     508           0 :                     rendering::RenderState aShadowState( rRenderState );
     509           0 :                     ::basegfx::B2DHomMatrix aTranslate;
     510             : 
     511             :                     aTranslate.translate( rShadowOffset.getX(),
     512           0 :                                           rShadowOffset.getY() );
     513             : 
     514           0 :                     ::canvas::tools::appendToRenderState(aShadowState, aTranslate);
     515             : 
     516           0 :                     aShadowState.DeviceColor =
     517             :                         ::vcl::unotools::colorToDoubleSequence( rShadowColor,
     518           0 :                                                                 xColorSpace );
     519             : 
     520           0 :                     rRenderer( aShadowState );
     521             :                 }
     522             : 
     523             :                 // draw relief text, if enabled
     524           0 :                 if( rReliefColor != aEmptyColor )
     525             :                 {
     526           0 :                     rendering::RenderState aReliefState( rRenderState );
     527           0 :                     ::basegfx::B2DHomMatrix aTranslate;
     528             : 
     529             :                     aTranslate.translate( rReliefOffset.getX(),
     530           0 :                                           rReliefOffset.getY() );
     531             : 
     532           0 :                     ::canvas::tools::appendToRenderState(aReliefState, aTranslate);
     533             : 
     534           0 :                     aReliefState.DeviceColor =
     535             :                         ::vcl::unotools::colorToDoubleSequence( rReliefColor,
     536           0 :                                                                 xColorSpace );
     537             : 
     538           0 :                     rRenderer( aReliefState );
     539             :                 }
     540             : 
     541             :                 // draw normal text
     542           0 :                 rRenderer( rRenderState );
     543             : 
     544           0 :                 return true;
     545             :             }
     546             : 
     547             : 
     548           0 :             ::basegfx::B2DRange calcEffectTextBounds( const ::basegfx::B2DRange&    rTextBounds,
     549             :                                                       const ::basegfx::B2DRange&    rLineBounds,
     550             :                                                       const ::basegfx::B2DSize&     rReliefOffset,
     551             :                                                       const ::basegfx::B2DSize&     rShadowOffset,
     552             :                                                       const rendering::RenderState& rRenderState,
     553             :                                                       const rendering::ViewState&   rViewState )
     554             :             {
     555           0 :                 ::basegfx::B2DRange aBounds( rTextBounds );
     556             : 
     557             :                 // add extends of text lines
     558           0 :                 aBounds.expand( rLineBounds );
     559             : 
     560             :                 // TODO(Q3): Provide this functionality at the B2DRange
     561           0 :                 ::basegfx::B2DRange aTotalBounds( aBounds );
     562             :                 aTotalBounds.expand(
     563           0 :                     ::basegfx::B2DRange( aBounds.getMinX() + rReliefOffset.getX(),
     564           0 :                                          aBounds.getMinY() + rReliefOffset.getY(),
     565           0 :                                          aBounds.getMaxX() + rReliefOffset.getX(),
     566           0 :                                          aBounds.getMaxY() + rReliefOffset.getY() ) );
     567             :                 aTotalBounds.expand(
     568           0 :                     ::basegfx::B2DRange( aBounds.getMinX() + rShadowOffset.getX(),
     569           0 :                                          aBounds.getMinY() + rShadowOffset.getY(),
     570           0 :                                          aBounds.getMaxX() + rShadowOffset.getX(),
     571           0 :                                          aBounds.getMaxY() + rShadowOffset.getY() ) );
     572             : 
     573             :                 return tools::calcDevicePixelBounds( aTotalBounds,
     574             :                                                      rViewState,
     575           0 :                                                      rRenderState );
     576             :             }
     577             : 
     578           0 :             void initEffectLinePolyPolygon( ::basegfx::B2DSize&                             o_rOverallSize,
     579             :                                             uno::Reference< rendering::XPolyPolygon2D >&    o_rTextLines,
     580             :                                             const CanvasSharedPtr&                          rCanvas,
     581             :                                             const uno::Sequence< double >&                  rOffsets,
     582             :                                             const tools::TextLineInfo&                      rLineInfo   )
     583             :             {
     584             :                 const ::basegfx::B2DPolyPolygon aPoly(
     585             :                     textLinesFromLogicalOffsets(
     586             :                         rOffsets,
     587           0 :                         rLineInfo ) );
     588             : 
     589           0 :                 o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange();
     590             : 
     591           0 :                 o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
     592           0 :                     rCanvas->getUNOCanvas()->getDevice(),
     593           0 :                     aPoly );
     594           0 :             }
     595             : 
     596           0 :             void initEffectLinePolyPolygon( ::basegfx::B2DSize&                             o_rOverallSize,
     597             :                                             uno::Reference< rendering::XPolyPolygon2D >&    o_rTextLines,
     598             :                                             const CanvasSharedPtr&                          rCanvas,
     599             :                                             double                                          nLineWidth,
     600             :                                             const tools::TextLineInfo&                      rLineInfo   )
     601             :             {
     602             :                 const ::basegfx::B2DPolyPolygon aPoly(
     603             :                     tools::createTextLinesPolyPolygon( 0.0, nLineWidth,
     604           0 :                                                        rLineInfo ) );
     605             : 
     606           0 :                 o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange();
     607             : 
     608           0 :                 o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
     609           0 :                     rCanvas->getUNOCanvas()->getDevice(),
     610           0 :                     aPoly );
     611           0 :             }
     612             : 
     613             : 
     614             : 
     615             : 
     616           0 :             class TextAction : public Action, private ::boost::noncopyable
     617             :             {
     618             :             public:
     619             :                 TextAction( const ::basegfx::B2DPoint&  rStartPoint,
     620             :                             const OUString&      rString,
     621             :                             sal_Int32                   nStartPos,
     622             :                             sal_Int32                   nLen,
     623             :                             const CanvasSharedPtr&      rCanvas,
     624             :                             const OutDevState&          rState );
     625             : 
     626             :                 TextAction( const ::basegfx::B2DPoint&      rStartPoint,
     627             :                             const OUString&          rString,
     628             :                             sal_Int32                       nStartPos,
     629             :                             sal_Int32                       nLen,
     630             :                             const CanvasSharedPtr&          rCanvas,
     631             :                             const OutDevState&              rState,
     632             :                             const ::basegfx::B2DHomMatrix&  rTextTransform );
     633             : 
     634             :                 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
     635             :                 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
     636             :                                            const Subset&                  rSubset ) const SAL_OVERRIDE;
     637             : 
     638             :                 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
     639             :                 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix&   rTransformation,
     640             :                                                        const Subset&                    rSubset ) const SAL_OVERRIDE;
     641             : 
     642             :                 virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
     643             : 
     644             :             private:
     645             :                 // TODO(P2): This is potentially a real mass object
     646             :                 // (every character might be a separate TextAction),
     647             :                 // thus, make it as lightweight as possible. For
     648             :                 // example, share common RenderState among several
     649             :                 // TextActions, maybe using maOffsets for the
     650             :                 // translation.
     651             : 
     652             :                 uno::Reference< rendering::XCanvasFont >    mxFont;
     653             :                 const rendering::StringContext              maStringContext;
     654             :                 const CanvasSharedPtr                       mpCanvas;
     655             :                 rendering::RenderState                      maState;
     656             :                 const sal_Int8                              maTextDirection;
     657             :             };
     658             : 
     659           0 :             TextAction::TextAction( const ::basegfx::B2DPoint&  rStartPoint,
     660             :                                     const OUString&      rString,
     661             :                                     sal_Int32                   nStartPos,
     662             :                                     sal_Int32                   nLen,
     663             :                                     const CanvasSharedPtr&      rCanvas,
     664             :                                     const OutDevState&          rState  ) :
     665             :                 mxFont( rState.xFont ),
     666             :                 maStringContext( rString, nStartPos, nLen ),
     667             :                 mpCanvas( rCanvas ),
     668             :                 maState(),
     669           0 :                 maTextDirection( rState.textDirection )
     670             :             {
     671             :                 init( maState, mxFont,
     672             :                       rStartPoint,
     673           0 :                       rState, rCanvas );
     674             : 
     675           0 :                 ENSURE_OR_THROW( mxFont.is(),
     676             :                                   "::cppcanvas::internal::TextAction(): Invalid font" );
     677           0 :             }
     678             : 
     679           0 :             TextAction::TextAction( const ::basegfx::B2DPoint&      rStartPoint,
     680             :                                     const OUString&          rString,
     681             :                                     sal_Int32                       nStartPos,
     682             :                                     sal_Int32                       nLen,
     683             :                                     const CanvasSharedPtr&          rCanvas,
     684             :                                     const OutDevState&              rState,
     685             :                                     const ::basegfx::B2DHomMatrix&  rTextTransform ) :
     686             :                 mxFont( rState.xFont ),
     687             :                 maStringContext( rString, nStartPos, nLen ),
     688             :                 mpCanvas( rCanvas ),
     689             :                 maState(),
     690           0 :                 maTextDirection( rState.textDirection )
     691             :             {
     692             :                 init( maState, mxFont,
     693             :                       rStartPoint,
     694           0 :                       rState, rCanvas, rTextTransform );
     695             : 
     696           0 :                 ENSURE_OR_THROW( mxFont.is(),
     697             :                                   "::cppcanvas::internal::TextAction(): Invalid font" );
     698           0 :             }
     699             : 
     700           0 :             bool TextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
     701             :             {
     702             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextAction::render()" );
     703             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextAction: 0x" << std::hex << this );
     704             : 
     705           0 :                 rendering::RenderState aLocalState( maState );
     706           0 :                 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
     707             : 
     708           0 :                 mpCanvas->getUNOCanvas()->drawText( maStringContext, mxFont,
     709           0 :                                                     mpCanvas->getViewState(), aLocalState, maTextDirection );
     710             : 
     711           0 :                 return true;
     712             :             }
     713             : 
     714           0 :             bool TextAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
     715             :                                            const Subset&                  /*rSubset*/ ) const
     716             :             {
     717             :                 SAL_WARN( "cppcanvas.emf", "TextAction::renderSubset(): Subset not supported by this object" );
     718             : 
     719             :                 // TODO(P1): Retrieve necessary font metric info for
     720             :                 // TextAction from XCanvas. Currently, the
     721             :                 // TextActionFactory does not generate this object for
     722             :                 // _subsettable_ text
     723           0 :                 return render( rTransformation );
     724             :             }
     725             : 
     726           0 :             ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
     727             :             {
     728             :                 // create XTextLayout, to have the
     729             :                 // XTextLayout::queryTextBounds() method available
     730             :                 uno::Reference< rendering::XTextLayout > xTextLayout(
     731           0 :                     mxFont->createTextLayout(
     732             :                         maStringContext,
     733             :                         maTextDirection,
     734           0 :                         0 ) );
     735             : 
     736           0 :                 rendering::RenderState aLocalState( maState );
     737           0 :                 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
     738             : 
     739             :                 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
     740           0 :                                                          xTextLayout->queryTextBounds() ),
     741           0 :                                                      mpCanvas->getViewState(),
     742           0 :                                                      aLocalState );
     743             :             }
     744             : 
     745           0 :             ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix&   rTransformation,
     746             :                                                        const Subset&                    /*rSubset*/ ) const
     747             :             {
     748             :                 SAL_WARN( "cppcanvas.emf", "TextAction::getBounds(): Subset not supported by this object" );
     749             : 
     750             :                 // TODO(P1): Retrieve necessary font metric info for
     751             :                 // TextAction from XCanvas. Currently, the
     752             :                 // TextActionFactory does not generate this object for
     753             :                 // _subsettable_ text
     754           0 :                 return getBounds( rTransformation );
     755             :             }
     756             : 
     757           0 :             sal_Int32 TextAction::getActionCount() const
     758             :             {
     759             :                 // TODO(P1): Retrieve necessary font metric info for
     760             :                 // TextAction from XCanvas. Currently, the
     761             :                 // TextActionFactory does not generate this object for
     762             :                 // _subsettable_ text
     763           0 :                 return 1;
     764             :             }
     765             : 
     766             : 
     767             : 
     768             : 
     769           0 :             class EffectTextAction :
     770             :                 public Action,
     771             :                 public TextRenderer,
     772             :                 private ::boost::noncopyable
     773             :             {
     774             :             public:
     775             :                 EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
     776             :                                   const ::basegfx::B2DSize&  rReliefOffset,
     777             :                                   const ::Color&             rReliefColor,
     778             :                                   const ::basegfx::B2DSize&  rShadowOffset,
     779             :                                   const ::Color&             rShadowColor,
     780             :                                   const OUString&     rText,
     781             :                                   sal_Int32                  nStartPos,
     782             :                                   sal_Int32                  nLen,
     783             :                                   VirtualDevice&             rVDev,
     784             :                                   const CanvasSharedPtr&     rCanvas,
     785             :                                   const OutDevState&         rState );
     786             : 
     787             :                 EffectTextAction( const ::basegfx::B2DPoint&        rStartPoint,
     788             :                                   const ::basegfx::B2DSize&         rReliefOffset,
     789             :                                   const ::Color&                    rReliefColor,
     790             :                                   const ::basegfx::B2DSize&         rShadowOffset,
     791             :                                   const ::Color&                    rShadowColor,
     792             :                                   const OUString&            rText,
     793             :                                   sal_Int32                         nStartPos,
     794             :                                   sal_Int32                         nLen,
     795             :                                   VirtualDevice&                    rVDev,
     796             :                                   const CanvasSharedPtr&            rCanvas,
     797             :                                   const OutDevState&                rState,
     798             :                                   const ::basegfx::B2DHomMatrix&    rTextTransform );
     799             : 
     800             :                 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
     801             :                 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
     802             :                                            const Subset&                  rSubset ) const SAL_OVERRIDE;
     803             : 
     804             :                 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
     805             :                 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix&   rTransformation,
     806             :                                                        const Subset&                    rSubset ) const SAL_OVERRIDE;
     807             : 
     808             :                 virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
     809             : 
     810             :             private:
     811             :                 /// Interface TextRenderer
     812             :                 virtual bool operator()( const rendering::RenderState& rRenderState ) const SAL_OVERRIDE;
     813             : 
     814             :                 // TODO(P2): This is potentially a real mass object
     815             :                 // (every character might be a separate TextAction),
     816             :                 // thus, make it as lightweight as possible. For
     817             :                 // example, share common RenderState among several
     818             :                 // TextActions, maybe using maOffsets for the
     819             :                 // translation.
     820             : 
     821             :                 uno::Reference< rendering::XCanvasFont >    mxFont;
     822             :                 const rendering::StringContext              maStringContext;
     823             :                 const CanvasSharedPtr                       mpCanvas;
     824             :                 rendering::RenderState                      maState;
     825             :                 const tools::TextLineInfo                   maTextLineInfo;
     826             :                 ::basegfx::B2DSize                          maLinesOverallSize;
     827             :                 const double                                mnLineWidth;
     828             :                 uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
     829             :                 const ::basegfx::B2DSize                    maReliefOffset;
     830             :                 const ::Color                               maReliefColor;
     831             :                 const ::basegfx::B2DSize                    maShadowOffset;
     832             :                 const ::Color                               maShadowColor;
     833             :                 const sal_Int8                              maTextDirection;
     834             :             };
     835             : 
     836           0 :             EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
     837             :                                                 const ::basegfx::B2DSize&  rReliefOffset,
     838             :                                                 const ::Color&             rReliefColor,
     839             :                                                 const ::basegfx::B2DSize&  rShadowOffset,
     840             :                                                 const ::Color&             rShadowColor,
     841             :                                                 const OUString&     rText,
     842             :                                                 sal_Int32                  nStartPos,
     843             :                                                 sal_Int32                  nLen,
     844             :                                                 VirtualDevice&             rVDev,
     845             :                                                 const CanvasSharedPtr&     rCanvas,
     846             :                                                 const OutDevState&         rState ) :
     847             :                 mxFont( rState.xFont ),
     848             :                 maStringContext( rText, nStartPos, nLen ),
     849             :                 mpCanvas( rCanvas ),
     850             :                 maState(),
     851             :                 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
     852             :                 maLinesOverallSize(),
     853           0 :                 mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ),
     854             :                 mxTextLines(),
     855             :                 maReliefOffset( rReliefOffset ),
     856             :                 maReliefColor( rReliefColor ),
     857             :                 maShadowOffset( rShadowOffset ),
     858             :                 maShadowColor( rShadowColor ),
     859           0 :                 maTextDirection( rState.textDirection )
     860             :             {
     861             :                 initEffectLinePolyPolygon( maLinesOverallSize,
     862             :                                            mxTextLines,
     863             :                                            rCanvas,
     864             :                                            mnLineWidth,
     865           0 :                                            maTextLineInfo );
     866             : 
     867             :                 init( maState, mxFont,
     868             :                       rStartPoint,
     869           0 :                       rState, rCanvas );
     870             : 
     871           0 :                 ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(),
     872             :                                   "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
     873           0 :             }
     874             : 
     875           0 :             EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint&      rStartPoint,
     876             :                                                 const ::basegfx::B2DSize&       rReliefOffset,
     877             :                                                 const ::Color&                  rReliefColor,
     878             :                                                 const ::basegfx::B2DSize&       rShadowOffset,
     879             :                                                 const ::Color&                  rShadowColor,
     880             :                                                 const OUString&          rText,
     881             :                                                 sal_Int32                       nStartPos,
     882             :                                                 sal_Int32                       nLen,
     883             :                                                 VirtualDevice&                  rVDev,
     884             :                                                 const CanvasSharedPtr&          rCanvas,
     885             :                                                 const OutDevState&              rState,
     886             :                                                 const ::basegfx::B2DHomMatrix&  rTextTransform ) :
     887             :                 mxFont( rState.xFont ),
     888             :                 maStringContext( rText, nStartPos, nLen ),
     889             :                 mpCanvas( rCanvas ),
     890             :                 maState(),
     891             :                 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
     892             :                 maLinesOverallSize(),
     893           0 :                 mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ),
     894             :                 mxTextLines(),
     895             :                 maReliefOffset( rReliefOffset ),
     896             :                 maReliefColor( rReliefColor ),
     897             :                 maShadowOffset( rShadowOffset ),
     898             :                 maShadowColor( rShadowColor ),
     899           0 :                 maTextDirection( rState.textDirection )
     900             :             {
     901             :                 initEffectLinePolyPolygon( maLinesOverallSize,
     902             :                                            mxTextLines,
     903             :                                            rCanvas,
     904             :                                            mnLineWidth,
     905           0 :                                            maTextLineInfo );
     906             : 
     907             :                 init( maState, mxFont,
     908             :                       rStartPoint,
     909           0 :                       rState, rCanvas, rTextTransform );
     910             : 
     911           0 :                 ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(),
     912             :                                   "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
     913           0 :             }
     914             : 
     915           0 :             bool EffectTextAction::operator()( const rendering::RenderState& rRenderState ) const
     916             :             {
     917           0 :                 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
     918           0 :                 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
     919             : 
     920           0 :                 rCanvas->fillPolyPolygon( mxTextLines,
     921             :                                           rViewState,
     922           0 :                                           rRenderState );
     923             : 
     924           0 :                 rCanvas->drawText( maStringContext, mxFont,
     925             :                                    rViewState,
     926             :                                    rRenderState,
     927           0 :                                    maTextDirection );
     928             : 
     929           0 :                 return true;
     930             :             }
     931             : 
     932           0 :             bool EffectTextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
     933             :             {
     934             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextAction::render()" );
     935             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextAction: 0x" << std::hex << this );
     936             : 
     937           0 :                 rendering::RenderState aLocalState( maState );
     938           0 :                 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
     939             : 
     940             :                 return renderEffectText( *this,
     941             :                                          aLocalState,
     942           0 :                                          mpCanvas->getViewState(),
     943           0 :                                          mpCanvas->getUNOCanvas(),
     944             :                                          maShadowColor,
     945             :                                          maShadowOffset,
     946             :                                          maReliefColor,
     947           0 :                                          maReliefOffset );
     948             :             }
     949             : 
     950           0 :             bool EffectTextAction::renderSubset( const ::basegfx::B2DHomMatrix&   rTransformation,
     951             :                                                  const Subset&                    /*rSubset*/ ) const
     952             :             {
     953             :                 SAL_WARN( "cppcanvas.emf", "EffectTextAction::renderSubset(): Subset not supported by this object" );
     954             : 
     955             :                 // TODO(P1): Retrieve necessary font metric info for
     956             :                 // TextAction from XCanvas. Currently, the
     957             :                 // TextActionFactory does not generate this object for
     958             :                 // subsettable text
     959           0 :                 return render( rTransformation );
     960             :             }
     961             : 
     962           0 :             ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
     963             :             {
     964             :                 // create XTextLayout, to have the
     965             :                 // XTextLayout::queryTextBounds() method available
     966             :                 uno::Reference< rendering::XTextLayout > xTextLayout(
     967           0 :                     mxFont->createTextLayout(
     968             :                         maStringContext,
     969             :                         maTextDirection,
     970           0 :                         0 ) );
     971             : 
     972           0 :                 rendering::RenderState aLocalState( maState );
     973           0 :                 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
     974             : 
     975             :                 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
     976           0 :                                                  xTextLayout->queryTextBounds() ),
     977             :                                              ::basegfx::B2DRange( 0,0,
     978             :                                                                   maLinesOverallSize.getX(),
     979             :                                                                   maLinesOverallSize.getY() ),
     980             :                                              maReliefOffset,
     981             :                                              maShadowOffset,
     982             :                                              aLocalState,
     983           0 :                                              mpCanvas->getViewState() );
     984             :             }
     985             : 
     986           0 :             ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
     987             :                                                              const Subset&                  /*rSubset*/ ) const
     988             :             {
     989             :                 SAL_WARN( "cppcanvas.emf", "EffectTextAction::getBounds(): Subset not supported by this object" );
     990             : 
     991             :                 // TODO(P1): Retrieve necessary font metric info for
     992             :                 // TextAction from XCanvas. Currently, the
     993             :                 // TextActionFactory does not generate this object for
     994             :                 // _subsettable_ text
     995           0 :                 return getBounds( rTransformation );
     996             :             }
     997             : 
     998           0 :             sal_Int32 EffectTextAction::getActionCount() const
     999             :             {
    1000             :                 // TODO(P1): Retrieve necessary font metric info for
    1001             :                 // TextAction from XCanvas. Currently, the
    1002             :                 // TextActionFactory does not generate this object for
    1003             :                 // subsettable text
    1004           0 :                 return 1;
    1005             :             }
    1006             : 
    1007             : 
    1008             : 
    1009             : 
    1010           0 :             class TextArrayAction : public Action, private ::boost::noncopyable
    1011             :             {
    1012             :             public:
    1013             :                 TextArrayAction( const ::basegfx::B2DPoint&     rStartPoint,
    1014             :                                  const OUString&         rString,
    1015             :                                  sal_Int32                      nStartPos,
    1016             :                                  sal_Int32                      nLen,
    1017             :                                  const uno::Sequence< double >& rOffsets,
    1018             :                                  const CanvasSharedPtr&         rCanvas,
    1019             :                                  const OutDevState&             rState );
    1020             : 
    1021             :                 TextArrayAction( const ::basegfx::B2DPoint&     rStartPoint,
    1022             :                                  const OUString&         rString,
    1023             :                                  sal_Int32                      nStartPos,
    1024             :                                  sal_Int32                      nLen,
    1025             :                                  const uno::Sequence< double >& rOffsets,
    1026             :                                  const CanvasSharedPtr&         rCanvas,
    1027             :                                  const OutDevState&             rState,
    1028             :                                  const ::basegfx::B2DHomMatrix& rTextTransform );
    1029             : 
    1030             :                 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
    1031             :                 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
    1032             :                                            const Subset&                  rSubset ) const SAL_OVERRIDE;
    1033             : 
    1034             :                 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
    1035             :                 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix&   rTransformation,
    1036             :                                                        const Subset&                    rSubset ) const SAL_OVERRIDE;
    1037             : 
    1038             :                 virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
    1039             : 
    1040             :             private:
    1041             :                 // TODO(P2): This is potentially a real mass object
    1042             :                 // (every character might be a separate TextAction),
    1043             :                 // thus, make it as lightweight as possible. For
    1044             :                 // example, share common RenderState among several
    1045             :                 // TextActions, maybe using maOffsets for the
    1046             :                 // translation.
    1047             : 
    1048             :                 uno::Reference< rendering::XTextLayout >    mxTextLayout;
    1049             :                 const CanvasSharedPtr                       mpCanvas;
    1050             :                 rendering::RenderState                      maState;
    1051             :             };
    1052             : 
    1053           0 :             TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint&        rStartPoint,
    1054             :                                               const OUString&            rString,
    1055             :                                               sal_Int32                         nStartPos,
    1056             :                                               sal_Int32                         nLen,
    1057             :                                               const uno::Sequence< double >&    rOffsets,
    1058             :                                               const CanvasSharedPtr&            rCanvas,
    1059             :                                               const OutDevState&                rState ) :
    1060             :                 mxTextLayout(),
    1061             :                 mpCanvas( rCanvas ),
    1062           0 :                 maState()
    1063             :             {
    1064             :                 initArrayAction( maState,
    1065             :                                  mxTextLayout,
    1066             :                                  rStartPoint,
    1067             :                                  rString,
    1068             :                                  nStartPos,
    1069             :                                  nLen,
    1070             :                                  rOffsets,
    1071             :                                  rCanvas,
    1072           0 :                                  rState, NULL );
    1073           0 :             }
    1074             : 
    1075           0 :             TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint&        rStartPoint,
    1076             :                                               const OUString&            rString,
    1077             :                                               sal_Int32                         nStartPos,
    1078             :                                               sal_Int32                         nLen,
    1079             :                                               const uno::Sequence< double >&    rOffsets,
    1080             :                                               const CanvasSharedPtr&            rCanvas,
    1081             :                                               const OutDevState&                rState,
    1082             :                                               const ::basegfx::B2DHomMatrix&    rTextTransform ) :
    1083             :                 mxTextLayout(),
    1084             :                 mpCanvas( rCanvas ),
    1085           0 :                 maState()
    1086             :             {
    1087             :                 initArrayAction( maState,
    1088             :                                  mxTextLayout,
    1089             :                                  rStartPoint,
    1090             :                                  rString,
    1091             :                                  nStartPos,
    1092             :                                  nLen,
    1093             :                                  rOffsets,
    1094             :                                  rCanvas,
    1095             :                                  rState,
    1096           0 :                                  &rTextTransform );
    1097           0 :             }
    1098             : 
    1099           0 :             bool TextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
    1100             :             {
    1101             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::render()" );
    1102             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex << this );
    1103             : 
    1104           0 :                 rendering::RenderState aLocalState( maState );
    1105           0 :                 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
    1106             : 
    1107           0 :                 mpCanvas->getUNOCanvas()->drawTextLayout( mxTextLayout,
    1108           0 :                                                           mpCanvas->getViewState(),
    1109           0 :                                                           aLocalState );
    1110             : 
    1111           0 :                 return true;
    1112             :             }
    1113             : 
    1114           0 :             bool TextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix&    rTransformation,
    1115             :                                                 const Subset&                     rSubset ) const
    1116             :             {
    1117             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::renderSubset()" );
    1118             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex << this );
    1119             : 
    1120           0 :                 rendering::RenderState                      aLocalState( maState );
    1121           0 :                 uno::Reference< rendering::XTextLayout >    xTextLayout( mxTextLayout );
    1122             : 
    1123             :                 double nDummy0, nDummy1;
    1124             :                 createSubsetLayout( xTextLayout,
    1125             :                                     aLocalState,
    1126             :                                     nDummy0,
    1127             :                                     nDummy1,
    1128             :                                     rTransformation,
    1129           0 :                                     rSubset );
    1130             : 
    1131           0 :                 if( !xTextLayout.is() )
    1132           0 :                     return true; // empty layout, render nothing
    1133             : 
    1134           0 :                 mpCanvas->getUNOCanvas()->drawTextLayout( xTextLayout,
    1135           0 :                                                           mpCanvas->getViewState(),
    1136           0 :                                                           aLocalState );
    1137             : 
    1138           0 :                 return true;
    1139             :             }
    1140             : 
    1141           0 :             ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
    1142             :             {
    1143           0 :                 rendering::RenderState aLocalState( maState );
    1144           0 :                 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
    1145             : 
    1146             :                 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
    1147           0 :                                                          mxTextLayout->queryTextBounds() ),
    1148           0 :                                                      mpCanvas->getViewState(),
    1149           0 :                                                      aLocalState );
    1150             :             }
    1151             : 
    1152           0 :             ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix&  rTransformation,
    1153             :                                                             const Subset&                   rSubset ) const
    1154             :             {
    1155             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::getBounds( subset )" );
    1156             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex << this );
    1157             : 
    1158           0 :                 rendering::RenderState                      aLocalState( maState );
    1159           0 :                 uno::Reference< rendering::XTextLayout >    xTextLayout( mxTextLayout );
    1160             : 
    1161             :                 double nDummy0, nDummy1;
    1162             :                 createSubsetLayout( xTextLayout,
    1163             :                                     aLocalState,
    1164             :                                     nDummy0,
    1165             :                                     nDummy1,
    1166             :                                     rTransformation,
    1167           0 :                                     rSubset );
    1168             : 
    1169           0 :                 if( !xTextLayout.is() )
    1170           0 :                     return ::basegfx::B2DRange(); // empty layout, empty bounds
    1171             : 
    1172             :                 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
    1173           0 :                                                          xTextLayout->queryTextBounds() ),
    1174           0 :                                                      mpCanvas->getViewState(),
    1175           0 :                                                      aLocalState );
    1176             :             }
    1177             : 
    1178           0 :             sal_Int32 TextArrayAction::getActionCount() const
    1179             :             {
    1180           0 :                 const rendering::StringContext& rOrigContext( mxTextLayout->getText() );
    1181             : 
    1182           0 :                 return rOrigContext.Length;
    1183             :             }
    1184             : 
    1185             : 
    1186             : 
    1187             : 
    1188           0 :             class EffectTextArrayAction :
    1189             :                 public Action,
    1190             :                 public TextRenderer,
    1191             :                 private ::boost::noncopyable
    1192             :             {
    1193             :             public:
    1194             :                 EffectTextArrayAction( const ::basegfx::B2DPoint&       rStartPoint,
    1195             :                                        const ::basegfx::B2DSize&        rReliefOffset,
    1196             :                                        const ::Color&                   rReliefColor,
    1197             :                                        const ::basegfx::B2DSize&        rShadowOffset,
    1198             :                                        const ::Color&                   rShadowColor,
    1199             :                                        const OUString&           rText,
    1200             :                                        sal_Int32                        nStartPos,
    1201             :                                        sal_Int32                        nLen,
    1202             :                                        const uno::Sequence< double >&   rOffsets,
    1203             :                                        VirtualDevice&                   rVDev,
    1204             :                                        const CanvasSharedPtr&           rCanvas,
    1205             :                                        const OutDevState&               rState  );
    1206             :                 EffectTextArrayAction( const ::basegfx::B2DPoint&       rStartPoint,
    1207             :                                        const ::basegfx::B2DSize&        rReliefOffset,
    1208             :                                        const ::Color&                   rReliefColor,
    1209             :                                        const ::basegfx::B2DSize&        rShadowOffset,
    1210             :                                        const ::Color&                   rShadowColor,
    1211             :                                        const OUString&           rText,
    1212             :                                        sal_Int32                        nStartPos,
    1213             :                                        sal_Int32                        nLen,
    1214             :                                        const uno::Sequence< double >&   rOffsets,
    1215             :                                        VirtualDevice&                   rVDev,
    1216             :                                        const CanvasSharedPtr&           rCanvas,
    1217             :                                        const OutDevState&               rState,
    1218             :                                        const ::basegfx::B2DHomMatrix&   rTextTransform );
    1219             : 
    1220             :                 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
    1221             :                 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
    1222             :                                            const Subset&                  rSubset ) const SAL_OVERRIDE;
    1223             : 
    1224             :                 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
    1225             :                 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix&   rTransformation,
    1226             :                                                        const Subset&                    rSubset ) const SAL_OVERRIDE;
    1227             : 
    1228             :                 virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
    1229             : 
    1230             :             private:
    1231             :                 // TextRenderer interface
    1232             :                 virtual bool operator()( const rendering::RenderState& rRenderState ) const SAL_OVERRIDE;
    1233             : 
    1234             :                 // TODO(P2): This is potentially a real mass object
    1235             :                 // (every character might be a separate TextAction),
    1236             :                 // thus, make it as lightweight as possible. For
    1237             :                 // example, share common RenderState among several
    1238             :                 // TextActions, maybe using maOffsets for the
    1239             :                 // translation.
    1240             : 
    1241             :                 uno::Reference< rendering::XTextLayout >        mxTextLayout;
    1242             :                 const CanvasSharedPtr                           mpCanvas;
    1243             :                 rendering::RenderState                          maState;
    1244             :                 const tools::TextLineInfo                       maTextLineInfo;
    1245             :                 ::basegfx::B2DSize                              maLinesOverallSize;
    1246             :                 uno::Reference< rendering::XPolyPolygon2D >     mxTextLines;
    1247             :                 const ::basegfx::B2DSize                        maReliefOffset;
    1248             :                 const ::Color                                   maReliefColor;
    1249             :                 const ::basegfx::B2DSize                        maShadowOffset;
    1250             :                 const ::Color                                   maShadowColor;
    1251             :             };
    1252             : 
    1253           0 :             EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint&        rStartPoint,
    1254             :                                                           const ::basegfx::B2DSize&         rReliefOffset,
    1255             :                                                           const ::Color&                    rReliefColor,
    1256             :                                                           const ::basegfx::B2DSize&         rShadowOffset,
    1257             :                                                           const ::Color&                    rShadowColor,
    1258             :                                                           const OUString&            rText,
    1259             :                                                           sal_Int32                         nStartPos,
    1260             :                                                           sal_Int32                         nLen,
    1261             :                                                           const uno::Sequence< double >&    rOffsets,
    1262             :                                                           VirtualDevice&                    rVDev,
    1263             :                                                           const CanvasSharedPtr&            rCanvas,
    1264             :                                                           const OutDevState&                rState  ) :
    1265             :                 mxTextLayout(),
    1266             :                 mpCanvas( rCanvas ),
    1267             :                 maState(),
    1268             :                 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
    1269             :                 maLinesOverallSize(),
    1270             :                 mxTextLines(),
    1271             :                 maReliefOffset( rReliefOffset ),
    1272             :                 maReliefColor( rReliefColor ),
    1273             :                 maShadowOffset( rShadowOffset ),
    1274           0 :                 maShadowColor( rShadowColor )
    1275             :             {
    1276             :                 initEffectLinePolyPolygon( maLinesOverallSize,
    1277             :                                            mxTextLines,
    1278             :                                            rCanvas,
    1279             :                                            rOffsets,
    1280           0 :                                            maTextLineInfo );
    1281             : 
    1282             :                 initArrayAction( maState,
    1283             :                                  mxTextLayout,
    1284             :                                  rStartPoint,
    1285             :                                  rText,
    1286             :                                  nStartPos,
    1287             :                                  nLen,
    1288             :                                  rOffsets,
    1289             :                                  rCanvas,
    1290           0 :                                  rState, NULL );
    1291           0 :             }
    1292             : 
    1293           0 :             EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint&        rStartPoint,
    1294             :                                                           const ::basegfx::B2DSize&         rReliefOffset,
    1295             :                                                           const ::Color&                    rReliefColor,
    1296             :                                                           const ::basegfx::B2DSize&         rShadowOffset,
    1297             :                                                           const ::Color&                    rShadowColor,
    1298             :                                                           const OUString&            rText,
    1299             :                                                           sal_Int32                         nStartPos,
    1300             :                                                           sal_Int32                         nLen,
    1301             :                                                           const uno::Sequence< double >&    rOffsets,
    1302             :                                                           VirtualDevice&                    rVDev,
    1303             :                                                           const CanvasSharedPtr&            rCanvas,
    1304             :                                                           const OutDevState&                rState,
    1305             :                                                           const ::basegfx::B2DHomMatrix&    rTextTransform ) :
    1306             :                 mxTextLayout(),
    1307             :                 mpCanvas( rCanvas ),
    1308             :                 maState(),
    1309             :                 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
    1310             :                 maLinesOverallSize(),
    1311             :                 mxTextLines(),
    1312             :                 maReliefOffset( rReliefOffset ),
    1313             :                 maReliefColor( rReliefColor ),
    1314             :                 maShadowOffset( rShadowOffset ),
    1315           0 :                 maShadowColor( rShadowColor )
    1316             :             {
    1317             :                 initEffectLinePolyPolygon( maLinesOverallSize,
    1318             :                                            mxTextLines,
    1319             :                                            rCanvas,
    1320             :                                            rOffsets,
    1321           0 :                                            maTextLineInfo );
    1322             : 
    1323             :                 initArrayAction( maState,
    1324             :                                  mxTextLayout,
    1325             :                                  rStartPoint,
    1326             :                                  rText,
    1327             :                                  nStartPos,
    1328             :                                  nLen,
    1329             :                                  rOffsets,
    1330             :                                  rCanvas,
    1331             :                                  rState,
    1332           0 :                                  &rTextTransform );
    1333           0 :             }
    1334             : 
    1335           0 :             bool EffectTextArrayAction::operator()( const rendering::RenderState& rRenderState ) const
    1336             :             {
    1337           0 :                 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
    1338           0 :                 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
    1339             : 
    1340           0 :                 rCanvas->fillPolyPolygon( mxTextLines,
    1341             :                                           rViewState,
    1342           0 :                                           rRenderState );
    1343             : 
    1344           0 :                 rCanvas->drawTextLayout( mxTextLayout,
    1345             :                                          rViewState,
    1346           0 :                                          rRenderState );
    1347             : 
    1348           0 :                 return true;
    1349             :             }
    1350             : 
    1351           0 :             bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
    1352             :             {
    1353             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::render()" );
    1354             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex << this );
    1355             : 
    1356           0 :                 rendering::RenderState aLocalState( maState );
    1357           0 :                 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
    1358             : 
    1359             :                 return renderEffectText( *this,
    1360             :                                          aLocalState,
    1361           0 :                                          mpCanvas->getViewState(),
    1362           0 :                                          mpCanvas->getUNOCanvas(),
    1363             :                                          maShadowColor,
    1364             :                                          maShadowOffset,
    1365             :                                          maReliefColor,
    1366           0 :                                          maReliefOffset );
    1367             :             }
    1368             : 
    1369           0 :             class EffectTextArrayRenderHelper : public TextRenderer
    1370             :             {
    1371             :             public:
    1372           0 :                 EffectTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >&        rCanvas,
    1373             :                                              const uno::Reference< rendering::XTextLayout >&    rTextLayout,
    1374             :                                              const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon,
    1375             :                                              const rendering::ViewState&                        rViewState ) :
    1376             :                     mrCanvas( rCanvas ),
    1377             :                     mrTextLayout( rTextLayout ),
    1378             :                     mrLinePolygon( rLinePolygon ),
    1379           0 :                     mrViewState( rViewState )
    1380             :                 {
    1381           0 :                 }
    1382             : 
    1383             :                 // TextRenderer interface
    1384           0 :                 virtual bool operator()( const rendering::RenderState& rRenderState ) const SAL_OVERRIDE
    1385             :                 {
    1386           0 :                     mrCanvas->fillPolyPolygon( mrLinePolygon,
    1387             :                                                mrViewState,
    1388           0 :                                                rRenderState );
    1389             : 
    1390           0 :                     mrCanvas->drawTextLayout( mrTextLayout,
    1391             :                                               mrViewState,
    1392           0 :                                               rRenderState );
    1393             : 
    1394           0 :                     return true;
    1395             :                 }
    1396             : 
    1397             :             private:
    1398             :                 const uno::Reference< rendering::XCanvas >&         mrCanvas;
    1399             :                 const uno::Reference< rendering::XTextLayout >&     mrTextLayout;
    1400             :                 const uno::Reference< rendering::XPolyPolygon2D >&  mrLinePolygon;
    1401             :                 const rendering::ViewState&                         mrViewState;
    1402             :             };
    1403             : 
    1404           0 :             bool EffectTextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix&  rTransformation,
    1405             :                                                       const Subset&                   rSubset ) const
    1406             :             {
    1407             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::renderSubset()" );
    1408             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex << this );
    1409             : 
    1410           0 :                 rendering::RenderState                   aLocalState( maState );
    1411           0 :                 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
    1412           0 :                 const geometry::RealRectangle2D          aTextBounds( mxTextLayout->queryTextBounds() );
    1413             : 
    1414           0 :                 double nMinPos(0.0);
    1415           0 :                 double nMaxPos(aTextBounds.X2 - aTextBounds.X1);
    1416             : 
    1417             :                 createSubsetLayout( xTextLayout,
    1418             :                                     aLocalState,
    1419             :                                     nMinPos,
    1420             :                                     nMaxPos,
    1421             :                                     rTransformation,
    1422           0 :                                     rSubset );
    1423             : 
    1424           0 :                 if( !xTextLayout.is() )
    1425           0 :                     return true; // empty layout, render nothing
    1426             : 
    1427             : 
    1428             :                 // create and setup local line polygon
    1429             :                 // ===================================
    1430             : 
    1431           0 :                 uno::Reference< rendering::XCanvas > xCanvas( mpCanvas->getUNOCanvas() );
    1432           0 :                 const rendering::ViewState&          rViewState( mpCanvas->getViewState() );
    1433             : 
    1434             :                 uno::Reference< rendering::XPolyPolygon2D > xTextLines(
    1435             :                     ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
    1436           0 :                         xCanvas->getDevice(),
    1437             :                         tools::createTextLinesPolyPolygon(
    1438           0 :                             0.0, nMaxPos - nMinPos,
    1439           0 :                             maTextLineInfo ) ) );
    1440             : 
    1441             : 
    1442             :                 // render everything
    1443             :                 // =================
    1444             : 
    1445             :                 return renderEffectText(
    1446             :                     EffectTextArrayRenderHelper( xCanvas,
    1447             :                                                  xTextLayout,
    1448             :                                                  xTextLines,
    1449             :                                                  rViewState ),
    1450             :                     aLocalState,
    1451             :                     rViewState,
    1452             :                     xCanvas,
    1453             :                     maShadowColor,
    1454             :                     maShadowOffset,
    1455             :                     maReliefColor,
    1456           0 :                     maReliefOffset );
    1457             :             }
    1458             : 
    1459           0 :             ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
    1460             :             {
    1461           0 :                 rendering::RenderState aLocalState( maState );
    1462           0 :                 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
    1463             : 
    1464             :                 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
    1465           0 :                                                  mxTextLayout->queryTextBounds() ),
    1466             :                                              ::basegfx::B2DRange( 0,0,
    1467             :                                                                   maLinesOverallSize.getX(),
    1468             :                                                                   maLinesOverallSize.getY() ),
    1469             :                                              maReliefOffset,
    1470             :                                              maShadowOffset,
    1471             :                                              aLocalState,
    1472           0 :                                              mpCanvas->getViewState() );
    1473             :             }
    1474             : 
    1475           0 :             ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix&    rTransformation,
    1476             :                                                                   const Subset&                     rSubset ) const
    1477             :             {
    1478             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::getBounds( subset )" );
    1479             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex << this );
    1480             : 
    1481           0 :                 rendering::RenderState                   aLocalState( maState );
    1482           0 :                 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
    1483           0 :                 const geometry::RealRectangle2D          aTextBounds( mxTextLayout->queryTextBounds() );
    1484             : 
    1485           0 :                 double nMinPos(0.0);
    1486           0 :                 double nMaxPos(aTextBounds.X2 - aTextBounds.X1);
    1487             : 
    1488             :                 createSubsetLayout( xTextLayout,
    1489             :                                     aLocalState,
    1490             :                                     nMinPos,
    1491             :                                     nMaxPos,
    1492             :                                     rTransformation,
    1493           0 :                                     rSubset );
    1494             : 
    1495           0 :                 if( !xTextLayout.is() )
    1496           0 :                     return ::basegfx::B2DRange(); // empty layout, empty bounds
    1497             : 
    1498             : 
    1499             :                 // create and setup local line polygon
    1500             :                 // ===================================
    1501             : 
    1502             :                 const ::basegfx::B2DPolyPolygon aPoly(
    1503             :                     tools::createTextLinesPolyPolygon(
    1504           0 :                         0.0, nMaxPos - nMinPos,
    1505           0 :                         maTextLineInfo ) );
    1506             : 
    1507             :                 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
    1508           0 :                                                  xTextLayout->queryTextBounds() ),
    1509             :                                              ::basegfx::tools::getRange( aPoly ),
    1510             :                                              maReliefOffset,
    1511             :                                              maShadowOffset,
    1512             :                                              aLocalState,
    1513           0 :                                              mpCanvas->getViewState() );
    1514             :             }
    1515             : 
    1516           0 :             sal_Int32 EffectTextArrayAction::getActionCount() const
    1517             :             {
    1518           0 :                 const rendering::StringContext& rOrigContext( mxTextLayout->getText() );
    1519             : 
    1520           0 :                 return rOrigContext.Length;
    1521             :             }
    1522             : 
    1523             : 
    1524             : 
    1525             : 
    1526           0 :             class OutlineAction :
    1527             :                 public Action,
    1528             :                 public TextRenderer,
    1529             :                 private ::boost::noncopyable
    1530             :             {
    1531             :             public:
    1532             :                 OutlineAction( const ::basegfx::B2DPoint&                           rStartPoint,
    1533             :                                const ::basegfx::B2DSize&                            rReliefOffset,
    1534             :                                const ::Color&                                       rReliefColor,
    1535             :                                const ::basegfx::B2DSize&                            rShadowOffset,
    1536             :                                const ::Color&                                       rShadowColor,
    1537             :                                const ::basegfx::B2DRectangle&                       rOutlineBounds,
    1538             :                                const uno::Reference< rendering::XPolyPolygon2D >&   rTextPoly,
    1539             :                                const ::std::vector< sal_Int32 >&                    rPolygonGlyphMap,
    1540             :                                const uno::Sequence< double >&                       rOffsets,
    1541             :                                VirtualDevice&                                       rVDev,
    1542             :                                const CanvasSharedPtr&                               rCanvas,
    1543             :                                const OutDevState&                                   rState  );
    1544             :                 OutlineAction( const ::basegfx::B2DPoint&                           rStartPoint,
    1545             :                                const ::basegfx::B2DSize&                            rReliefOffset,
    1546             :                                const ::Color&                                       rReliefColor,
    1547             :                                const ::basegfx::B2DSize&                            rShadowOffset,
    1548             :                                const ::Color&                                       rShadowColor,
    1549             :                                const ::basegfx::B2DRectangle&                       rOutlineBounds,
    1550             :                                const uno::Reference< rendering::XPolyPolygon2D >&   rTextPoly,
    1551             :                                const ::std::vector< sal_Int32 >&                    rPolygonGlyphMap,
    1552             :                                const uno::Sequence< double >&                       rOffsets,
    1553             :                                VirtualDevice&                                       rVDev,
    1554             :                                const CanvasSharedPtr&                               rCanvas,
    1555             :                                const OutDevState&                                   rState,
    1556             :                                const ::basegfx::B2DHomMatrix&                       rTextTransform );
    1557             : 
    1558             :                 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
    1559             :                 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
    1560             :                                            const Subset&                  rSubset ) const SAL_OVERRIDE;
    1561             : 
    1562             :                 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
    1563             :                 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix&   rTransformation,
    1564             :                                                        const Subset&                    rSubset ) const SAL_OVERRIDE;
    1565             : 
    1566             :                 virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
    1567             : 
    1568             :             private:
    1569             :                 // TextRenderer interface
    1570             :                 virtual bool operator()( const rendering::RenderState& rRenderState ) const SAL_OVERRIDE;
    1571             : 
    1572             :                 // TODO(P2): This is potentially a real mass object
    1573             :                 // (every character might be a separate TextAction),
    1574             :                 // thus, make it as lightweight as possible. For
    1575             :                 // example, share common RenderState among several
    1576             :                 // TextActions, maybe using maOffsets for the
    1577             :                 // translation.
    1578             : 
    1579             :                 uno::Reference< rendering::XPolyPolygon2D >         mxTextPoly;
    1580             : 
    1581             :                 /** This vector denotes the index of the start polygon
    1582             :                     for the respective glyph sequence.
    1583             : 
    1584             :                     To get a polygon index range for a given character
    1585             :                     index i, take [ maPolygonGlyphMap[i],
    1586             :                     maPolygonGlyphMap[i+1] ). Note that this is wrong
    1587             :                     for BiDi
    1588             :                  */
    1589             :                 const ::std::vector< sal_Int32 >                    maPolygonGlyphMap;
    1590             :                 const uno::Sequence< double >                       maOffsets;
    1591             :                 const CanvasSharedPtr                               mpCanvas;
    1592             :                 rendering::RenderState                              maState;
    1593             :                 double                                              mnOutlineWidth;
    1594             :                 const uno::Sequence< double >                       maFillColor;
    1595             :                 const tools::TextLineInfo                           maTextLineInfo;
    1596             :                 ::basegfx::B2DSize                                  maLinesOverallSize;
    1597             :                 const ::basegfx::B2DRectangle                       maOutlineBounds;
    1598             :                 uno::Reference< rendering::XPolyPolygon2D >         mxTextLines;
    1599             :                 const ::basegfx::B2DSize                            maReliefOffset;
    1600             :                 const ::Color                                       maReliefColor;
    1601             :                 const ::basegfx::B2DSize                            maShadowOffset;
    1602             :                 const ::Color                                       maShadowColor;
    1603             :             };
    1604             : 
    1605           0 :             double calcOutlineWidth( const OutDevState& rState,
    1606             :                                      VirtualDevice&     rVDev )
    1607             :             {
    1608             :                 const ::basegfx::B2DSize aFontSize( 0,
    1609           0 :                                                     rVDev.GetFont().GetHeight() / 64.0 );
    1610             : 
    1611             :                 const double nOutlineWidth(
    1612           0 :                     (rState.mapModeTransform * aFontSize).getY() );
    1613             : 
    1614           0 :                 return nOutlineWidth < 1.0 ? 1.0 : nOutlineWidth;
    1615             :             }
    1616             : 
    1617           0 :             OutlineAction::OutlineAction( const ::basegfx::B2DPoint&                            rStartPoint,
    1618             :                                           const ::basegfx::B2DSize&                             rReliefOffset,
    1619             :                                           const ::Color&                                        rReliefColor,
    1620             :                                           const ::basegfx::B2DSize&                             rShadowOffset,
    1621             :                                           const ::Color&                                        rShadowColor,
    1622             :                                           const ::basegfx::B2DRectangle&                        rOutlineBounds,
    1623             :                                           const uno::Reference< rendering::XPolyPolygon2D >&    rTextPoly,
    1624             :                                           const ::std::vector< sal_Int32 >&                     rPolygonGlyphMap,
    1625             :                                           const uno::Sequence< double >&                        rOffsets,
    1626             :                                           VirtualDevice&                                        rVDev,
    1627             :                                           const CanvasSharedPtr&                                rCanvas,
    1628             :                                           const OutDevState&                                    rState  ) :
    1629             :                 mxTextPoly( rTextPoly ),
    1630             :                 maPolygonGlyphMap( rPolygonGlyphMap ),
    1631             :                 maOffsets( rOffsets ),
    1632             :                 mpCanvas( rCanvas ),
    1633             :                 maState(),
    1634           0 :                 mnOutlineWidth( calcOutlineWidth(rState,rVDev) ),
    1635             :                 maFillColor(
    1636             :                     ::vcl::unotools::colorToDoubleSequence(
    1637             :                         ::Color( COL_WHITE ),
    1638           0 :                         rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
    1639             :                 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
    1640             :                 maLinesOverallSize(),
    1641             :                 maOutlineBounds( rOutlineBounds ),
    1642             :                 mxTextLines(),
    1643             :                 maReliefOffset( rReliefOffset ),
    1644             :                 maReliefColor( rReliefColor ),
    1645             :                 maShadowOffset( rShadowOffset ),
    1646           0 :                 maShadowColor( rShadowColor )
    1647             :             {
    1648             :                 initEffectLinePolyPolygon( maLinesOverallSize,
    1649             :                                            mxTextLines,
    1650             :                                            rCanvas,
    1651             :                                            rOffsets,
    1652           0 :                                            maTextLineInfo );
    1653             : 
    1654             :                 init( maState,
    1655             :                       rStartPoint,
    1656             :                       rState,
    1657           0 :                       rCanvas );
    1658           0 :             }
    1659             : 
    1660           0 :             OutlineAction::OutlineAction( const ::basegfx::B2DPoint&                            rStartPoint,
    1661             :                                           const ::basegfx::B2DSize&                             rReliefOffset,
    1662             :                                           const ::Color&                                        rReliefColor,
    1663             :                                           const ::basegfx::B2DSize&                             rShadowOffset,
    1664             :                                           const ::Color&                                        rShadowColor,
    1665             :                                           const ::basegfx::B2DRectangle&                        rOutlineBounds,
    1666             :                                           const uno::Reference< rendering::XPolyPolygon2D >&    rTextPoly,
    1667             :                                           const ::std::vector< sal_Int32 >&                     rPolygonGlyphMap,
    1668             :                                           const uno::Sequence< double >&                        rOffsets,
    1669             :                                           VirtualDevice&                                        rVDev,
    1670             :                                           const CanvasSharedPtr&                                rCanvas,
    1671             :                                           const OutDevState&                                    rState,
    1672             :                                           const ::basegfx::B2DHomMatrix&                        rTextTransform ) :
    1673             :                 mxTextPoly( rTextPoly ),
    1674             :                 maPolygonGlyphMap( rPolygonGlyphMap ),
    1675             :                 maOffsets( rOffsets ),
    1676             :                 mpCanvas( rCanvas ),
    1677             :                 maState(),
    1678           0 :                 mnOutlineWidth( calcOutlineWidth(rState,rVDev) ),
    1679             :                 maFillColor(
    1680             :                     ::vcl::unotools::colorToDoubleSequence(
    1681             :                         ::Color( COL_WHITE ),
    1682           0 :                         rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
    1683             :                 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
    1684             :                 maLinesOverallSize(),
    1685             :                 maOutlineBounds( rOutlineBounds ),
    1686             :                 mxTextLines(),
    1687             :                 maReliefOffset( rReliefOffset ),
    1688             :                 maReliefColor( rReliefColor ),
    1689             :                 maShadowOffset( rShadowOffset ),
    1690           0 :                 maShadowColor( rShadowColor )
    1691             :             {
    1692             :                 initEffectLinePolyPolygon( maLinesOverallSize,
    1693             :                                            mxTextLines,
    1694             :                                            rCanvas,
    1695             :                                            rOffsets,
    1696           0 :                                            maTextLineInfo );
    1697             : 
    1698             :                 init( maState,
    1699             :                       rStartPoint,
    1700             :                       rState,
    1701             :                       rCanvas,
    1702           0 :                       rTextTransform );
    1703           0 :             }
    1704             : 
    1705           0 :             bool OutlineAction::operator()( const rendering::RenderState& rRenderState ) const
    1706             :             {
    1707           0 :                 const rendering::ViewState&                 rViewState( mpCanvas->getViewState() );
    1708           0 :                 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
    1709             : 
    1710           0 :                 rendering::StrokeAttributes aStrokeAttributes;
    1711             : 
    1712           0 :                 aStrokeAttributes.StrokeWidth  = mnOutlineWidth;
    1713           0 :                 aStrokeAttributes.MiterLimit   = 1.0;
    1714           0 :                 aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
    1715           0 :                 aStrokeAttributes.EndCapType   = rendering::PathCapType::BUTT;
    1716           0 :                 aStrokeAttributes.JoinType     = rendering::PathJoinType::MITER;
    1717             : 
    1718           0 :                 rendering::RenderState aLocalState( rRenderState );
    1719           0 :                 aLocalState.DeviceColor = maFillColor;
    1720             : 
    1721             :                 // TODO(P1): implement caching
    1722             : 
    1723             :                 // background of text
    1724           0 :                 rCanvas->fillPolyPolygon( mxTextPoly,
    1725             :                                           rViewState,
    1726           0 :                                           aLocalState );
    1727             : 
    1728             :                 // border line of text
    1729           0 :                 rCanvas->strokePolyPolygon( mxTextPoly,
    1730             :                                             rViewState,
    1731             :                                             rRenderState,
    1732           0 :                                             aStrokeAttributes );
    1733             : 
    1734             :                 // underlines/strikethrough - background
    1735           0 :                 rCanvas->fillPolyPolygon( mxTextLines,
    1736             :                                           rViewState,
    1737           0 :                                           aLocalState );
    1738             :                 // underlines/strikethrough - border
    1739           0 :                 rCanvas->strokePolyPolygon( mxTextLines,
    1740             :                                             rViewState,
    1741             :                                             rRenderState,
    1742           0 :                                             aStrokeAttributes );
    1743             : 
    1744           0 :                 return true;
    1745             :             }
    1746             : 
    1747           0 :             bool OutlineAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
    1748             :             {
    1749             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::render()" );
    1750             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex << this );
    1751             : 
    1752           0 :                 rendering::RenderState aLocalState( maState );
    1753           0 :                 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
    1754             : 
    1755             :                 return renderEffectText( *this,
    1756             :                                          aLocalState,
    1757           0 :                                          mpCanvas->getViewState(),
    1758           0 :                                          mpCanvas->getUNOCanvas(),
    1759             :                                          maShadowColor,
    1760             :                                          maShadowOffset,
    1761             :                                          maReliefColor,
    1762           0 :                                          maReliefOffset );
    1763             :             }
    1764             : 
    1765             : #if 0 // see #if'ed out use in OutlineAction::renderSubset below:
    1766             :             class OutlineTextArrayRenderHelper : public TextRenderer
    1767             :             {
    1768             :             public:
    1769             :                 OutlineTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >&        rCanvas,
    1770             :                                               const uno::Reference< rendering::XPolyPolygon2D >& rTextPolygon,
    1771             :                                               const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon,
    1772             :                                               const rendering::ViewState&                        rViewState,
    1773             :                                               double                                             nOutlineWidth ) :
    1774             :                     maFillColor(
    1775             :                         ::vcl::unotools::colorToDoubleSequence(
    1776             :                             ::Color( COL_WHITE ),
    1777             :                             rCanvas->getDevice()->getDeviceColorSpace() )),
    1778             :                     mnOutlineWidth( nOutlineWidth ),
    1779             :                     mrCanvas( rCanvas ),
    1780             :                     mrTextPolygon( rTextPolygon ),
    1781             :                     mrLinePolygon( rLinePolygon ),
    1782             :                     mrViewState( rViewState )
    1783             :                 {
    1784             :                 }
    1785             : 
    1786             :                 // TextRenderer interface
    1787             :                 virtual bool operator()( const rendering::RenderState& rRenderState ) const
    1788             :                 {
    1789             :                     rendering::StrokeAttributes aStrokeAttributes;
    1790             : 
    1791             :                     aStrokeAttributes.StrokeWidth  = mnOutlineWidth;
    1792             :                     aStrokeAttributes.MiterLimit   = 1.0;
    1793             :                     aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
    1794             :                     aStrokeAttributes.EndCapType   = rendering::PathCapType::BUTT;
    1795             :                     aStrokeAttributes.JoinType     = rendering::PathJoinType::MITER;
    1796             : 
    1797             :                     rendering::RenderState aLocalState( rRenderState );
    1798             :                     aLocalState.DeviceColor = maFillColor;
    1799             : 
    1800             :                     // TODO(P1): implement caching
    1801             : 
    1802             :                     // background of text
    1803             :                     mrCanvas->fillPolyPolygon( mrTextPolygon,
    1804             :                                                mrViewState,
    1805             :                                                aLocalState );
    1806             : 
    1807             :                     // border line of text
    1808             :                     mrCanvas->strokePolyPolygon( mrTextPolygon,
    1809             :                                                  mrViewState,
    1810             :                                                  rRenderState,
    1811             :                                                  aStrokeAttributes );
    1812             : 
    1813             :                     // underlines/strikethrough - background
    1814             :                     mrCanvas->fillPolyPolygon( mrLinePolygon,
    1815             :                                                mrViewState,
    1816             :                                                aLocalState );
    1817             :                     // underlines/strikethrough - border
    1818             :                     mrCanvas->strokePolyPolygon( mrLinePolygon,
    1819             :                                                  mrViewState,
    1820             :                                                  rRenderState,
    1821             :                                                  aStrokeAttributes );
    1822             : 
    1823             :                     return true;
    1824             :                 }
    1825             : 
    1826             :             private:
    1827             :                 const uno::Sequence< double >                       maFillColor;
    1828             :                 double                                              mnOutlineWidth;
    1829             :                 const uno::Reference< rendering::XCanvas >&         mrCanvas;
    1830             :                 const uno::Reference< rendering::XPolyPolygon2D >&  mrTextPolygon;
    1831             :                 const uno::Reference< rendering::XPolyPolygon2D >&  mrLinePolygon;
    1832             :                 const rendering::ViewState&                         mrViewState;
    1833             :             };
    1834             : #endif
    1835             : 
    1836           0 :             bool OutlineAction::renderSubset( const ::basegfx::B2DHomMatrix&  rTransformation,
    1837             :                                               const Subset&                   rSubset ) const
    1838             :             {
    1839             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction::renderSubset()" );
    1840             :                 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction: 0x" << std::hex << this );
    1841             : 
    1842           0 :                 if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd )
    1843           0 :                     return true; // empty range, render nothing
    1844             : 
    1845             : #if 1
    1846             :                 // TODO(F3): Subsetting NYI for outline text!
    1847           0 :                 return render( rTransformation );
    1848             : #else
    1849             :                 const rendering::StringContext rOrigContext( mxTextLayout->getText() );
    1850             : 
    1851             :                 if( rSubset.mnSubsetBegin == 0 &&
    1852             :                     rSubset.mnSubsetEnd == rOrigContext.Length )
    1853             :                 {
    1854             :                     // full range, no need for subsetting
    1855             :                     return render( rTransformation );
    1856             :                 }
    1857             : 
    1858             :                 rendering::RenderState aLocalState( maState );
    1859             :                 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
    1860             : 
    1861             : 
    1862             :                 // create and setup local Text polygon
    1863             :                 // ===================================
    1864             : 
    1865             :                 uno::Reference< rendering::XPolyPolygon2D > xTextPolygon();
    1866             : 
    1867             :                 // TODO(P3): Provide an API method for that!
    1868             : 
    1869             :                 if( !xTextLayout.is() )
    1870             :                     return false;
    1871             : 
    1872             :                 // render everything
    1873             :                 // =================
    1874             : 
    1875             :                 return renderEffectText(
    1876             :                     OutlineTextArrayRenderHelper(
    1877             :                         xCanvas,
    1878             :                         mnOutlineWidth,
    1879             :                         xTextLayout,
    1880             :                         xTextLines,
    1881             :                         rViewState ),
    1882             :                     aLocalState,
    1883             :                     rViewState,
    1884             :                     xCanvas,
    1885             :                     maShadowColor,
    1886             :                     maShadowOffset,
    1887             :                     maReliefColor,
    1888             :                     maReliefOffset );
    1889             : #endif
    1890             :             }
    1891             : 
    1892           0 :             ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
    1893             :             {
    1894           0 :                 rendering::RenderState aLocalState( maState );
    1895           0 :                 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
    1896             : 
    1897             :                 return calcEffectTextBounds( maOutlineBounds,
    1898             :                                              ::basegfx::B2DRange( 0,0,
    1899             :                                                                   maLinesOverallSize.getX(),
    1900             :                                                                   maLinesOverallSize.getY() ),
    1901             :                                              maReliefOffset,
    1902             :                                              maShadowOffset,
    1903             :                                              aLocalState,
    1904           0 :                                              mpCanvas->getViewState() );
    1905             :             }
    1906             : 
    1907           0 :             ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix&    rTransformation,
    1908             :                                                           const Subset&                     /*rSubset*/ ) const
    1909             :             {
    1910             :                 SAL_WARN( "cppcanvas.emf", "OutlineAction::getBounds(): Subset not yet supported by this object" );
    1911             : 
    1912           0 :                 return getBounds( rTransformation );
    1913             :             }
    1914             : 
    1915           0 :             sal_Int32 OutlineAction::getActionCount() const
    1916             :             {
    1917             :                 // TODO(F3): Subsetting NYI for outline text!
    1918           0 :                 return maOffsets.getLength();
    1919             :             }
    1920             : 
    1921             : 
    1922             : 
    1923             : 
    1924             :             // Action factory methods
    1925             : 
    1926             : 
    1927             : 
    1928             :             /** Create an outline action
    1929             : 
    1930             :                 This method extracts the polygonal outline from the
    1931             :                 text, and creates a properly setup OutlineAction from
    1932             :                 it.
    1933             :              */
    1934           0 :             ActionSharedPtr createOutline( const ::basegfx::B2DPoint&       rStartPoint,
    1935             :                                            const ::basegfx::B2DSize&        rReliefOffset,
    1936             :                                            const ::Color&                   rReliefColor,
    1937             :                                            const ::basegfx::B2DSize&        rShadowOffset,
    1938             :                                            const ::Color&                   rShadowColor,
    1939             :                                            const OUString&                  rText,
    1940             :                                            sal_Int32                        nStartPos,
    1941             :                                            sal_Int32                        nLen,
    1942             :                                            const long*                      pDXArray,
    1943             :                                            VirtualDevice&                   rVDev,
    1944             :                                            const CanvasSharedPtr&           rCanvas,
    1945             :                                            const OutDevState&               rState,
    1946             :                                            const Renderer::Parameters&      rParms  )
    1947             :             {
    1948             :                 // operate on raw DX array here (in logical coordinate
    1949             :                 // system), to have a higher resolution
    1950             :                 // PolyPolygon. That polygon is then converted to
    1951             :                 // device coordinate system.
    1952             : 
    1953             :                 // #i68512# Temporarily switch off font rotation
    1954             :                 // (which is already contained in the render state
    1955             :                 // transformation matrix - otherwise, glyph polygons
    1956             :                 // will be rotated twice)
    1957           0 :                 const vcl::Font aOrigFont( rVDev.GetFont() );
    1958           0 :                 vcl::Font       aUnrotatedFont( aOrigFont );
    1959           0 :                 aUnrotatedFont.SetOrientation(0);
    1960           0 :                 rVDev.SetFont( aUnrotatedFont );
    1961             : 
    1962             :                 // TODO(F3): Don't understand parameter semantics of
    1963             :                 // GetTextOutlines()
    1964           0 :                 ::basegfx::B2DPolyPolygon aResultingPolyPolygon;
    1965           0 :                 PolyPolyVector aVCLPolyPolyVector;
    1966             :                 const bool bHaveOutlines( rVDev.GetTextOutlines( aVCLPolyPolyVector, rText,
    1967             :                                                                  static_cast<sal_uInt16>(nStartPos),
    1968             :                                                                  static_cast<sal_uInt16>(nStartPos),
    1969             :                                                                  static_cast<sal_uInt16>(nLen),
    1970           0 :                                                                  true, 0, pDXArray ) );
    1971           0 :                 rVDev.SetFont(aOrigFont);
    1972             : 
    1973           0 :                 if( !bHaveOutlines )
    1974           0 :                     return ActionSharedPtr();
    1975             : 
    1976           0 :                 ::std::vector< sal_Int32 > aPolygonGlyphMap;
    1977             : 
    1978             :                 // first glyph starts at polygon index 0
    1979           0 :                 aPolygonGlyphMap.push_back( 0 );
    1980             : 
    1981             :                 // remove offsetting from mapmode transformation
    1982             :                 // (outline polygons must stay at origin, only need to
    1983             :                 // be scaled)
    1984             :                 ::basegfx::B2DHomMatrix aMapModeTransform(
    1985           0 :                     rState.mapModeTransform );
    1986           0 :                 aMapModeTransform.set(0,2, 0.0);
    1987           0 :                 aMapModeTransform.set(1,2, 0.0);
    1988             : 
    1989           0 :                 PolyPolyVector::const_iterator       aIter( aVCLPolyPolyVector.begin() );
    1990           0 :                 const PolyPolyVector::const_iterator aEnd( aVCLPolyPolyVector.end() );
    1991           0 :                 for( ; aIter!= aEnd; ++aIter )
    1992             :                 {
    1993           0 :                     ::basegfx::B2DPolyPolygon aPolyPolygon;
    1994             : 
    1995           0 :                     aPolyPolygon = aIter->getB2DPolyPolygon();
    1996           0 :                     aPolyPolygon.transform( aMapModeTransform );
    1997             : 
    1998             :                     // append result to collecting polypoly
    1999           0 :                     for( sal_uInt32 i=0; i<aPolyPolygon.count(); ++i )
    2000             :                     {
    2001             :                         // #i47795# Ensure closed polygons (since
    2002             :                         // FreeType returns the glyph outlines
    2003             :                         // open)
    2004           0 :                         const ::basegfx::B2DPolygon& rPoly( aPolyPolygon.getB2DPolygon( i ) );
    2005           0 :                         const sal_uInt32 nCount( rPoly.count() );
    2006           0 :                         if( nCount<3 ||
    2007           0 :                             rPoly.isClosed() )
    2008             :                         {
    2009             :                             // polygon either degenerate, or
    2010             :                             // already closed.
    2011           0 :                             aResultingPolyPolygon.append( rPoly );
    2012             :                         }
    2013             :                         else
    2014             :                         {
    2015           0 :                             ::basegfx::B2DPolygon aPoly(rPoly);
    2016           0 :                             aPoly.setClosed(true);
    2017             : 
    2018           0 :                             aResultingPolyPolygon.append( aPoly );
    2019             :                         }
    2020           0 :                     }
    2021             : 
    2022             :                     // TODO(F3): Depending on the semantics of
    2023             :                     // GetTextOutlines(), this here is wrong!
    2024             : 
    2025             :                     // calc next glyph index
    2026           0 :                     aPolygonGlyphMap.push_back( aResultingPolyPolygon.count() );
    2027           0 :                 }
    2028             : 
    2029             :                 const uno::Sequence< double > aCharWidthSeq(
    2030             :                     pDXArray ?
    2031             :                     setupDXArray( pDXArray, nLen, rState ) :
    2032             :                     setupDXArray( rText,
    2033             :                                   nStartPos,
    2034             :                                   nLen,
    2035             :                                   rVDev,
    2036           0 :                                   rState ));
    2037             :                 const uno::Reference< rendering::XPolyPolygon2D > xTextPoly(
    2038             :                     ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
    2039           0 :                         rCanvas->getUNOCanvas()->getDevice(),
    2040           0 :                         aResultingPolyPolygon ) );
    2041             : 
    2042           0 :                 if( rParms.maTextTransformation.is_initialized() )
    2043             :                 {
    2044             :                     return ActionSharedPtr(
    2045             :                         new OutlineAction(
    2046             :                             rStartPoint,
    2047             :                             rReliefOffset,
    2048             :                             rReliefColor,
    2049             :                             rShadowOffset,
    2050             :                             rShadowColor,
    2051             :                             ::basegfx::tools::getRange(aResultingPolyPolygon),
    2052             :                             xTextPoly,
    2053             :                             aPolygonGlyphMap,
    2054             :                             aCharWidthSeq,
    2055             :                             rVDev,
    2056             :                             rCanvas,
    2057             :                             rState,
    2058           0 :                             *rParms.maTextTransformation ) );
    2059             :                 }
    2060             :                 else
    2061             :                 {
    2062             :                     return ActionSharedPtr(
    2063             :                         new OutlineAction(
    2064             :                             rStartPoint,
    2065             :                             rReliefOffset,
    2066             :                             rReliefColor,
    2067             :                             rShadowOffset,
    2068             :                             rShadowColor,
    2069             :                             ::basegfx::tools::getRange(aResultingPolyPolygon),
    2070             :                             xTextPoly,
    2071             :                             aPolygonGlyphMap,
    2072             :                             aCharWidthSeq,
    2073             :                             rVDev,
    2074             :                             rCanvas,
    2075           0 :                             rState  ) );
    2076           0 :                 }
    2077             :             }
    2078             : 
    2079             :         } // namespace
    2080             : 
    2081             : 
    2082             : 
    2083             : 
    2084           0 :         ActionSharedPtr TextActionFactory::createTextAction( const ::Point&                 rStartPoint,
    2085             :                                                              const ::Size&                  rReliefOffset,
    2086             :                                                              const ::Color&                 rReliefColor,
    2087             :                                                              const ::Size&                  rShadowOffset,
    2088             :                                                              const ::Color&                 rShadowColor,
    2089             :                                                              const OUString&                rText,
    2090             :                                                              sal_Int32                      nStartPos,
    2091             :                                                              sal_Int32                      nLen,
    2092             :                                                              const long*                    pDXArray,
    2093             :                                                              VirtualDevice&                 rVDev,
    2094             :                                                              const CanvasSharedPtr&         rCanvas,
    2095             :                                                              const OutDevState&             rState,
    2096             :                                                              const Renderer::Parameters&    rParms,
    2097             :                                                              bool                           bSubsettable    )
    2098             :         {
    2099             :             const ::Size  aBaselineOffset( tools::getBaselineOffset( rState,
    2100           0 :                                                                      rVDev ) );
    2101             :             // #143885# maintain (nearly) full precision positioning,
    2102             :             // by circumventing integer-based OutDev-mapping
    2103             :             const ::basegfx::B2DPoint aStartPoint(
    2104             :                 rState.mapModeTransform *
    2105           0 :                 ::basegfx::B2DPoint(rStartPoint.X() + aBaselineOffset.Width(),
    2106           0 :                                     rStartPoint.Y() + aBaselineOffset.Height()) );
    2107             : 
    2108             :             const ::basegfx::B2DSize aReliefOffset(
    2109           0 :                 rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rReliefOffset ) );
    2110             :             const ::basegfx::B2DSize aShadowOffset(
    2111           0 :                 rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rShadowOffset ) );
    2112             : 
    2113           0 :             if( rState.isTextOutlineModeSet )
    2114             :             {
    2115             :                 return createOutline(
    2116             :                             aStartPoint,
    2117             :                             aReliefOffset,
    2118             :                             rReliefColor,
    2119             :                             aShadowOffset,
    2120             :                             rShadowColor,
    2121             :                             rText,
    2122             :                             nStartPos,
    2123             :                             nLen,
    2124             :                             pDXArray,
    2125             :                             rVDev,
    2126             :                             rCanvas,
    2127             :                             rState,
    2128           0 :                             rParms );
    2129             :             }
    2130             : 
    2131             :             // convert DX array to device coordinate system (and
    2132             :             // create it in the first place, if pDXArray is NULL)
    2133             :             const uno::Sequence< double > aCharWidths(
    2134             :                 pDXArray ?
    2135             :                 setupDXArray( pDXArray, nLen, rState ) :
    2136             :                 setupDXArray( rText,
    2137             :                               nStartPos,
    2138             :                               nLen,
    2139             :                               rVDev,
    2140           0 :                               rState ));
    2141             : 
    2142             :             // determine type of text action to create
    2143             :             // =======================================
    2144             : 
    2145           0 :             const ::Color aEmptyColor( COL_AUTO );
    2146             : 
    2147           0 :             ActionSharedPtr ret;
    2148             : 
    2149             :             // no DX array, and no need to subset - no need to store
    2150             :             // DX array, then.
    2151           0 :             if( !pDXArray && !bSubsettable )
    2152             :             {
    2153             :                 // effects, or not?
    2154           0 :                 if( !rState.textOverlineStyle &&
    2155           0 :                     !rState.textUnderlineStyle &&
    2156           0 :                     !rState.textStrikeoutStyle &&
    2157           0 :                     rReliefColor == aEmptyColor &&
    2158           0 :                     rShadowColor == aEmptyColor )
    2159             :                 {
    2160             :                     // nope
    2161           0 :                     if( rParms.maTextTransformation.is_initialized() )
    2162             :                     {
    2163           0 :                         ret = ActionSharedPtr( new TextAction(
    2164             :                                                     aStartPoint,
    2165             :                                                     rText,
    2166             :                                                     nStartPos,
    2167             :                                                     nLen,
    2168             :                                                     rCanvas,
    2169             :                                                     rState,
    2170           0 :                                                     *rParms.maTextTransformation ) );
    2171             :                     }
    2172             :                     else
    2173             :                     {
    2174           0 :                         ret = ActionSharedPtr( new TextAction(
    2175             :                                                     aStartPoint,
    2176             :                                                     rText,
    2177             :                                                     nStartPos,
    2178             :                                                     nLen,
    2179             :                                                     rCanvas,
    2180           0 :                                                     rState ) );
    2181             :                     }
    2182             :                 }
    2183             :                 else
    2184             :                 {
    2185             :                     // at least one of the effects requested
    2186           0 :                     if( rParms.maTextTransformation.is_initialized() )
    2187           0 :                         ret = ActionSharedPtr( new EffectTextAction(
    2188             :                                                     aStartPoint,
    2189             :                                                     aReliefOffset,
    2190             :                                                     rReliefColor,
    2191             :                                                     aShadowOffset,
    2192             :                                                     rShadowColor,
    2193             :                                                     rText,
    2194             :                                                     nStartPos,
    2195             :                                                     nLen,
    2196             :                                                     rVDev,
    2197             :                                                     rCanvas,
    2198             :                                                     rState,
    2199           0 :                                                     *rParms.maTextTransformation ) );
    2200             :                     else
    2201           0 :                         ret = ActionSharedPtr( new EffectTextAction(
    2202             :                                                     aStartPoint,
    2203             :                                                     aReliefOffset,
    2204             :                                                     rReliefColor,
    2205             :                                                     aShadowOffset,
    2206             :                                                     rShadowColor,
    2207             :                                                     rText,
    2208             :                                                     nStartPos,
    2209             :                                                     nLen,
    2210             :                                                     rVDev,
    2211             :                                                     rCanvas,
    2212           0 :                                                     rState ) );
    2213             :                 }
    2214             :             }
    2215             :             else
    2216             :             {
    2217             :                 // DX array necessary - any effects?
    2218           0 :                 if( !rState.textOverlineStyle &&
    2219           0 :                     !rState.textUnderlineStyle &&
    2220           0 :                     !rState.textStrikeoutStyle &&
    2221           0 :                     rReliefColor == aEmptyColor &&
    2222           0 :                     rShadowColor == aEmptyColor )
    2223             :                 {
    2224             :                     // nope
    2225           0 :                     if( rParms.maTextTransformation.is_initialized() )
    2226           0 :                         ret = ActionSharedPtr( new TextArrayAction(
    2227             :                                                     aStartPoint,
    2228             :                                                     rText,
    2229             :                                                     nStartPos,
    2230             :                                                     nLen,
    2231             :                                                     aCharWidths,
    2232             :                                                     rCanvas,
    2233             :                                                     rState,
    2234           0 :                                                     *rParms.maTextTransformation ) );
    2235             :                     else
    2236           0 :                         ret = ActionSharedPtr( new TextArrayAction(
    2237             :                                                     aStartPoint,
    2238             :                                                     rText,
    2239             :                                                     nStartPos,
    2240             :                                                     nLen,
    2241             :                                                     aCharWidths,
    2242             :                                                     rCanvas,
    2243           0 :                                                     rState ) );
    2244             :                 }
    2245             :                 else
    2246             :                 {
    2247             :                     // at least one of the effects requested
    2248           0 :                     if( rParms.maTextTransformation.is_initialized() )
    2249           0 :                         ret = ActionSharedPtr( new EffectTextArrayAction(
    2250             :                                                     aStartPoint,
    2251             :                                                     aReliefOffset,
    2252             :                                                     rReliefColor,
    2253             :                                                     aShadowOffset,
    2254             :                                                     rShadowColor,
    2255             :                                                     rText,
    2256             :                                                     nStartPos,
    2257             :                                                     nLen,
    2258             :                                                     aCharWidths,
    2259             :                                                     rVDev,
    2260             :                                                     rCanvas,
    2261             :                                                     rState,
    2262           0 :                                                     *rParms.maTextTransformation ) );
    2263             :                     else
    2264           0 :                         ret = ActionSharedPtr( new EffectTextArrayAction(
    2265             :                                                     aStartPoint,
    2266             :                                                     aReliefOffset,
    2267             :                                                     rReliefColor,
    2268             :                                                     aShadowOffset,
    2269             :                                                     rShadowColor,
    2270             :                                                     rText,
    2271             :                                                     nStartPos,
    2272             :                                                     nLen,
    2273             :                                                     aCharWidths,
    2274             :                                                     rVDev,
    2275             :                                                     rCanvas,
    2276           0 :                                                     rState ) );
    2277             :                 }
    2278             :             }
    2279           0 :             return ret;
    2280             :         }
    2281             :     }
    2282        1143 : }
    2283             : 
    2284             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10