1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <tools/diagnose_ex.h>
23 #include <com/sun/star/rendering/PathCapType.hpp>
24 #include <com/sun/star/rendering/PathJoinType.hpp>
25 #include <com/sun/star/rendering/XCanvas.hpp>
26 #include <com/sun/star/rendering/XCanvasFont.hpp>
28 #include <basegfx/numeric/ftools.hxx>
29 #include <basegfx/matrix/b2dhommatrix.hxx>
30 #include <basegfx/range/b2drectangle.hxx>
31 #include <basegfx/vector/b2dsize.hxx>
32 #include <basegfx/polygon/b2dpolypolygontools.hxx>
33 #include <basegfx/polygon/b2dpolygontools.hxx>
34 #include <basegfx/matrix/b2dhommatrixtools.hxx>
36 #include <tools/gen.hxx>
37 #include <vcl/canvastools.hxx>
38 #include <vcl/virdev.hxx>
40 #include <basegfx/tools/canvastools.hxx>
41 #include <canvas/canvastools.hxx>
45 #include "textaction.hxx"
46 #include "outdevstate.hxx"
47 #include "mtftools.hxx"
50 using namespace ::com::sun::star
;
58 void init( rendering::RenderState
& o_rRenderState
,
59 const ::basegfx::B2DPoint
& rStartPoint
,
60 const OutDevState
& rState
,
61 const CanvasSharedPtr
& rCanvas
)
63 tools::initRenderState(o_rRenderState
,rState
);
65 // #i36950# Offset clip back to origin (as it's also moved
67 // #i53964# Also take VCL font rotation into account,
68 // since this, opposed to the FontMatrix rotation
69 // elsewhere, _does_ get incorporated into the render
71 tools::modifyClip( o_rRenderState
,
76 &rState
.fontRotation
);
78 basegfx::B2DHomMatrix
aLocalTransformation(basegfx::tools::createRotateB2DHomMatrix(rState
.fontRotation
));
79 aLocalTransformation
.translate( rStartPoint
.getX(),
81 ::canvas::tools::appendToRenderState( o_rRenderState
,
82 aLocalTransformation
);
84 o_rRenderState
.DeviceColor
= rState
.textColor
;
87 void init( rendering::RenderState
& o_rRenderState
,
88 const ::basegfx::B2DPoint
& rStartPoint
,
89 const OutDevState
& rState
,
90 const CanvasSharedPtr
& rCanvas
,
91 const ::basegfx::B2DHomMatrix
& rTextTransform
)
93 init( o_rRenderState
, rStartPoint
, rState
, rCanvas
);
95 // TODO(F2): Also inversely-transform clip with
96 // rTextTransform (which is actually rather hard, as the
97 // text transform is _prepended_ to the render state)!
99 // prepend extra font transform to render state
100 // (prepend it, because it's interpreted in the unit
101 // rect coordinate space)
102 ::canvas::tools::prependToRenderState( o_rRenderState
,
106 void init( rendering::RenderState
& o_rRenderState
,
107 uno::Reference
< rendering::XCanvasFont
>& o_rFont
,
108 const ::basegfx::B2DPoint
& rStartPoint
,
109 const OutDevState
& rState
,
110 const CanvasSharedPtr
& rCanvas
)
112 // ensure that o_rFont is valid. It is possible that
113 // text actions are generated without previously
114 // setting a font. Then, just take a default font
117 // Use completely default FontRequest
118 const rendering::FontRequest aFontRequest
;
120 geometry::Matrix2D aFontMatrix
;
121 ::canvas::tools::setIdentityMatrix2D( aFontMatrix
);
123 o_rFont
= rCanvas
->getUNOCanvas()->createFont(
125 uno::Sequence
< beans::PropertyValue
>(),
129 init( o_rRenderState
,
135 void init( rendering::RenderState
& o_rRenderState
,
136 uno::Reference
< rendering::XCanvasFont
>& o_rFont
,
137 const ::basegfx::B2DPoint
& rStartPoint
,
138 const OutDevState
& rState
,
139 const CanvasSharedPtr
& rCanvas
,
140 const ::basegfx::B2DHomMatrix
& rTextTransform
)
142 init( o_rRenderState
, o_rFont
, rStartPoint
, rState
, rCanvas
);
144 // TODO(F2): Also inversely-transform clip with
145 // rTextTransform (which is actually rather hard, as the
146 // text transform is _prepended_ to the render state)!
148 // prepend extra font transform to render state
149 // (prepend it, because it's interpreted in the unit
150 // rect coordinate space)
151 ::canvas::tools::prependToRenderState( o_rRenderState
,
155 ::basegfx::B2DPolyPolygon
textLinesFromLogicalOffsets( const uno::Sequence
< double >& rOffsets
,
156 const tools::TextLineInfo
& rTextLineInfo
)
158 return tools::createTextLinesPolyPolygon(
160 // extract character cell furthest to the right
161 *(::std::max_element(
162 rOffsets
.getConstArray(),
163 rOffsets
.getConstArray() + rOffsets
.getLength() )),
167 uno::Sequence
< double > setupDXArray( const long* pCharWidths
,
169 const OutDevState
& rState
)
171 // convert character widths from logical units
172 uno::Sequence
< double > aCharWidthSeq( nLen
);
173 double* pOutputWidths( aCharWidthSeq
.getArray() );
175 // #143885# maintain (nearly) full precision of DX
176 // array, by circumventing integer-based
178 const double nScale( rState
.mapModeTransform
.get(0,0) );
179 for( int i
= 0; i
< nLen
; ++i
)
181 // TODO(F2): use correct scale direction
182 *pOutputWidths
++ = *pCharWidths
++ * nScale
;
185 return aCharWidthSeq
;
188 uno::Sequence
< double > setupDXArray( const OUString
& rText
,
191 VirtualDevice
& rVDev
,
192 const OutDevState
& rState
)
194 // no external DX array given, create one from given
196 ::std::unique_ptr
< long []> pCharWidths( new long[nLen
] );
198 rVDev
.GetTextArray( rText
, pCharWidths
.get(),
201 return setupDXArray( pCharWidths
.get(), nLen
, rState
);
204 ::basegfx::B2DPoint
adaptStartPoint( const ::basegfx::B2DPoint
& rStartPoint
,
205 const OutDevState
& rState
,
206 const uno::Sequence
< double >& rOffsets
)
208 ::basegfx::B2DPoint
aLocalPoint( rStartPoint
);
210 if( rState
.textAlignment
)
212 // text origin is right, not left. Modify start point
213 // accordingly, because XCanvas::drawTextLayout()
214 // always aligns left!
216 const double nOffset( rOffsets
[ rOffsets
.getLength()-1 ] );
218 // correct start point for rotated text: rotate around
219 // former start point
220 aLocalPoint
.setX( aLocalPoint
.getX() + cos( rState
.fontRotation
)*nOffset
);
221 aLocalPoint
.setY( aLocalPoint
.getY() + sin( rState
.fontRotation
)*nOffset
);
227 /** Perform common setup for array text actions
229 This method creates the XTextLayout object and
230 initializes it, e.g. with the logical advancements.
232 void initArrayAction( rendering::RenderState
& o_rRenderState
,
233 uno::Reference
< rendering::XTextLayout
>& o_rTextLayout
,
234 const ::basegfx::B2DPoint
& rStartPoint
,
235 const OUString
& rText
,
238 const uno::Sequence
< double >& rOffsets
,
239 const CanvasSharedPtr
& rCanvas
,
240 const OutDevState
& rState
,
241 const ::basegfx::B2DHomMatrix
* pTextTransform
)
243 ENSURE_OR_THROW( rOffsets
.getLength(),
244 "::cppcanvas::internal::initArrayAction(): zero-length DX array" );
246 const ::basegfx::B2DPoint
aLocalStartPoint(
247 adaptStartPoint( rStartPoint
, rState
, rOffsets
) );
249 uno::Reference
< rendering::XCanvasFont
> xFont( rState
.xFont
);
252 init( o_rRenderState
, xFont
, aLocalStartPoint
, rState
, rCanvas
, *pTextTransform
);
254 init( o_rRenderState
, xFont
, aLocalStartPoint
, rState
, rCanvas
);
256 o_rTextLayout
= xFont
->createTextLayout(
257 rendering::StringContext( rText
, nStartPos
, nLen
),
258 rState
.textDirection
,
261 ENSURE_OR_THROW( o_rTextLayout
.is(),
262 "::cppcanvas::internal::initArrayAction(): Invalid font" );
264 o_rTextLayout
->applyLogicalAdvancements( rOffsets
);
267 double getLineWidth( ::VirtualDevice
& rVDev
,
268 const OutDevState
& rState
,
269 const rendering::StringContext
& rStringContext
)
271 // TODO(F2): use correct scale direction
272 const ::basegfx::B2DSize
aSize( rVDev
.GetTextWidth( rStringContext
.Text
,
273 static_cast<sal_uInt16
>(rStringContext
.StartPosition
),
274 static_cast<sal_uInt16
>(rStringContext
.Length
) ),
277 return (rState
.mapModeTransform
* aSize
).getX();
280 uno::Sequence
< double >
281 calcSubsetOffsets( rendering::RenderState
& io_rRenderState
,
284 const uno::Reference
< rendering::XTextLayout
>& rOrigTextLayout
,
285 const ::cppcanvas::internal::Action::Subset
& rSubset
)
287 ENSURE_OR_THROW( rSubset
.mnSubsetEnd
> rSubset
.mnSubsetBegin
,
288 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
290 uno::Sequence
< double > aOrigOffsets( rOrigTextLayout
->queryLogicalAdvancements() );
291 const double* pOffsets( aOrigOffsets
.getConstArray() );
293 ENSURE_OR_THROW( aOrigOffsets
.getLength() >= rSubset
.mnSubsetEnd
,
294 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
296 // TODO(F3): It currently seems that for RTL text, the
297 // DX offsets are nevertheless increasing in logical
298 // text order (I'd expect they are decreasing,
299 // mimicking the fact that the text is output
300 // right-to-left). This breaks text effects for ALL
303 // determine leftmost position in given subset range -
304 // as the DX array contains the output positions
305 // starting with the second character (the first is
306 // assumed to have output position 0), correct begin
308 const double nMinPos( rSubset
.mnSubsetBegin
<= 0 ? 0 :
309 *(::std::min_element( pOffsets
+rSubset
.mnSubsetBegin
-1,
310 pOffsets
+rSubset
.mnSubsetEnd
)) );
312 // determine rightmost position in given subset range
313 // - as the DX array contains the output positions
314 // starting with the second character (the first is
315 // assumed to have output position 0), correct begin
317 const double nMaxPos(
318 *(::std::max_element( pOffsets
+ (rSubset
.mnSubsetBegin
<= 0 ?
319 0 : rSubset
.mnSubsetBegin
-1),
320 pOffsets
+ rSubset
.mnSubsetEnd
)) );
323 // adapt render state, to move text output to given offset
326 // TODO(F1): Strictly speaking, we also have to adapt
327 // the clip here, which normally should _not_ move
328 // with the output offset. Neglected for now, as it
329 // does not matter for drawing layer output
331 if( rSubset
.mnSubsetBegin
> 0 )
333 ::basegfx::B2DHomMatrix aTranslation
;
334 if( rOrigTextLayout
->getFont()->getFontRequest().FontDescription
.IsVertical
)
336 // vertical text -> offset in y direction
337 aTranslation
.translate( 0.0, nMinPos
);
341 // horizontal text -> offset in x direction
342 aTranslation
.translate( nMinPos
, 0.0 );
345 ::canvas::tools::appendToRenderState( io_rRenderState
,
350 // reduce DX array to given substring
353 const sal_Int32
nNewElements( rSubset
.mnSubsetEnd
- rSubset
.mnSubsetBegin
);
354 uno::Sequence
< double > aAdaptedOffsets( nNewElements
);
355 double* pAdaptedOffsets( aAdaptedOffsets
.getArray() );
357 // move to new output position (subtract nMinPos,
358 // which is the new '0' position), copy only the range
359 // as given by rSubset.
360 ::std::transform( pOffsets
+ rSubset
.mnSubsetBegin
,
361 pOffsets
+ rSubset
.mnSubsetEnd
,
363 [nMinPos
](double aPos
) { return aPos
- nMinPos
; } );
368 return aAdaptedOffsets
;
371 uno::Reference
< rendering::XTextLayout
>
372 createSubsetLayout( const rendering::StringContext
& rOrigContext
,
373 const ::cppcanvas::internal::Action::Subset
& rSubset
,
374 const uno::Reference
< rendering::XTextLayout
>& rOrigTextLayout
)
376 // create temporary new text layout with subset string
379 const sal_Int32
nNewStartPos( rOrigContext
.StartPosition
+ ::std::min(
380 rSubset
.mnSubsetBegin
, rOrigContext
.Length
-1 ) );
381 const sal_Int32
nNewLength( ::std::max(
383 rSubset
.mnSubsetEnd
- rSubset
.mnSubsetBegin
,
384 rOrigContext
.Length
),
387 const rendering::StringContext
aContext( rOrigContext
.Text
,
391 uno::Reference
< rendering::XTextLayout
> xTextLayout(
392 rOrigTextLayout
->getFont()->createTextLayout( aContext
,
393 rOrigTextLayout
->getMainTextDirection(),
395 uno::UNO_QUERY_THROW
);
400 /** Setup subset text layout
402 @param io_rTextLayout
403 Must contain original (full set) text layout on input,
404 will contain subsetted text layout (or empty
405 reference, for empty subsets) on output.
407 @param io_rRenderState
408 Must contain original render state on input, will
409 contain shifted render state concatenated with
410 rTransformation on output.
412 @param rTransformation
413 Additional transformation, to be prepended to render
419 void createSubsetLayout( uno::Reference
< rendering::XTextLayout
>& io_rTextLayout
,
420 rendering::RenderState
& io_rRenderState
,
423 const ::basegfx::B2DHomMatrix
& rTransformation
,
424 const Action::Subset
& rSubset
)
426 ::canvas::tools::prependToRenderState(io_rRenderState
, rTransformation
);
428 if( rSubset
.mnSubsetBegin
== rSubset
.mnSubsetEnd
)
430 // empty range, empty layout
431 io_rTextLayout
.clear();
436 ENSURE_OR_THROW( io_rTextLayout
.is(),
437 "createSubsetLayout(): Invalid input layout" );
439 const rendering::StringContext
& rOrigContext( io_rTextLayout
->getText() );
441 if( rSubset
.mnSubsetBegin
== 0 &&
442 rSubset
.mnSubsetEnd
== rOrigContext
.Length
)
444 // full range, no need for subsetting
448 uno::Reference
< rendering::XTextLayout
> xTextLayout(
449 createSubsetLayout( rOrigContext
, rSubset
, io_rTextLayout
) );
451 if( xTextLayout
.is() )
453 xTextLayout
->applyLogicalAdvancements(
454 calcSubsetOffsets( io_rRenderState
,
461 io_rTextLayout
= xTextLayout
;
465 /** Interface for renderEffectText functor below.
467 This is interface is used from the renderEffectText()
468 method below, to call the client implementation.
473 virtual ~TextRenderer() {}
475 /// Render text with given RenderState
476 virtual bool operator()( const rendering::RenderState
& rRenderState
) const = 0;
479 /** Render effect text.
482 Functor object, will be called to render the actual
483 part of the text effect (the text itself and the means
484 to render it are unknown to this method)
486 bool renderEffectText( const TextRenderer
& rRenderer
,
487 const rendering::RenderState
& rRenderState
,
488 const rendering::ViewState
& /*rViewState*/,
489 const uno::Reference
< rendering::XCanvas
>& xCanvas
,
490 const ::Color
& rShadowColor
,
491 const ::basegfx::B2DSize
& rShadowOffset
,
492 const ::Color
& rReliefColor
,
493 const ::basegfx::B2DSize
& rReliefOffset
)
495 ::Color
aEmptyColor( COL_AUTO
);
496 uno::Reference
<rendering::XColorSpace
> xColorSpace(
497 xCanvas
->getDevice()->getDeviceColorSpace() );
499 // draw shadow text, if enabled
500 if( rShadowColor
!= aEmptyColor
)
502 rendering::RenderState
aShadowState( rRenderState
);
503 ::basegfx::B2DHomMatrix aTranslate
;
505 aTranslate
.translate( rShadowOffset
.getX(),
506 rShadowOffset
.getY() );
508 ::canvas::tools::appendToRenderState(aShadowState
, aTranslate
);
510 aShadowState
.DeviceColor
=
511 vcl::unotools::colorToDoubleSequence( rShadowColor
,
514 rRenderer( aShadowState
);
517 // draw relief text, if enabled
518 if( rReliefColor
!= aEmptyColor
)
520 rendering::RenderState
aReliefState( rRenderState
);
521 ::basegfx::B2DHomMatrix aTranslate
;
523 aTranslate
.translate( rReliefOffset
.getX(),
524 rReliefOffset
.getY() );
526 ::canvas::tools::appendToRenderState(aReliefState
, aTranslate
);
528 aReliefState
.DeviceColor
=
529 vcl::unotools::colorToDoubleSequence( rReliefColor
,
532 rRenderer( aReliefState
);
536 rRenderer( rRenderState
);
542 ::basegfx::B2DRange
calcEffectTextBounds( const ::basegfx::B2DRange
& rTextBounds
,
543 const ::basegfx::B2DRange
& rLineBounds
,
544 const ::basegfx::B2DSize
& rReliefOffset
,
545 const ::basegfx::B2DSize
& rShadowOffset
,
546 const rendering::RenderState
& rRenderState
,
547 const rendering::ViewState
& rViewState
)
549 ::basegfx::B2DRange
aBounds( rTextBounds
);
551 // add extends of text lines
552 aBounds
.expand( rLineBounds
);
554 // TODO(Q3): Provide this functionality at the B2DRange
555 ::basegfx::B2DRange
aTotalBounds( aBounds
);
557 ::basegfx::B2DRange( aBounds
.getMinX() + rReliefOffset
.getX(),
558 aBounds
.getMinY() + rReliefOffset
.getY(),
559 aBounds
.getMaxX() + rReliefOffset
.getX(),
560 aBounds
.getMaxY() + rReliefOffset
.getY() ) );
562 ::basegfx::B2DRange( aBounds
.getMinX() + rShadowOffset
.getX(),
563 aBounds
.getMinY() + rShadowOffset
.getY(),
564 aBounds
.getMaxX() + rShadowOffset
.getX(),
565 aBounds
.getMaxY() + rShadowOffset
.getY() ) );
567 return tools::calcDevicePixelBounds( aTotalBounds
,
572 void initEffectLinePolyPolygon( ::basegfx::B2DSize
& o_rOverallSize
,
573 uno::Reference
< rendering::XPolyPolygon2D
>& o_rTextLines
,
574 const CanvasSharedPtr
& rCanvas
,
575 const uno::Sequence
< double >& rOffsets
,
576 const tools::TextLineInfo
& rLineInfo
)
578 const ::basegfx::B2DPolyPolygon
aPoly(
579 textLinesFromLogicalOffsets(
583 o_rOverallSize
= ::basegfx::tools::getRange( aPoly
).getRange();
585 o_rTextLines
= ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
586 rCanvas
->getUNOCanvas()->getDevice(),
590 void initEffectLinePolyPolygon( ::basegfx::B2DSize
& o_rOverallSize
,
591 uno::Reference
< rendering::XPolyPolygon2D
>& o_rTextLines
,
592 const CanvasSharedPtr
& rCanvas
,
594 const tools::TextLineInfo
& rLineInfo
)
596 const ::basegfx::B2DPolyPolygon
aPoly(
597 tools::createTextLinesPolyPolygon( 0.0, nLineWidth
,
600 o_rOverallSize
= ::basegfx::tools::getRange( aPoly
).getRange();
602 o_rTextLines
= ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
603 rCanvas
->getUNOCanvas()->getDevice(),
608 class TextAction
: public Action
611 TextAction( const ::basegfx::B2DPoint
& rStartPoint
,
612 const OUString
& rString
,
615 const CanvasSharedPtr
& rCanvas
,
616 const OutDevState
& rState
);
618 TextAction( const ::basegfx::B2DPoint
& rStartPoint
,
619 const OUString
& rString
,
622 const CanvasSharedPtr
& rCanvas
,
623 const OutDevState
& rState
,
624 const ::basegfx::B2DHomMatrix
& rTextTransform
);
626 TextAction(const TextAction
&) = delete;
627 const TextAction
& operator=(const TextAction
&) = delete;
629 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
630 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
631 const Subset
& rSubset
) const override
;
633 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
634 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
635 const Subset
& rSubset
) const override
;
637 virtual sal_Int32
getActionCount() const override
;
640 // TODO(P2): This is potentially a real mass object
641 // (every character might be a separate TextAction),
642 // thus, make it as lightweight as possible. For
643 // example, share common RenderState among several
644 // TextActions, maybe using maOffsets for the
647 uno::Reference
< rendering::XCanvasFont
> mxFont
;
648 const rendering::StringContext maStringContext
;
649 const CanvasSharedPtr mpCanvas
;
650 rendering::RenderState maState
;
651 const sal_Int8 maTextDirection
;
654 TextAction::TextAction( const ::basegfx::B2DPoint
& rStartPoint
,
655 const OUString
& rString
,
658 const CanvasSharedPtr
& rCanvas
,
659 const OutDevState
& rState
) :
660 mxFont( rState
.xFont
),
661 maStringContext( rString
, nStartPos
, nLen
),
664 maTextDirection( rState
.textDirection
)
666 init( maState
, mxFont
,
670 ENSURE_OR_THROW( mxFont
.is(),
671 "::cppcanvas::internal::TextAction(): Invalid font" );
674 TextAction::TextAction( const ::basegfx::B2DPoint
& rStartPoint
,
675 const OUString
& rString
,
678 const CanvasSharedPtr
& rCanvas
,
679 const OutDevState
& rState
,
680 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
681 mxFont( rState
.xFont
),
682 maStringContext( rString
, nStartPos
, nLen
),
685 maTextDirection( rState
.textDirection
)
687 init( maState
, mxFont
,
689 rState
, rCanvas
, rTextTransform
);
691 ENSURE_OR_THROW( mxFont
.is(),
692 "::cppcanvas::internal::TextAction(): Invalid font" );
695 bool TextAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
697 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextAction::render()" );
698 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextAction: 0x" << std::hex
<< this );
700 rendering::RenderState
aLocalState( maState
);
701 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
703 mpCanvas
->getUNOCanvas()->drawText( maStringContext
, mxFont
,
704 mpCanvas
->getViewState(), aLocalState
, maTextDirection
);
709 bool TextAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
710 const Subset
& /*rSubset*/ ) const
712 SAL_WARN( "cppcanvas.emf", "TextAction::renderSubset(): Subset not supported by this object" );
714 // TODO(P1): Retrieve necessary font metric info for
715 // TextAction from XCanvas. Currently, the
716 // TextActionFactory does not generate this object for
717 // _subsettable_ text
718 return render( rTransformation
);
721 ::basegfx::B2DRange
TextAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
723 // create XTextLayout, to have the
724 // XTextLayout::queryTextBounds() method available
725 uno::Reference
< rendering::XTextLayout
> xTextLayout(
726 mxFont
->createTextLayout(
731 rendering::RenderState
aLocalState( maState
);
732 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
734 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
735 xTextLayout
->queryTextBounds() ),
736 mpCanvas
->getViewState(),
740 ::basegfx::B2DRange
TextAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
741 const Subset
& /*rSubset*/ ) const
743 SAL_WARN( "cppcanvas.emf", "TextAction::getBounds(): Subset not supported by this object" );
745 // TODO(P1): Retrieve necessary font metric info for
746 // TextAction from XCanvas. Currently, the
747 // TextActionFactory does not generate this object for
748 // _subsettable_ text
749 return getBounds( rTransformation
);
752 sal_Int32
TextAction::getActionCount() const
754 // TODO(P1): Retrieve necessary font metric info for
755 // TextAction from XCanvas. Currently, the
756 // TextActionFactory does not generate this object for
757 // _subsettable_ text
762 class EffectTextAction
:
767 EffectTextAction( const ::basegfx::B2DPoint
& rStartPoint
,
768 const ::basegfx::B2DSize
& rReliefOffset
,
769 const ::Color
& rReliefColor
,
770 const ::basegfx::B2DSize
& rShadowOffset
,
771 const ::Color
& rShadowColor
,
772 const OUString
& rText
,
775 VirtualDevice
& rVDev
,
776 const CanvasSharedPtr
& rCanvas
,
777 const OutDevState
& rState
);
779 EffectTextAction( const ::basegfx::B2DPoint
& rStartPoint
,
780 const ::basegfx::B2DSize
& rReliefOffset
,
781 const ::Color
& rReliefColor
,
782 const ::basegfx::B2DSize
& rShadowOffset
,
783 const ::Color
& rShadowColor
,
784 const OUString
& rText
,
787 VirtualDevice
& rVDev
,
788 const CanvasSharedPtr
& rCanvas
,
789 const OutDevState
& rState
,
790 const ::basegfx::B2DHomMatrix
& rTextTransform
);
792 EffectTextAction(const EffectTextAction
&) = delete;
793 const EffectTextAction
& operator=(const EffectTextAction
&) = delete;
795 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
796 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
797 const Subset
& rSubset
) const override
;
799 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
800 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
801 const Subset
& rSubset
) const override
;
803 virtual sal_Int32
getActionCount() const override
;
806 /// Interface TextRenderer
807 virtual bool operator()( const rendering::RenderState
& rRenderState
) const override
;
809 // TODO(P2): This is potentially a real mass object
810 // (every character might be a separate TextAction),
811 // thus, make it as lightweight as possible. For
812 // example, share common RenderState among several
813 // TextActions, maybe using maOffsets for the
816 uno::Reference
< rendering::XCanvasFont
> mxFont
;
817 const rendering::StringContext maStringContext
;
818 const CanvasSharedPtr mpCanvas
;
819 rendering::RenderState maState
;
820 const tools::TextLineInfo maTextLineInfo
;
821 ::basegfx::B2DSize maLinesOverallSize
;
822 const double mnLineWidth
;
823 uno::Reference
< rendering::XPolyPolygon2D
> mxTextLines
;
824 const ::basegfx::B2DSize maReliefOffset
;
825 const ::Color maReliefColor
;
826 const ::basegfx::B2DSize maShadowOffset
;
827 const ::Color maShadowColor
;
828 const sal_Int8 maTextDirection
;
831 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint
& rStartPoint
,
832 const ::basegfx::B2DSize
& rReliefOffset
,
833 const ::Color
& rReliefColor
,
834 const ::basegfx::B2DSize
& rShadowOffset
,
835 const ::Color
& rShadowColor
,
836 const OUString
& rText
,
839 VirtualDevice
& rVDev
,
840 const CanvasSharedPtr
& rCanvas
,
841 const OutDevState
& rState
) :
842 mxFont( rState
.xFont
),
843 maStringContext( rText
, nStartPos
, nLen
),
846 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
847 maLinesOverallSize(),
848 mnLineWidth( getLineWidth( rVDev
, rState
, maStringContext
) ),
850 maReliefOffset( rReliefOffset
),
851 maReliefColor( rReliefColor
),
852 maShadowOffset( rShadowOffset
),
853 maShadowColor( rShadowColor
),
854 maTextDirection( rState
.textDirection
)
856 initEffectLinePolyPolygon( maLinesOverallSize
,
862 init( maState
, mxFont
,
866 ENSURE_OR_THROW( mxFont
.is() && mxTextLines
.is(),
867 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
870 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint
& rStartPoint
,
871 const ::basegfx::B2DSize
& rReliefOffset
,
872 const ::Color
& rReliefColor
,
873 const ::basegfx::B2DSize
& rShadowOffset
,
874 const ::Color
& rShadowColor
,
875 const OUString
& rText
,
878 VirtualDevice
& rVDev
,
879 const CanvasSharedPtr
& rCanvas
,
880 const OutDevState
& rState
,
881 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
882 mxFont( rState
.xFont
),
883 maStringContext( rText
, nStartPos
, nLen
),
886 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
887 maLinesOverallSize(),
888 mnLineWidth( getLineWidth( rVDev
, rState
, maStringContext
) ),
890 maReliefOffset( rReliefOffset
),
891 maReliefColor( rReliefColor
),
892 maShadowOffset( rShadowOffset
),
893 maShadowColor( rShadowColor
),
894 maTextDirection( rState
.textDirection
)
896 initEffectLinePolyPolygon( maLinesOverallSize
,
902 init( maState
, mxFont
,
904 rState
, rCanvas
, rTextTransform
);
906 ENSURE_OR_THROW( mxFont
.is() && mxTextLines
.is(),
907 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
910 bool EffectTextAction::operator()( const rendering::RenderState
& rRenderState
) const
912 const rendering::ViewState
& rViewState( mpCanvas
->getViewState() );
913 const uno::Reference
< rendering::XCanvas
>& rCanvas( mpCanvas
->getUNOCanvas() );
915 rCanvas
->fillPolyPolygon( mxTextLines
,
919 rCanvas
->drawText( maStringContext
, mxFont
,
927 bool EffectTextAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
929 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextAction::render()" );
930 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextAction: 0x" << std::hex
<< this );
932 rendering::RenderState
aLocalState( maState
);
933 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
935 return renderEffectText( *this,
937 mpCanvas
->getViewState(),
938 mpCanvas
->getUNOCanvas(),
945 bool EffectTextAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
946 const Subset
& /*rSubset*/ ) const
948 SAL_WARN( "cppcanvas.emf", "EffectTextAction::renderSubset(): Subset not supported by this object" );
950 // TODO(P1): Retrieve necessary font metric info for
951 // TextAction from XCanvas. Currently, the
952 // TextActionFactory does not generate this object for
954 return render( rTransformation
);
957 ::basegfx::B2DRange
EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
959 // create XTextLayout, to have the
960 // XTextLayout::queryTextBounds() method available
961 uno::Reference
< rendering::XTextLayout
> xTextLayout(
962 mxFont
->createTextLayout(
967 rendering::RenderState
aLocalState( maState
);
968 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
970 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
971 xTextLayout
->queryTextBounds() ),
972 ::basegfx::B2DRange( 0,0,
973 maLinesOverallSize
.getX(),
974 maLinesOverallSize
.getY() ),
978 mpCanvas
->getViewState() );
981 ::basegfx::B2DRange
EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
982 const Subset
& /*rSubset*/ ) const
984 SAL_WARN( "cppcanvas.emf", "EffectTextAction::getBounds(): Subset not supported by this object" );
986 // TODO(P1): Retrieve necessary font metric info for
987 // TextAction from XCanvas. Currently, the
988 // TextActionFactory does not generate this object for
989 // _subsettable_ text
990 return getBounds( rTransformation
);
993 sal_Int32
EffectTextAction::getActionCount() const
995 // TODO(P1): Retrieve necessary font metric info for
996 // TextAction from XCanvas. Currently, the
997 // TextActionFactory does not generate this object for
1003 class TextArrayAction
: public Action
1006 TextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1007 const OUString
& rString
,
1008 sal_Int32 nStartPos
,
1010 const uno::Sequence
< double >& rOffsets
,
1011 const CanvasSharedPtr
& rCanvas
,
1012 const OutDevState
& rState
);
1014 TextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1015 const OUString
& rString
,
1016 sal_Int32 nStartPos
,
1018 const uno::Sequence
< double >& rOffsets
,
1019 const CanvasSharedPtr
& rCanvas
,
1020 const OutDevState
& rState
,
1021 const ::basegfx::B2DHomMatrix
& rTextTransform
);
1023 TextArrayAction(const TextArrayAction
&) = delete;
1024 const TextArrayAction
& operator=(const TextArrayAction
&) = delete;
1026 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1027 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1028 const Subset
& rSubset
) const override
;
1030 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1031 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1032 const Subset
& rSubset
) const override
;
1034 virtual sal_Int32
getActionCount() const override
;
1037 // TODO(P2): This is potentially a real mass object
1038 // (every character might be a separate TextAction),
1039 // thus, make it as lightweight as possible. For
1040 // example, share common RenderState among several
1041 // TextActions, maybe using maOffsets for the
1044 uno::Reference
< rendering::XTextLayout
> mxTextLayout
;
1045 const CanvasSharedPtr mpCanvas
;
1046 rendering::RenderState maState
;
1049 TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1050 const OUString
& rString
,
1051 sal_Int32 nStartPos
,
1053 const uno::Sequence
< double >& rOffsets
,
1054 const CanvasSharedPtr
& rCanvas
,
1055 const OutDevState
& rState
) :
1057 mpCanvas( rCanvas
),
1060 initArrayAction( maState
,
1071 TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1072 const OUString
& rString
,
1073 sal_Int32 nStartPos
,
1075 const uno::Sequence
< double >& rOffsets
,
1076 const CanvasSharedPtr
& rCanvas
,
1077 const OutDevState
& rState
,
1078 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
1080 mpCanvas( rCanvas
),
1083 initArrayAction( maState
,
1095 bool TextArrayAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1097 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::render()" );
1098 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex
<< this );
1100 rendering::RenderState
aLocalState( maState
);
1101 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1103 mpCanvas
->getUNOCanvas()->drawTextLayout( mxTextLayout
,
1104 mpCanvas
->getViewState(),
1110 bool TextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1111 const Subset
& rSubset
) const
1113 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::renderSubset()" );
1114 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex
<< this );
1116 rendering::RenderState
aLocalState( maState
);
1117 uno::Reference
< rendering::XTextLayout
> xTextLayout( mxTextLayout
);
1119 double nDummy0
, nDummy1
;
1120 createSubsetLayout( xTextLayout
,
1127 if( !xTextLayout
.is() )
1128 return true; // empty layout, render nothing
1130 mpCanvas
->getUNOCanvas()->drawTextLayout( xTextLayout
,
1131 mpCanvas
->getViewState(),
1137 ::basegfx::B2DRange
TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1139 rendering::RenderState
aLocalState( maState
);
1140 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1142 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1143 mxTextLayout
->queryTextBounds() ),
1144 mpCanvas
->getViewState(),
1148 ::basegfx::B2DRange
TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1149 const Subset
& rSubset
) const
1151 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::getBounds( subset )" );
1152 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex
<< this );
1154 rendering::RenderState
aLocalState( maState
);
1155 uno::Reference
< rendering::XTextLayout
> xTextLayout( mxTextLayout
);
1157 double nDummy0
, nDummy1
;
1158 createSubsetLayout( xTextLayout
,
1165 if( !xTextLayout
.is() )
1166 return ::basegfx::B2DRange(); // empty layout, empty bounds
1168 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1169 xTextLayout
->queryTextBounds() ),
1170 mpCanvas
->getViewState(),
1174 sal_Int32
TextArrayAction::getActionCount() const
1176 const rendering::StringContext
& rOrigContext( mxTextLayout
->getText() );
1178 return rOrigContext
.Length
;
1182 class EffectTextArrayAction
:
1187 EffectTextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1188 const ::basegfx::B2DSize
& rReliefOffset
,
1189 const ::Color
& rReliefColor
,
1190 const ::basegfx::B2DSize
& rShadowOffset
,
1191 const ::Color
& rShadowColor
,
1192 const OUString
& rText
,
1193 sal_Int32 nStartPos
,
1195 const uno::Sequence
< double >& rOffsets
,
1196 VirtualDevice
& rVDev
,
1197 const CanvasSharedPtr
& rCanvas
,
1198 const OutDevState
& rState
);
1199 EffectTextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1200 const ::basegfx::B2DSize
& rReliefOffset
,
1201 const ::Color
& rReliefColor
,
1202 const ::basegfx::B2DSize
& rShadowOffset
,
1203 const ::Color
& rShadowColor
,
1204 const OUString
& rText
,
1205 sal_Int32 nStartPos
,
1207 const uno::Sequence
< double >& rOffsets
,
1208 VirtualDevice
& rVDev
,
1209 const CanvasSharedPtr
& rCanvas
,
1210 const OutDevState
& rState
,
1211 const ::basegfx::B2DHomMatrix
& rTextTransform
);
1213 EffectTextArrayAction(const EffectTextArrayAction
&) = delete;
1214 const EffectTextArrayAction
& operator=(const EffectTextArrayAction
&) = delete;
1216 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1217 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1218 const Subset
& rSubset
) const override
;
1220 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1221 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1222 const Subset
& rSubset
) const override
;
1224 virtual sal_Int32
getActionCount() const override
;
1227 // TextRenderer interface
1228 virtual bool operator()( const rendering::RenderState
& rRenderState
) const override
;
1230 // TODO(P2): This is potentially a real mass object
1231 // (every character might be a separate TextAction),
1232 // thus, make it as lightweight as possible. For
1233 // example, share common RenderState among several
1234 // TextActions, maybe using maOffsets for the
1237 uno::Reference
< rendering::XTextLayout
> mxTextLayout
;
1238 const CanvasSharedPtr mpCanvas
;
1239 rendering::RenderState maState
;
1240 const tools::TextLineInfo maTextLineInfo
;
1241 ::basegfx::B2DSize maLinesOverallSize
;
1242 uno::Reference
< rendering::XPolyPolygon2D
> mxTextLines
;
1243 const ::basegfx::B2DSize maReliefOffset
;
1244 const ::Color maReliefColor
;
1245 const ::basegfx::B2DSize maShadowOffset
;
1246 const ::Color maShadowColor
;
1249 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1250 const ::basegfx::B2DSize
& rReliefOffset
,
1251 const ::Color
& rReliefColor
,
1252 const ::basegfx::B2DSize
& rShadowOffset
,
1253 const ::Color
& rShadowColor
,
1254 const OUString
& rText
,
1255 sal_Int32 nStartPos
,
1257 const uno::Sequence
< double >& rOffsets
,
1258 VirtualDevice
& rVDev
,
1259 const CanvasSharedPtr
& rCanvas
,
1260 const OutDevState
& rState
) :
1262 mpCanvas( rCanvas
),
1264 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
1265 maLinesOverallSize(),
1267 maReliefOffset( rReliefOffset
),
1268 maReliefColor( rReliefColor
),
1269 maShadowOffset( rShadowOffset
),
1270 maShadowColor( rShadowColor
)
1272 initEffectLinePolyPolygon( maLinesOverallSize
,
1278 initArrayAction( maState
,
1289 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1290 const ::basegfx::B2DSize
& rReliefOffset
,
1291 const ::Color
& rReliefColor
,
1292 const ::basegfx::B2DSize
& rShadowOffset
,
1293 const ::Color
& rShadowColor
,
1294 const OUString
& rText
,
1295 sal_Int32 nStartPos
,
1297 const uno::Sequence
< double >& rOffsets
,
1298 VirtualDevice
& rVDev
,
1299 const CanvasSharedPtr
& rCanvas
,
1300 const OutDevState
& rState
,
1301 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
1303 mpCanvas( rCanvas
),
1305 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
1306 maLinesOverallSize(),
1308 maReliefOffset( rReliefOffset
),
1309 maReliefColor( rReliefColor
),
1310 maShadowOffset( rShadowOffset
),
1311 maShadowColor( rShadowColor
)
1313 initEffectLinePolyPolygon( maLinesOverallSize
,
1319 initArrayAction( maState
,
1331 bool EffectTextArrayAction::operator()( const rendering::RenderState
& rRenderState
) const
1333 const rendering::ViewState
& rViewState( mpCanvas
->getViewState() );
1334 const uno::Reference
< rendering::XCanvas
>& rCanvas( mpCanvas
->getUNOCanvas() );
1336 rCanvas
->fillPolyPolygon( mxTextLines
,
1340 rCanvas
->drawTextLayout( mxTextLayout
,
1347 bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1349 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::render()" );
1350 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex
<< this );
1352 rendering::RenderState
aLocalState( maState
);
1353 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1355 return renderEffectText( *this,
1357 mpCanvas
->getViewState(),
1358 mpCanvas
->getUNOCanvas(),
1365 class EffectTextArrayRenderHelper
: public TextRenderer
1368 EffectTextArrayRenderHelper( const uno::Reference
< rendering::XCanvas
>& rCanvas
,
1369 const uno::Reference
< rendering::XTextLayout
>& rTextLayout
,
1370 const uno::Reference
< rendering::XPolyPolygon2D
>& rLinePolygon
,
1371 const rendering::ViewState
& rViewState
) :
1372 mrCanvas( rCanvas
),
1373 mrTextLayout( rTextLayout
),
1374 mrLinePolygon( rLinePolygon
),
1375 mrViewState( rViewState
)
1379 // TextRenderer interface
1380 virtual bool operator()( const rendering::RenderState
& rRenderState
) const override
1382 mrCanvas
->fillPolyPolygon( mrLinePolygon
,
1386 mrCanvas
->drawTextLayout( mrTextLayout
,
1394 const uno::Reference
< rendering::XCanvas
>& mrCanvas
;
1395 const uno::Reference
< rendering::XTextLayout
>& mrTextLayout
;
1396 const uno::Reference
< rendering::XPolyPolygon2D
>& mrLinePolygon
;
1397 const rendering::ViewState
& mrViewState
;
1400 bool EffectTextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1401 const Subset
& rSubset
) const
1403 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::renderSubset()" );
1404 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex
<< this );
1406 rendering::RenderState
aLocalState( maState
);
1407 uno::Reference
< rendering::XTextLayout
> xTextLayout( mxTextLayout
);
1408 const geometry::RealRectangle2D
aTextBounds( mxTextLayout
->queryTextBounds() );
1410 double nMinPos(0.0);
1411 double nMaxPos(aTextBounds
.X2
- aTextBounds
.X1
);
1413 createSubsetLayout( xTextLayout
,
1420 if( !xTextLayout
.is() )
1421 return true; // empty layout, render nothing
1424 // create and setup local line polygon
1425 // ===================================
1427 uno::Reference
< rendering::XCanvas
> xCanvas( mpCanvas
->getUNOCanvas() );
1428 const rendering::ViewState
& rViewState( mpCanvas
->getViewState() );
1430 uno::Reference
< rendering::XPolyPolygon2D
> xTextLines(
1431 ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1432 xCanvas
->getDevice(),
1433 tools::createTextLinesPolyPolygon(
1434 0.0, nMaxPos
- nMinPos
,
1435 maTextLineInfo
) ) );
1438 // render everything
1439 // =================
1441 return renderEffectText(
1442 EffectTextArrayRenderHelper( xCanvas
,
1455 ::basegfx::B2DRange
EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1457 rendering::RenderState
aLocalState( maState
);
1458 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1460 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1461 mxTextLayout
->queryTextBounds() ),
1462 ::basegfx::B2DRange( 0,0,
1463 maLinesOverallSize
.getX(),
1464 maLinesOverallSize
.getY() ),
1468 mpCanvas
->getViewState() );
1471 ::basegfx::B2DRange
EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1472 const Subset
& rSubset
) const
1474 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::getBounds( subset )" );
1475 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex
<< this );
1477 rendering::RenderState
aLocalState( maState
);
1478 uno::Reference
< rendering::XTextLayout
> xTextLayout( mxTextLayout
);
1479 const geometry::RealRectangle2D
aTextBounds( mxTextLayout
->queryTextBounds() );
1481 double nMinPos(0.0);
1482 double nMaxPos(aTextBounds
.X2
- aTextBounds
.X1
);
1484 createSubsetLayout( xTextLayout
,
1491 if( !xTextLayout
.is() )
1492 return ::basegfx::B2DRange(); // empty layout, empty bounds
1495 // create and setup local line polygon
1496 // ===================================
1498 const ::basegfx::B2DPolyPolygon
aPoly(
1499 tools::createTextLinesPolyPolygon(
1500 0.0, nMaxPos
- nMinPos
,
1503 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1504 xTextLayout
->queryTextBounds() ),
1505 ::basegfx::tools::getRange( aPoly
),
1509 mpCanvas
->getViewState() );
1512 sal_Int32
EffectTextArrayAction::getActionCount() const
1514 const rendering::StringContext
& rOrigContext( mxTextLayout
->getText() );
1516 return rOrigContext
.Length
;
1520 class OutlineAction
:
1525 OutlineAction( const ::basegfx::B2DPoint
& rStartPoint
,
1526 const ::basegfx::B2DSize
& rReliefOffset
,
1527 const ::Color
& rReliefColor
,
1528 const ::basegfx::B2DSize
& rShadowOffset
,
1529 const ::Color
& rShadowColor
,
1530 const ::basegfx::B2DRectangle
& rOutlineBounds
,
1531 const uno::Reference
< rendering::XPolyPolygon2D
>& rTextPoly
,
1532 const uno::Sequence
< double >& rOffsets
,
1533 VirtualDevice
& rVDev
,
1534 const CanvasSharedPtr
& rCanvas
,
1535 const OutDevState
& rState
);
1536 OutlineAction( const ::basegfx::B2DPoint
& rStartPoint
,
1537 const ::basegfx::B2DSize
& rReliefOffset
,
1538 const ::Color
& rReliefColor
,
1539 const ::basegfx::B2DSize
& rShadowOffset
,
1540 const ::Color
& rShadowColor
,
1541 const ::basegfx::B2DRectangle
& rOutlineBounds
,
1542 const uno::Reference
< rendering::XPolyPolygon2D
>& rTextPoly
,
1543 const uno::Sequence
< double >& rOffsets
,
1544 VirtualDevice
& rVDev
,
1545 const CanvasSharedPtr
& rCanvas
,
1546 const OutDevState
& rState
,
1547 const ::basegfx::B2DHomMatrix
& rTextTransform
);
1549 OutlineAction(const OutlineAction
&) = delete;
1550 const OutlineAction
& operator=(const OutlineAction
&) = delete;
1552 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1553 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1554 const Subset
& rSubset
) const override
;
1556 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1557 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1558 const Subset
& rSubset
) const override
;
1560 virtual sal_Int32
getActionCount() const override
;
1563 // TextRenderer interface
1564 virtual bool operator()( const rendering::RenderState
& rRenderState
) const override
;
1566 // TODO(P2): This is potentially a real mass object
1567 // (every character might be a separate TextAction),
1568 // thus, make it as lightweight as possible. For
1569 // example, share common RenderState among several
1570 // TextActions, maybe using maOffsets for the
1573 uno::Reference
< rendering::XPolyPolygon2D
> mxTextPoly
;
1575 const uno::Sequence
< double > maOffsets
;
1576 const CanvasSharedPtr mpCanvas
;
1577 rendering::RenderState maState
;
1578 double mnOutlineWidth
;
1579 const uno::Sequence
< double > maFillColor
;
1580 const tools::TextLineInfo maTextLineInfo
;
1581 ::basegfx::B2DSize maLinesOverallSize
;
1582 const ::basegfx::B2DRectangle maOutlineBounds
;
1583 uno::Reference
< rendering::XPolyPolygon2D
> mxTextLines
;
1584 const ::basegfx::B2DSize maReliefOffset
;
1585 const ::Color maReliefColor
;
1586 const ::basegfx::B2DSize maShadowOffset
;
1587 const ::Color maShadowColor
;
1590 double calcOutlineWidth( const OutDevState
& rState
,
1591 VirtualDevice
& rVDev
)
1593 const ::basegfx::B2DSize
aFontSize( 0,
1594 rVDev
.GetFont().GetFontHeight() / 64.0 );
1596 const double nOutlineWidth(
1597 (rState
.mapModeTransform
* aFontSize
).getY() );
1599 return nOutlineWidth
< 1.0 ? 1.0 : nOutlineWidth
;
1602 OutlineAction::OutlineAction( const ::basegfx::B2DPoint
& rStartPoint
,
1603 const ::basegfx::B2DSize
& rReliefOffset
,
1604 const ::Color
& rReliefColor
,
1605 const ::basegfx::B2DSize
& rShadowOffset
,
1606 const ::Color
& rShadowColor
,
1607 const ::basegfx::B2DRectangle
& rOutlineBounds
,
1608 const uno::Reference
< rendering::XPolyPolygon2D
>& rTextPoly
,
1609 const uno::Sequence
< double >& rOffsets
,
1610 VirtualDevice
& rVDev
,
1611 const CanvasSharedPtr
& rCanvas
,
1612 const OutDevState
& rState
) :
1613 mxTextPoly( rTextPoly
),
1614 maOffsets( rOffsets
),
1615 mpCanvas( rCanvas
),
1617 mnOutlineWidth( calcOutlineWidth(rState
,rVDev
) ),
1619 vcl::unotools::colorToDoubleSequence(
1620 ::Color( COL_WHITE
),
1621 rCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1622 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
1623 maLinesOverallSize(),
1624 maOutlineBounds( rOutlineBounds
),
1626 maReliefOffset( rReliefOffset
),
1627 maReliefColor( rReliefColor
),
1628 maShadowOffset( rShadowOffset
),
1629 maShadowColor( rShadowColor
)
1631 initEffectLinePolyPolygon( maLinesOverallSize
,
1643 OutlineAction::OutlineAction( const ::basegfx::B2DPoint
& rStartPoint
,
1644 const ::basegfx::B2DSize
& rReliefOffset
,
1645 const ::Color
& rReliefColor
,
1646 const ::basegfx::B2DSize
& rShadowOffset
,
1647 const ::Color
& rShadowColor
,
1648 const ::basegfx::B2DRectangle
& rOutlineBounds
,
1649 const uno::Reference
< rendering::XPolyPolygon2D
>& rTextPoly
,
1650 const uno::Sequence
< double >& rOffsets
,
1651 VirtualDevice
& rVDev
,
1652 const CanvasSharedPtr
& rCanvas
,
1653 const OutDevState
& rState
,
1654 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
1655 mxTextPoly( rTextPoly
),
1656 maOffsets( rOffsets
),
1657 mpCanvas( rCanvas
),
1659 mnOutlineWidth( calcOutlineWidth(rState
,rVDev
) ),
1661 vcl::unotools::colorToDoubleSequence(
1662 ::Color( COL_WHITE
),
1663 rCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1664 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
1665 maLinesOverallSize(),
1666 maOutlineBounds( rOutlineBounds
),
1668 maReliefOffset( rReliefOffset
),
1669 maReliefColor( rReliefColor
),
1670 maShadowOffset( rShadowOffset
),
1671 maShadowColor( rShadowColor
)
1673 initEffectLinePolyPolygon( maLinesOverallSize
,
1686 bool OutlineAction::operator()( const rendering::RenderState
& rRenderState
) const
1688 const rendering::ViewState
& rViewState( mpCanvas
->getViewState() );
1689 const uno::Reference
< rendering::XCanvas
>& rCanvas( mpCanvas
->getUNOCanvas() );
1691 rendering::StrokeAttributes aStrokeAttributes
;
1693 aStrokeAttributes
.StrokeWidth
= mnOutlineWidth
;
1694 aStrokeAttributes
.MiterLimit
= 1.0;
1695 aStrokeAttributes
.StartCapType
= rendering::PathCapType::BUTT
;
1696 aStrokeAttributes
.EndCapType
= rendering::PathCapType::BUTT
;
1697 aStrokeAttributes
.JoinType
= rendering::PathJoinType::MITER
;
1699 rendering::RenderState
aLocalState( rRenderState
);
1700 aLocalState
.DeviceColor
= maFillColor
;
1702 // TODO(P1): implement caching
1704 // background of text
1705 rCanvas
->fillPolyPolygon( mxTextPoly
,
1709 // border line of text
1710 rCanvas
->strokePolyPolygon( mxTextPoly
,
1713 aStrokeAttributes
);
1715 // underlines/strikethrough - background
1716 rCanvas
->fillPolyPolygon( mxTextLines
,
1719 // underlines/strikethrough - border
1720 rCanvas
->strokePolyPolygon( mxTextLines
,
1723 aStrokeAttributes
);
1728 bool OutlineAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1730 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::render()" );
1731 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex
<< this );
1733 rendering::RenderState
aLocalState( maState
);
1734 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1736 return renderEffectText( *this,
1738 mpCanvas
->getViewState(),
1739 mpCanvas
->getUNOCanvas(),
1746 #if 0 // see #if'ed out use in OutlineAction::renderSubset below:
1747 class OutlineTextArrayRenderHelper
: public TextRenderer
1750 OutlineTextArrayRenderHelper( const uno::Reference
< rendering::XCanvas
>& rCanvas
,
1751 const uno::Reference
< rendering::XPolyPolygon2D
>& rTextPolygon
,
1752 const uno::Reference
< rendering::XPolyPolygon2D
>& rLinePolygon
,
1753 const rendering::ViewState
& rViewState
,
1754 double nOutlineWidth
) :
1756 vcl::unotools::colorToDoubleSequence(
1757 ::Color( COL_WHITE
),
1758 rCanvas
->getDevice()->getDeviceColorSpace() )),
1759 mnOutlineWidth( nOutlineWidth
),
1760 mrCanvas( rCanvas
),
1761 mrTextPolygon( rTextPolygon
),
1762 mrLinePolygon( rLinePolygon
),
1763 mrViewState( rViewState
)
1767 // TextRenderer interface
1768 virtual bool operator()( const rendering::RenderState
& rRenderState
) const
1770 rendering::StrokeAttributes aStrokeAttributes
;
1772 aStrokeAttributes
.StrokeWidth
= mnOutlineWidth
;
1773 aStrokeAttributes
.MiterLimit
= 1.0;
1774 aStrokeAttributes
.StartCapType
= rendering::PathCapType::BUTT
;
1775 aStrokeAttributes
.EndCapType
= rendering::PathCapType::BUTT
;
1776 aStrokeAttributes
.JoinType
= rendering::PathJoinType::MITER
;
1778 rendering::RenderState
aLocalState( rRenderState
);
1779 aLocalState
.DeviceColor
= maFillColor
;
1781 // TODO(P1): implement caching
1783 // background of text
1784 mrCanvas
->fillPolyPolygon( mrTextPolygon
,
1788 // border line of text
1789 mrCanvas
->strokePolyPolygon( mrTextPolygon
,
1792 aStrokeAttributes
);
1794 // underlines/strikethrough - background
1795 mrCanvas
->fillPolyPolygon( mrLinePolygon
,
1798 // underlines/strikethrough - border
1799 mrCanvas
->strokePolyPolygon( mrLinePolygon
,
1802 aStrokeAttributes
);
1808 const uno::Sequence
< double > maFillColor
;
1809 double mnOutlineWidth
;
1810 const uno::Reference
< rendering::XCanvas
>& mrCanvas
;
1811 const uno::Reference
< rendering::XPolyPolygon2D
>& mrTextPolygon
;
1812 const uno::Reference
< rendering::XPolyPolygon2D
>& mrLinePolygon
;
1813 const rendering::ViewState
& mrViewState
;
1817 bool OutlineAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1818 const Subset
& rSubset
) const
1820 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction::renderSubset()" );
1821 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction: 0x" << std::hex
<< this );
1823 if( rSubset
.mnSubsetBegin
== rSubset
.mnSubsetEnd
)
1824 return true; // empty range, render nothing
1827 // TODO(F3): Subsetting NYI for outline text!
1828 return render( rTransformation
);
1830 const rendering::StringContext
rOrigContext( mxTextLayout
->getText() );
1832 if( rSubset
.mnSubsetBegin
== 0 &&
1833 rSubset
.mnSubsetEnd
== rOrigContext
.Length
)
1835 // full range, no need for subsetting
1836 return render( rTransformation
);
1839 rendering::RenderState
aLocalState( maState
);
1840 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1843 // create and setup local Text polygon
1844 // ===================================
1846 uno::Reference
< rendering::XPolyPolygon2D
> xTextPolygon();
1848 // TODO(P3): Provide an API method for that!
1850 if( !xTextLayout
.is() )
1853 // render everything
1854 // =================
1856 return renderEffectText(
1857 OutlineTextArrayRenderHelper(
1873 ::basegfx::B2DRange
OutlineAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1875 rendering::RenderState
aLocalState( maState
);
1876 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1878 return calcEffectTextBounds( maOutlineBounds
,
1879 ::basegfx::B2DRange( 0,0,
1880 maLinesOverallSize
.getX(),
1881 maLinesOverallSize
.getY() ),
1885 mpCanvas
->getViewState() );
1888 ::basegfx::B2DRange
OutlineAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1889 const Subset
& /*rSubset*/ ) const
1891 SAL_WARN( "cppcanvas.emf", "OutlineAction::getBounds(): Subset not yet supported by this object" );
1893 return getBounds( rTransformation
);
1896 sal_Int32
OutlineAction::getActionCount() const
1898 // TODO(F3): Subsetting NYI for outline text!
1899 return maOffsets
.getLength();
1903 // Action factory methods
1906 /** Create an outline action
1908 This method extracts the polygonal outline from the
1909 text, and creates a properly setup OutlineAction from
1912 ActionSharedPtr
createOutline( const ::basegfx::B2DPoint
& rStartPoint
,
1913 const ::basegfx::B2DSize
& rReliefOffset
,
1914 const ::Color
& rReliefColor
,
1915 const ::basegfx::B2DSize
& rShadowOffset
,
1916 const ::Color
& rShadowColor
,
1917 const OUString
& rText
,
1918 sal_Int32 nStartPos
,
1920 const long* pDXArray
,
1921 VirtualDevice
& rVDev
,
1922 const CanvasSharedPtr
& rCanvas
,
1923 const OutDevState
& rState
,
1924 const Renderer::Parameters
& rParms
)
1926 // operate on raw DX array here (in logical coordinate
1927 // system), to have a higher resolution
1928 // PolyPolygon. That polygon is then converted to
1929 // device coordinate system.
1931 // #i68512# Temporarily switch off font rotation
1932 // (which is already contained in the render state
1933 // transformation matrix - otherwise, glyph polygons
1934 // will be rotated twice)
1935 const vcl::Font
aOrigFont( rVDev
.GetFont() );
1936 vcl::Font
aUnrotatedFont( aOrigFont
);
1937 aUnrotatedFont
.SetOrientation(0);
1938 rVDev
.SetFont( aUnrotatedFont
);
1940 // TODO(F3): Don't understand parameter semantics of
1941 // GetTextOutlines()
1942 ::basegfx::B2DPolyPolygon aResultingPolyPolygon
;
1943 PolyPolyVector aVCLPolyPolyVector
;
1944 const bool bHaveOutlines( rVDev
.GetTextOutlines( aVCLPolyPolyVector
, rText
,
1945 static_cast<sal_uInt16
>(nStartPos
),
1946 static_cast<sal_uInt16
>(nStartPos
),
1947 static_cast<sal_uInt16
>(nLen
),
1949 rVDev
.SetFont(aOrigFont
);
1951 if( !bHaveOutlines
)
1952 return ActionSharedPtr();
1954 // remove offsetting from mapmode transformation
1955 // (outline polygons must stay at origin, only need to
1957 ::basegfx::B2DHomMatrix
aMapModeTransform(
1958 rState
.mapModeTransform
);
1959 aMapModeTransform
.set(0,2, 0.0);
1960 aMapModeTransform
.set(1,2, 0.0);
1962 PolyPolyVector::const_iterator
aIter( aVCLPolyPolyVector
.begin() );
1963 const PolyPolyVector::const_iterator
aEnd( aVCLPolyPolyVector
.end() );
1964 for( ; aIter
!= aEnd
; ++aIter
)
1966 ::basegfx::B2DPolyPolygon aPolyPolygon
;
1968 aPolyPolygon
= aIter
->getB2DPolyPolygon();
1969 aPolyPolygon
.transform( aMapModeTransform
);
1971 // append result to collecting polypoly
1972 for( sal_uInt32 i
=0; i
<aPolyPolygon
.count(); ++i
)
1974 // #i47795# Ensure closed polygons (since
1975 // FreeType returns the glyph outlines
1977 const ::basegfx::B2DPolygon
& rPoly( aPolyPolygon
.getB2DPolygon( i
) );
1978 const sal_uInt32
nCount( rPoly
.count() );
1982 // polygon either degenerate, or
1984 aResultingPolyPolygon
.append( rPoly
);
1988 ::basegfx::B2DPolygon
aPoly(rPoly
);
1989 aPoly
.setClosed(true);
1991 aResultingPolyPolygon
.append( aPoly
);
1996 const uno::Sequence
< double > aCharWidthSeq(
1998 setupDXArray( pDXArray
, nLen
, rState
) :
1999 setupDXArray( rText
,
2004 const uno::Reference
< rendering::XPolyPolygon2D
> xTextPoly(
2005 ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
2006 rCanvas
->getUNOCanvas()->getDevice(),
2007 aResultingPolyPolygon
) );
2009 if( rParms
.maTextTransformation
.is_initialized() )
2011 return ActionSharedPtr(
2018 ::basegfx::tools::getRange(aResultingPolyPolygon
),
2024 *rParms
.maTextTransformation
) );
2028 return ActionSharedPtr(
2035 ::basegfx::tools::getRange(aResultingPolyPolygon
),
2047 ActionSharedPtr
TextActionFactory::createTextAction( const ::Point
& rStartPoint
,
2048 const ::Size
& rReliefOffset
,
2049 const ::Color
& rReliefColor
,
2050 const ::Size
& rShadowOffset
,
2051 const ::Color
& rShadowColor
,
2052 const OUString
& rText
,
2053 sal_Int32 nStartPos
,
2055 const long* pDXArray
,
2056 VirtualDevice
& rVDev
,
2057 const CanvasSharedPtr
& rCanvas
,
2058 const OutDevState
& rState
,
2059 const Renderer::Parameters
& rParms
,
2062 const ::Size
aBaselineOffset( tools::getBaselineOffset( rState
,
2064 // #143885# maintain (nearly) full precision positioning,
2065 // by circumventing integer-based OutDev-mapping
2066 const ::basegfx::B2DPoint
aStartPoint(
2067 rState
.mapModeTransform
*
2068 ::basegfx::B2DPoint(rStartPoint
.X() + aBaselineOffset
.Width(),
2069 rStartPoint
.Y() + aBaselineOffset
.Height()) );
2071 const ::basegfx::B2DSize
aReliefOffset(
2072 rState
.mapModeTransform
* vcl::unotools::b2DSizeFromSize( rReliefOffset
) );
2073 const ::basegfx::B2DSize
aShadowOffset(
2074 rState
.mapModeTransform
* vcl::unotools::b2DSizeFromSize( rShadowOffset
) );
2076 if( rState
.isTextOutlineModeSet
)
2078 return createOutline(
2094 // convert DX array to device coordinate system (and
2095 // create it in the first place, if pDXArray is NULL)
2096 const uno::Sequence
< double > aCharWidths(
2098 setupDXArray( pDXArray
, nLen
, rState
) :
2099 setupDXArray( rText
,
2105 // determine type of text action to create
2106 // =======================================
2108 const ::Color
aEmptyColor( COL_AUTO
);
2110 ActionSharedPtr ret
;
2112 // no DX array, and no need to subset - no need to store
2114 if( !pDXArray
&& !bSubsettable
)
2117 if( !rState
.textOverlineStyle
&&
2118 !rState
.textUnderlineStyle
&&
2119 !rState
.textStrikeoutStyle
&&
2120 rReliefColor
== aEmptyColor
&&
2121 rShadowColor
== aEmptyColor
)
2124 if( rParms
.maTextTransformation
.is_initialized() )
2126 ret
= ActionSharedPtr( new TextAction(
2133 *rParms
.maTextTransformation
) );
2137 ret
= ActionSharedPtr( new TextAction(
2148 // at least one of the effects requested
2149 if( rParms
.maTextTransformation
.is_initialized() )
2150 ret
= ActionSharedPtr( new EffectTextAction(
2162 *rParms
.maTextTransformation
) );
2164 ret
= ActionSharedPtr( new EffectTextAction(
2180 // DX array necessary - any effects?
2181 if( !rState
.textOverlineStyle
&&
2182 !rState
.textUnderlineStyle
&&
2183 !rState
.textStrikeoutStyle
&&
2184 rReliefColor
== aEmptyColor
&&
2185 rShadowColor
== aEmptyColor
)
2188 if( rParms
.maTextTransformation
.is_initialized() )
2189 ret
= ActionSharedPtr( new TextArrayAction(
2197 *rParms
.maTextTransformation
) );
2199 ret
= ActionSharedPtr( new TextArrayAction(
2210 // at least one of the effects requested
2211 if( rParms
.maTextTransformation
.is_initialized() )
2212 ret
= ActionSharedPtr( new EffectTextArrayAction(
2225 *rParms
.maTextTransformation
) );
2227 ret
= ActionSharedPtr( new EffectTextArrayAction(
2247 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */