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