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