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/matrix/b2dhommatrix.hxx>
29 #include <basegfx/range/b2drectangle.hxx>
30 #include <basegfx/vector/b2dsize.hxx>
31 #include <basegfx/polygon/b2dpolypolygontools.hxx>
32 #include <basegfx/polygon/b2dpolygontools.hxx>
33 #include <basegfx/matrix/b2dhommatrixtools.hxx>
35 #include <tools/gen.hxx>
36 #include <vcl/canvastools.hxx>
37 #include <vcl/virdev.hxx>
39 #include <basegfx/utils/canvastools.hxx>
40 #include <canvas/canvastools.hxx>
42 #include <sal/log.hxx>
44 #include "textaction.hxx"
45 #include "textlineshelper.hxx"
46 #include <outdevstate.hxx>
47 #include "mtftools.hxx"
50 using namespace ::com::sun::star
;
52 namespace cppcanvas::internal
56 void init( rendering::RenderState
& o_rRenderState
,
57 const ::basegfx::B2DPoint
& rStartPoint
,
58 const OutDevState
& rState
,
59 const CanvasSharedPtr
& rCanvas
)
61 tools::initRenderState(o_rRenderState
,rState
);
63 // #i36950# Offset clip back to origin (as it's also moved
65 // #i53964# Also take VCL font rotation into account,
66 // since this, opposed to the FontMatrix rotation
67 // elsewhere, _does_ get incorporated into the render
69 tools::modifyClip( o_rRenderState
,
74 &rState
.fontRotation
);
76 basegfx::B2DHomMatrix
aLocalTransformation(basegfx::utils::createRotateB2DHomMatrix(rState
.fontRotation
));
77 aLocalTransformation
.translate( rStartPoint
.getX(),
79 ::canvas::tools::appendToRenderState( o_rRenderState
,
80 aLocalTransformation
);
82 o_rRenderState
.DeviceColor
= rState
.textColor
;
85 void init( rendering::RenderState
& o_rRenderState
,
86 const ::basegfx::B2DPoint
& rStartPoint
,
87 const OutDevState
& rState
,
88 const CanvasSharedPtr
& rCanvas
,
89 const ::basegfx::B2DHomMatrix
& rTextTransform
)
91 init( o_rRenderState
, rStartPoint
, rState
, rCanvas
);
93 // TODO(F2): Also inversely-transform clip with
94 // rTextTransform (which is actually rather hard, as the
95 // text transform is _prepended_ to the render state)!
97 // prepend extra font transform to render state
98 // (prepend it, because it's interpreted in the unit
99 // rect coordinate space)
100 ::canvas::tools::prependToRenderState( o_rRenderState
,
104 void init( rendering::RenderState
& o_rRenderState
,
105 uno::Reference
< rendering::XCanvasFont
>& o_rFont
,
106 const ::basegfx::B2DPoint
& rStartPoint
,
107 const OutDevState
& rState
,
108 const CanvasSharedPtr
& rCanvas
)
110 // ensure that o_rFont is valid. It is possible that
111 // text actions are generated without previously
112 // setting a font. Then, just take a default font
115 // Use completely default FontRequest
116 const rendering::FontRequest aFontRequest
;
118 geometry::Matrix2D aFontMatrix
;
119 ::canvas::tools::setIdentityMatrix2D( aFontMatrix
);
121 o_rFont
= rCanvas
->getUNOCanvas()->createFont(
123 uno::Sequence
< beans::PropertyValue
>(),
127 init( o_rRenderState
,
133 void init( rendering::RenderState
& o_rRenderState
,
134 uno::Reference
< rendering::XCanvasFont
>& o_rFont
,
135 const ::basegfx::B2DPoint
& rStartPoint
,
136 const OutDevState
& rState
,
137 const CanvasSharedPtr
& rCanvas
,
138 const ::basegfx::B2DHomMatrix
& rTextTransform
)
140 init( o_rRenderState
, o_rFont
, rStartPoint
, rState
, rCanvas
);
142 // TODO(F2): Also inversely-transform clip with
143 // rTextTransform (which is actually rather hard, as the
144 // text transform is _prepended_ to the render state)!
146 // prepend extra font transform to render state
147 // (prepend it, because it's interpreted in the unit
148 // rect coordinate space)
149 ::canvas::tools::prependToRenderState( o_rRenderState
,
153 void initLayoutWidth(double& rLayoutWidth
, const uno::Sequence
<double>& rOffsets
)
155 ENSURE_OR_THROW(rOffsets
.hasElements(),
156 "::cppcanvas::internal::initLayoutWidth(): zero-length array" );
157 rLayoutWidth
= *(std::max_element(rOffsets
.begin(), rOffsets
.end()));
160 uno::Sequence
< double > setupDXArray( const ::tools::Long
* pCharWidths
,
162 const OutDevState
& rState
)
164 // convert character widths from logical units
165 uno::Sequence
< double > aCharWidthSeq( nLen
);
166 double* pOutputWidths( aCharWidthSeq
.getArray() );
168 // #143885# maintain (nearly) full precision of DX
169 // array, by circumventing integer-based
171 const double nScale( rState
.mapModeTransform
.get(0,0) );
172 for( int i
= 0; i
< nLen
; ++i
)
174 // TODO(F2): use correct scale direction
175 *pOutputWidths
++ = *pCharWidths
++ * nScale
;
178 return aCharWidthSeq
;
181 uno::Sequence
< double > setupDXArray( const OUString
& rText
,
184 VirtualDevice
const & rVDev
,
185 const OutDevState
& rState
)
187 // no external DX array given, create one from given
189 std::unique_ptr
< ::tools::Long
[]> pCharWidths( new ::tools::Long
[nLen
] );
191 rVDev
.GetTextArray( rText
, pCharWidths
.get(),
194 return setupDXArray( pCharWidths
.get(), nLen
, rState
);
197 ::basegfx::B2DPoint
adaptStartPoint( const ::basegfx::B2DPoint
& rStartPoint
,
198 const OutDevState
& rState
,
199 const uno::Sequence
< double >& rOffsets
)
201 ::basegfx::B2DPoint
aLocalPoint( rStartPoint
);
203 if( rState
.textAlignment
)
205 // text origin is right, not left. Modify start point
206 // accordingly, because XCanvas::drawTextLayout()
207 // always aligns left!
209 const double nOffset( rOffsets
[ rOffsets
.getLength()-1 ] );
211 // correct start point for rotated text: rotate around
212 // former start point
213 aLocalPoint
.setX( aLocalPoint
.getX() + cos( rState
.fontRotation
)*nOffset
);
214 aLocalPoint
.setY( aLocalPoint
.getY() + sin( rState
.fontRotation
)*nOffset
);
220 /** Perform common setup for array text actions
222 This method creates the XTextLayout object and
223 initializes it, e.g. with the logical advancements.
225 void initArrayAction( rendering::RenderState
& o_rRenderState
,
226 uno::Reference
< rendering::XTextLayout
>& o_rTextLayout
,
227 const ::basegfx::B2DPoint
& rStartPoint
,
228 const OUString
& rText
,
231 const uno::Sequence
< double >& rOffsets
,
232 const CanvasSharedPtr
& rCanvas
,
233 const OutDevState
& rState
,
234 const ::basegfx::B2DHomMatrix
* pTextTransform
)
236 ENSURE_OR_THROW( rOffsets
.hasElements(),
237 "::cppcanvas::internal::initArrayAction(): zero-length DX array" );
239 const ::basegfx::B2DPoint
aLocalStartPoint(
240 adaptStartPoint( rStartPoint
, rState
, rOffsets
) );
242 uno::Reference
< rendering::XCanvasFont
> xFont( rState
.xFont
);
245 init( o_rRenderState
, xFont
, aLocalStartPoint
, rState
, rCanvas
, *pTextTransform
);
247 init( o_rRenderState
, xFont
, aLocalStartPoint
, rState
, rCanvas
);
249 o_rTextLayout
= xFont
->createTextLayout(
250 rendering::StringContext( rText
, nStartPos
, nLen
),
251 rState
.textDirection
,
254 ENSURE_OR_THROW( o_rTextLayout
.is(),
255 "::cppcanvas::internal::initArrayAction(): Invalid font" );
257 o_rTextLayout
->applyLogicalAdvancements( rOffsets
);
261 double getLineWidth( ::VirtualDevice
const & rVDev
,
262 const OutDevState
& rState
,
263 const rendering::StringContext
& rStringContext
)
265 // TODO(F2): use correct scale direction
266 const ::basegfx::B2DSize
aSize( rVDev
.GetTextWidth( rStringContext
.Text
,
267 static_cast<sal_uInt16
>(rStringContext
.StartPosition
),
268 static_cast<sal_uInt16
>(rStringContext
.Length
) ),
271 return (rState
.mapModeTransform
* aSize
).getX();
274 uno::Sequence
< double >
275 calcSubsetOffsets( rendering::RenderState
& io_rRenderState
,
278 const uno::Reference
< rendering::XTextLayout
>& rOrigTextLayout
,
280 const ::cppcanvas::internal::Action::Subset
& rSubset
)
282 ENSURE_OR_THROW( rSubset
.mnSubsetEnd
> rSubset
.mnSubsetBegin
,
283 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
285 uno::Sequence
< double > aOrigOffsets( rOrigTextLayout
->queryLogicalAdvancements() );
286 const double* pOffsets( aOrigOffsets
.getConstArray() );
288 ENSURE_OR_THROW( aOrigOffsets
.getLength() >= rSubset
.mnSubsetEnd
,
289 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
292 // determine leftmost position in given subset range -
293 // as the DX array contains the output positions
294 // starting with the second character (the first is
295 // assumed to have output position 0), correct begin
297 const double nMinPos( rSubset
.mnSubsetBegin
<= 0 ? 0 :
298 *(std::min_element( pOffsets
+rSubset
.mnSubsetBegin
-1,
299 pOffsets
+rSubset
.mnSubsetEnd
)) );
301 // determine rightmost position in given subset range
302 // - as the DX array contains the output positions
303 // starting with the second character (the first is
304 // assumed to have output position 0), correct begin
306 const double nMaxPos(
307 *(std::max_element( pOffsets
+ (rSubset
.mnSubsetBegin
<= 0 ?
308 0 : rSubset
.mnSubsetBegin
-1),
309 pOffsets
+ rSubset
.mnSubsetEnd
)) );
311 // Logical advancements always increase in logical text order.
312 // For RTL text, nMaxPos is the distance from the right edge to
313 // the leftmost position in the subset, so we have to convert
314 // it to the offset from the origin (i.e. left edge ).
315 // LTR: |---- min --->|---- max --->| |
316 // RTL: | |<--- max ----|<--- min ---|
318 const double nOffset
= rOrigTextLayout
->getMainTextDirection()
319 ? nLayoutWidth
- nMaxPos
: nMinPos
;
322 // adapt render state, to move text output to given offset
325 // TODO(F1): Strictly speaking, we also have to adapt
326 // the clip here, which normally should _not_ move
327 // with the output offset. Neglected for now, as it
328 // does not matter for drawing layer output
332 ::basegfx::B2DHomMatrix aTranslation
;
333 if( rOrigTextLayout
->getFont()->getFontRequest().FontDescription
.IsVertical
== css::util::TriState_YES
)
335 // vertical text -> offset in y direction
336 aTranslation
.translate(0.0, nOffset
);
340 // horizontal text -> offset in x direction
341 aTranslation
.translate(nOffset
, 0.0);
344 ::canvas::tools::appendToRenderState( io_rRenderState
,
349 // reduce DX array to given substring
352 const sal_Int32
nNewElements( rSubset
.mnSubsetEnd
- rSubset
.mnSubsetBegin
);
353 uno::Sequence
< double > aAdaptedOffsets( nNewElements
);
354 double* pAdaptedOffsets( aAdaptedOffsets
.getArray() );
356 // move to new output position (subtract nMinPos,
357 // which is the new '0' position), copy only the range
358 // as given by rSubset.
359 std::transform( pOffsets
+ rSubset
.mnSubsetBegin
,
360 pOffsets
+ rSubset
.mnSubsetEnd
,
362 [nMinPos
](double aPos
) { return aPos
- nMinPos
; } );
367 return aAdaptedOffsets
;
370 uno::Reference
< rendering::XTextLayout
>
371 createSubsetLayout( const rendering::StringContext
& rOrigContext
,
372 const ::cppcanvas::internal::Action::Subset
& rSubset
,
373 const uno::Reference
< rendering::XTextLayout
>& rOrigTextLayout
)
375 // create temporary new text layout with subset string
378 const sal_Int32
nNewStartPos( rOrigContext
.StartPosition
+ std::min(
379 rSubset
.mnSubsetBegin
, rOrigContext
.Length
-1 ) );
380 const sal_Int32
nNewLength( std::max(
382 rSubset
.mnSubsetEnd
- rSubset
.mnSubsetBegin
,
383 rOrigContext
.Length
),
386 const rendering::StringContext
aContext( rOrigContext
.Text
,
390 uno::Reference
< rendering::XTextLayout
> xTextLayout(
391 rOrigTextLayout
->getFont()->createTextLayout( aContext
,
392 rOrigTextLayout
->getMainTextDirection(),
394 uno::UNO_SET_THROW
);
399 /** Setup subset text layout
401 @param io_rTextLayout
402 Must contain original (full set) text layout on input,
403 will contain subsetted text layout (or empty
404 reference, for empty subsets) on output.
406 @param io_rRenderState
407 Must contain original render state on input, will
408 contain shifted render state concatenated with
409 rTransformation on output.
411 @param rTransformation
412 Additional transformation, to be prepended to render
418 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
,
462 io_rTextLayout
= xTextLayout
;
466 /** Interface for renderEffectText functor below.
468 This is interface is used from the renderEffectText()
469 method below, to call the client implementation.
474 virtual ~TextRenderer() {}
476 /// Render text with given RenderState
477 virtual bool operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
, bool bNormalText
) const = 0;
480 /** Render effect text.
483 Functor object, will be called to render the actual
484 part of the text effect (the text itself and the means
485 to render it are unknown to this method)
487 bool renderEffectText( const TextRenderer
& rRenderer
,
488 const rendering::RenderState
& rRenderState
,
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
,
494 const ::Color
& rTextFillColor
)
496 ::Color
aEmptyColor( COL_AUTO
);
497 uno::Reference
<rendering::XColorSpace
> xColorSpace(
498 xCanvas
->getDevice()->getDeviceColorSpace() );
500 // draw shadow text, if enabled
501 if( rShadowColor
!= aEmptyColor
)
503 rendering::RenderState
aShadowState( rRenderState
);
504 ::basegfx::B2DHomMatrix aTranslate
;
506 aTranslate
.translate( rShadowOffset
.getX(),
507 rShadowOffset
.getY() );
509 ::canvas::tools::appendToRenderState(aShadowState
, aTranslate
);
511 aShadowState
.DeviceColor
=
512 vcl::unotools::colorToDoubleSequence( rShadowColor
,
515 rRenderer( aShadowState
, rTextFillColor
, false );
518 // draw relief text, if enabled
519 if( rReliefColor
!= aEmptyColor
)
521 rendering::RenderState
aReliefState( rRenderState
);
522 ::basegfx::B2DHomMatrix aTranslate
;
524 aTranslate
.translate( rReliefOffset
.getX(),
525 rReliefOffset
.getY() );
527 ::canvas::tools::appendToRenderState(aReliefState
, aTranslate
);
529 aReliefState
.DeviceColor
=
530 vcl::unotools::colorToDoubleSequence( rReliefColor
,
533 rRenderer( aReliefState
, rTextFillColor
, false );
537 rRenderer( rRenderState
, rTextFillColor
, true );
543 ::basegfx::B2DRange
calcEffectTextBounds( const ::basegfx::B2DRange
& rTextBounds
,
544 const ::basegfx::B2DRange
& rLineBounds
,
545 const ::basegfx::B2DSize
& rReliefOffset
,
546 const ::basegfx::B2DSize
& rShadowOffset
,
547 const rendering::RenderState
& rRenderState
,
548 const rendering::ViewState
& rViewState
)
550 ::basegfx::B2DRange
aBounds( rTextBounds
);
552 // add extends of text lines
553 aBounds
.expand( rLineBounds
);
555 // TODO(Q3): Provide this functionality at the B2DRange
556 ::basegfx::B2DRange
aTotalBounds( aBounds
);
558 ::basegfx::B2DRange( aBounds
.getMinX() + rReliefOffset
.getX(),
559 aBounds
.getMinY() + rReliefOffset
.getY(),
560 aBounds
.getMaxX() + rReliefOffset
.getX(),
561 aBounds
.getMaxY() + rReliefOffset
.getY() ) );
563 ::basegfx::B2DRange( aBounds
.getMinX() + rShadowOffset
.getX(),
564 aBounds
.getMinY() + rShadowOffset
.getY(),
565 aBounds
.getMaxX() + rShadowOffset
.getX(),
566 aBounds
.getMaxY() + rShadowOffset
.getY() ) );
568 return tools::calcDevicePixelBounds( aTotalBounds
,
573 void initEffectLinePolyPolygon( ::basegfx::B2DSize
& o_rOverallSize
,
574 uno::Reference
< rendering::XPolyPolygon2D
>& o_rTextLines
,
575 const CanvasSharedPtr
& rCanvas
,
577 const tools::TextLineInfo
& rLineInfo
)
579 const ::basegfx::B2DPolyPolygon
aPoly(
580 tools::createTextLinesPolyPolygon( 0.0, nLineWidth
,
583 o_rOverallSize
= ::basegfx::utils::getRange( aPoly
).getRange();
585 o_rTextLines
= ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
586 rCanvas
->getUNOCanvas()->getDevice(),
591 class TextAction
: public Action
594 TextAction( const ::basegfx::B2DPoint
& rStartPoint
,
595 const OUString
& rString
,
598 const CanvasSharedPtr
& rCanvas
,
599 const OutDevState
& rState
);
601 TextAction( const ::basegfx::B2DPoint
& rStartPoint
,
602 const OUString
& rString
,
605 const CanvasSharedPtr
& rCanvas
,
606 const OutDevState
& rState
,
607 const ::basegfx::B2DHomMatrix
& rTextTransform
);
609 TextAction(const TextAction
&) = delete;
610 const TextAction
& operator=(const TextAction
&) = delete;
612 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
613 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
614 const Subset
& rSubset
) const override
;
616 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
617 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
618 const Subset
& rSubset
) const override
;
620 virtual sal_Int32
getActionCount() const override
;
623 // TODO(P2): This is potentially a real mass object
624 // (every character might be a separate TextAction),
625 // thus, make it as lightweight as possible. For
626 // example, share common RenderState among several
627 // TextActions, maybe using maOffsets for the
630 uno::Reference
< rendering::XCanvasFont
> mxFont
;
631 const rendering::StringContext maStringContext
;
632 const CanvasSharedPtr mpCanvas
;
633 rendering::RenderState maState
;
634 const sal_Int8 maTextDirection
;
637 TextAction::TextAction( const ::basegfx::B2DPoint
& rStartPoint
,
638 const OUString
& rString
,
641 const CanvasSharedPtr
& rCanvas
,
642 const OutDevState
& rState
) :
643 mxFont( rState
.xFont
),
644 maStringContext( rString
, nStartPos
, nLen
),
647 maTextDirection( rState
.textDirection
)
649 init( maState
, mxFont
,
653 ENSURE_OR_THROW( mxFont
.is(),
654 "::cppcanvas::internal::TextAction(): Invalid font" );
657 TextAction::TextAction( const ::basegfx::B2DPoint
& rStartPoint
,
658 const OUString
& rString
,
661 const CanvasSharedPtr
& rCanvas
,
662 const OutDevState
& rState
,
663 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
664 mxFont( rState
.xFont
),
665 maStringContext( rString
, nStartPos
, nLen
),
668 maTextDirection( rState
.textDirection
)
670 init( maState
, mxFont
,
672 rState
, rCanvas
, rTextTransform
);
674 ENSURE_OR_THROW( mxFont
.is(),
675 "::cppcanvas::internal::TextAction(): Invalid font" );
678 bool TextAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
680 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextAction::render()" );
681 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextAction: 0x" << std::hex
<< this );
683 rendering::RenderState
aLocalState( maState
);
684 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
686 mpCanvas
->getUNOCanvas()->drawText( maStringContext
, mxFont
,
687 mpCanvas
->getViewState(), aLocalState
, maTextDirection
);
692 bool TextAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
693 const Subset
& /*rSubset*/ ) const
695 SAL_WARN( "cppcanvas.emf", "TextAction::renderSubset(): Subset not supported by this object" );
697 // TODO(P1): Retrieve necessary font metric info for
698 // TextAction from XCanvas. Currently, the
699 // TextActionFactory does not generate this object for
700 // _subsettable_ text
701 return render( rTransformation
);
704 ::basegfx::B2DRange
TextAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
706 // create XTextLayout, to have the
707 // XTextLayout::queryTextBounds() method available
708 uno::Reference
< rendering::XTextLayout
> xTextLayout(
709 mxFont
->createTextLayout(
714 rendering::RenderState
aLocalState( maState
);
715 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
717 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
718 xTextLayout
->queryTextBounds() ),
719 mpCanvas
->getViewState(),
723 ::basegfx::B2DRange
TextAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
724 const Subset
& /*rSubset*/ ) const
726 SAL_WARN( "cppcanvas.emf", "TextAction::getBounds(): Subset not supported by this object" );
728 // TODO(P1): Retrieve necessary font metric info for
729 // TextAction from XCanvas. Currently, the
730 // TextActionFactory does not generate this object for
731 // _subsettable_ text
732 return getBounds( rTransformation
);
735 sal_Int32
TextAction::getActionCount() const
737 // TODO(P1): Retrieve necessary font metric info for
738 // TextAction from XCanvas. Currently, the
739 // TextActionFactory does not generate this object for
740 // _subsettable_ text
745 class EffectTextAction
:
750 EffectTextAction( const ::basegfx::B2DPoint
& rStartPoint
,
751 const ::basegfx::B2DSize
& rReliefOffset
,
752 const ::Color
& rReliefColor
,
753 const ::basegfx::B2DSize
& rShadowOffset
,
754 const ::Color
& rShadowColor
,
755 const ::Color
& rTextFillColor
,
756 const OUString
& rText
,
759 VirtualDevice
const & rVDev
,
760 const CanvasSharedPtr
& rCanvas
,
761 const OutDevState
& rState
);
763 EffectTextAction( const ::basegfx::B2DPoint
& rStartPoint
,
764 const ::basegfx::B2DSize
& rReliefOffset
,
765 const ::Color
& rReliefColor
,
766 const ::basegfx::B2DSize
& rShadowOffset
,
767 const ::Color
& rShadowColor
,
768 const ::Color
& rTextFillColor
,
769 const OUString
& rText
,
772 VirtualDevice
const & rVDev
,
773 const CanvasSharedPtr
& rCanvas
,
774 const OutDevState
& rState
,
775 const ::basegfx::B2DHomMatrix
& rTextTransform
);
777 EffectTextAction(const EffectTextAction
&) = delete;
778 const EffectTextAction
& operator=(const EffectTextAction
&) = delete;
780 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
781 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
782 const Subset
& rSubset
) const override
;
784 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
785 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
786 const Subset
& rSubset
) const override
;
788 virtual sal_Int32
getActionCount() const override
;
791 /// Interface TextRenderer
792 virtual bool operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
, bool bNormalText
) const override
;
794 geometry::RealRectangle2D
queryTextBounds() const;
795 css::uno::Reference
<css::rendering::XPolyPolygon2D
> queryTextBounds(const uno::Reference
<rendering::XCanvas
>& rCanvas
) const;
797 // TODO(P2): This is potentially a real mass object
798 // (every character might be a separate TextAction),
799 // thus, make it as lightweight as possible. For
800 // example, share common RenderState among several
801 // TextActions, maybe using maOffsets for the
804 uno::Reference
< rendering::XCanvasFont
> mxFont
;
805 const rendering::StringContext maStringContext
;
806 const CanvasSharedPtr mpCanvas
;
807 rendering::RenderState maState
;
808 const tools::TextLineInfo maTextLineInfo
;
809 ::basegfx::B2DSize maLinesOverallSize
;
810 uno::Reference
< rendering::XPolyPolygon2D
> mxTextLines
;
811 const ::basegfx::B2DSize maReliefOffset
;
812 const ::Color maReliefColor
;
813 const ::basegfx::B2DSize maShadowOffset
;
814 const ::Color maShadowColor
;
815 const ::Color maTextFillColor
;
816 const sal_Int8 maTextDirection
;
819 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint
& rStartPoint
,
820 const ::basegfx::B2DSize
& rReliefOffset
,
821 const ::Color
& rReliefColor
,
822 const ::basegfx::B2DSize
& rShadowOffset
,
823 const ::Color
& rShadowColor
,
824 const ::Color
& rTextFillColor
,
825 const OUString
& rText
,
828 VirtualDevice
const & rVDev
,
829 const CanvasSharedPtr
& rCanvas
,
830 const OutDevState
& rState
) :
831 mxFont( rState
.xFont
),
832 maStringContext( rText
, nStartPos
, nLen
),
835 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
836 maLinesOverallSize(),
838 maReliefOffset( rReliefOffset
),
839 maReliefColor( rReliefColor
),
840 maShadowOffset( rShadowOffset
),
841 maShadowColor( rShadowColor
),
842 maTextFillColor( rTextFillColor
),
843 maTextDirection( rState
.textDirection
)
845 const double nLineWidth(getLineWidth( rVDev
, rState
, maStringContext
));
846 initEffectLinePolyPolygon( maLinesOverallSize
,
852 init( maState
, mxFont
,
856 ENSURE_OR_THROW( mxFont
.is() && mxTextLines
.is(),
857 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
860 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint
& rStartPoint
,
861 const ::basegfx::B2DSize
& rReliefOffset
,
862 const ::Color
& rReliefColor
,
863 const ::basegfx::B2DSize
& rShadowOffset
,
864 const ::Color
& rShadowColor
,
865 const ::Color
& rTextFillColor
,
866 const OUString
& rText
,
869 VirtualDevice
const & rVDev
,
870 const CanvasSharedPtr
& rCanvas
,
871 const OutDevState
& rState
,
872 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
873 mxFont( rState
.xFont
),
874 maStringContext( rText
, nStartPos
, nLen
),
877 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
878 maLinesOverallSize(),
880 maReliefOffset( rReliefOffset
),
881 maReliefColor( rReliefColor
),
882 maShadowOffset( rShadowOffset
),
883 maShadowColor( rShadowColor
),
884 maTextFillColor( rTextFillColor
),
885 maTextDirection( rState
.textDirection
)
887 const double nLineWidth( getLineWidth( rVDev
, rState
, maStringContext
) );
888 initEffectLinePolyPolygon( maLinesOverallSize
,
894 init( maState
, mxFont
,
896 rState
, rCanvas
, rTextTransform
);
898 ENSURE_OR_THROW( mxFont
.is() && mxTextLines
.is(),
899 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
902 bool EffectTextAction::operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
, bool /*bNormalText*/ ) const
904 const rendering::ViewState
& rViewState( mpCanvas
->getViewState() );
905 const uno::Reference
< rendering::XCanvas
>& rCanvas( mpCanvas
->getUNOCanvas() );
907 //rhbz#1589029 non-transparent text fill background support
908 if (rTextFillColor
!= COL_AUTO
)
910 rendering::RenderState
aLocalState( rRenderState
);
911 aLocalState
.DeviceColor
= vcl::unotools::colorToDoubleSequence(
912 rTextFillColor
, rCanvas
->getDevice()->getDeviceColorSpace());
913 auto xTextBounds
= queryTextBounds(rCanvas
);
914 // background of text
915 rCanvas
->fillPolyPolygon(xTextBounds
, rViewState
, aLocalState
);
919 rCanvas
->fillPolyPolygon( mxTextLines
,
923 rCanvas
->drawText( maStringContext
, mxFont
,
931 bool EffectTextAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
933 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextAction::render()" );
934 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextAction: 0x" << std::hex
<< this );
936 rendering::RenderState
aLocalState( maState
);
937 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
939 return renderEffectText( *this,
941 mpCanvas
->getUNOCanvas(),
949 bool EffectTextAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
950 const Subset
& /*rSubset*/ ) const
952 SAL_WARN( "cppcanvas.emf", "EffectTextAction::renderSubset(): Subset not supported by this object" );
954 // TODO(P1): Retrieve necessary font metric info for
955 // TextAction from XCanvas. Currently, the
956 // TextActionFactory does not generate this object for
958 return render( rTransformation
);
961 geometry::RealRectangle2D
EffectTextAction::queryTextBounds() const
963 // create XTextLayout, to have the
964 // XTextLayout::queryTextBounds() method available
965 uno::Reference
< rendering::XTextLayout
> xTextLayout(
966 mxFont
->createTextLayout(
971 return xTextLayout
->queryTextBounds();
974 css::uno::Reference
<css::rendering::XPolyPolygon2D
> EffectTextAction::queryTextBounds(const uno::Reference
<rendering::XCanvas
>& rCanvas
) const
976 auto aTextBounds
= queryTextBounds();
977 auto aB2DBounds
= ::basegfx::unotools::b2DRectangleFromRealRectangle2D(aTextBounds
);
978 auto aTextBoundsPoly
= ::basegfx::utils::createPolygonFromRect(aB2DBounds
);
979 return ::basegfx::unotools::xPolyPolygonFromB2DPolygon(rCanvas
->getDevice(), aTextBoundsPoly
);
982 ::basegfx::B2DRange
EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
984 rendering::RenderState
aLocalState( maState
);
985 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
987 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
989 ::basegfx::B2DRange( 0,0,
990 maLinesOverallSize
.getX(),
991 maLinesOverallSize
.getY() ),
995 mpCanvas
->getViewState() );
998 ::basegfx::B2DRange
EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
999 const Subset
& /*rSubset*/ ) const
1001 SAL_WARN( "cppcanvas.emf", "EffectTextAction::getBounds(): Subset not supported by this object" );
1003 // TODO(P1): Retrieve necessary font metric info for
1004 // TextAction from XCanvas. Currently, the
1005 // TextActionFactory does not generate this object for
1006 // _subsettable_ text
1007 return getBounds( rTransformation
);
1010 sal_Int32
EffectTextAction::getActionCount() const
1012 // TODO(P1): Retrieve necessary font metric info for
1013 // TextAction from XCanvas. Currently, the
1014 // TextActionFactory does not generate this object for
1020 class TextArrayAction
: public Action
1023 TextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1024 const OUString
& rString
,
1025 sal_Int32 nStartPos
,
1027 const uno::Sequence
< double >& rOffsets
,
1028 const CanvasSharedPtr
& rCanvas
,
1029 const OutDevState
& rState
);
1031 TextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1032 const OUString
& rString
,
1033 sal_Int32 nStartPos
,
1035 const uno::Sequence
< double >& rOffsets
,
1036 const CanvasSharedPtr
& rCanvas
,
1037 const OutDevState
& rState
,
1038 const ::basegfx::B2DHomMatrix
& rTextTransform
);
1040 TextArrayAction(const TextArrayAction
&) = delete;
1041 const TextArrayAction
& operator=(const TextArrayAction
&) = delete;
1043 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1044 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1045 const Subset
& rSubset
) const override
;
1047 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1048 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1049 const Subset
& rSubset
) const override
;
1051 virtual sal_Int32
getActionCount() const override
;
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
1061 uno::Reference
< rendering::XTextLayout
> mxTextLayout
;
1062 const CanvasSharedPtr mpCanvas
;
1063 rendering::RenderState maState
;
1064 double mnLayoutWidth
;
1067 TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1068 const OUString
& rString
,
1069 sal_Int32 nStartPos
,
1071 const uno::Sequence
< double >& rOffsets
,
1072 const CanvasSharedPtr
& rCanvas
,
1073 const OutDevState
& rState
) :
1075 mpCanvas( rCanvas
),
1078 initLayoutWidth(mnLayoutWidth
, rOffsets
);
1080 initArrayAction( maState
,
1091 TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1092 const OUString
& rString
,
1093 sal_Int32 nStartPos
,
1095 const uno::Sequence
< double >& rOffsets
,
1096 const CanvasSharedPtr
& rCanvas
,
1097 const OutDevState
& rState
,
1098 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
1100 mpCanvas( rCanvas
),
1103 initLayoutWidth(mnLayoutWidth
, rOffsets
);
1105 initArrayAction( maState
,
1117 bool TextArrayAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1119 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::render()" );
1120 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex
<< this );
1122 rendering::RenderState
aLocalState( maState
);
1123 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1125 mpCanvas
->getUNOCanvas()->drawTextLayout( mxTextLayout
,
1126 mpCanvas
->getViewState(),
1132 bool TextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1133 const Subset
& rSubset
) const
1135 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::renderSubset()" );
1136 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex
<< this );
1138 rendering::RenderState
aLocalState( maState
);
1139 uno::Reference
< rendering::XTextLayout
> xTextLayout( mxTextLayout
);
1141 double nDummy0
, nDummy1
;
1142 createSubsetLayout( xTextLayout
,
1150 if( !xTextLayout
.is() )
1151 return true; // empty layout, render nothing
1153 mpCanvas
->getUNOCanvas()->drawTextLayout( xTextLayout
,
1154 mpCanvas
->getViewState(),
1160 ::basegfx::B2DRange
TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1162 rendering::RenderState
aLocalState( maState
);
1163 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1165 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1166 mxTextLayout
->queryTextBounds() ),
1167 mpCanvas
->getViewState(),
1171 ::basegfx::B2DRange
TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1172 const Subset
& rSubset
) const
1174 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::getBounds( subset )" );
1175 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex
<< this );
1177 rendering::RenderState
aLocalState( maState
);
1178 uno::Reference
< rendering::XTextLayout
> xTextLayout( mxTextLayout
);
1180 double nDummy0
, nDummy1
;
1181 createSubsetLayout( xTextLayout
,
1189 if( !xTextLayout
.is() )
1190 return ::basegfx::B2DRange(); // empty layout, empty bounds
1192 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1193 xTextLayout
->queryTextBounds() ),
1194 mpCanvas
->getViewState(),
1198 sal_Int32
TextArrayAction::getActionCount() const
1200 const rendering::StringContext
& rOrigContext( mxTextLayout
->getText() );
1202 return rOrigContext
.Length
;
1206 class EffectTextArrayAction
:
1211 EffectTextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1212 const ::basegfx::B2DSize
& rReliefOffset
,
1213 const ::Color
& rReliefColor
,
1214 const ::basegfx::B2DSize
& rShadowOffset
,
1215 const ::Color
& rShadowColor
,
1216 const ::Color
& rTextFillColor
,
1217 const OUString
& rText
,
1218 sal_Int32 nStartPos
,
1220 const uno::Sequence
< double >& rOffsets
,
1221 VirtualDevice
const & rVDev
,
1222 const CanvasSharedPtr
& rCanvas
,
1223 const OutDevState
& rState
);
1224 EffectTextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1225 const ::basegfx::B2DSize
& rReliefOffset
,
1226 const ::Color
& rReliefColor
,
1227 const ::basegfx::B2DSize
& rShadowOffset
,
1228 const ::Color
& rShadowColor
,
1229 const ::Color
& rTextFillColor
,
1230 const OUString
& rText
,
1231 sal_Int32 nStartPos
,
1233 const uno::Sequence
< double >& rOffsets
,
1234 VirtualDevice
const & rVDev
,
1235 const CanvasSharedPtr
& rCanvas
,
1236 const OutDevState
& rState
,
1237 const ::basegfx::B2DHomMatrix
& rTextTransform
);
1239 EffectTextArrayAction(const EffectTextArrayAction
&) = delete;
1240 const EffectTextArrayAction
& operator=(const EffectTextArrayAction
&) = delete;
1242 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1243 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1244 const Subset
& rSubset
) const override
;
1246 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1247 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1248 const Subset
& rSubset
) const override
;
1250 virtual sal_Int32
getActionCount() const override
;
1253 // TextRenderer interface
1254 virtual bool operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
, bool bNormalText
) const override
;
1256 css::uno::Reference
<css::rendering::XPolyPolygon2D
> queryTextBounds(const uno::Reference
<rendering::XCanvas
>& rCanvas
) const;
1258 // TODO(P2): This is potentially a real mass object
1259 // (every character might be a separate TextAction),
1260 // thus, make it as lightweight as possible. For
1261 // example, share common RenderState among several
1262 // TextActions, maybe using maOffsets for the
1265 uno::Reference
< rendering::XTextLayout
> mxTextLayout
;
1266 const CanvasSharedPtr mpCanvas
;
1267 rendering::RenderState maState
;
1268 const tools::TextLineInfo maTextLineInfo
;
1269 TextLinesHelper maTextLinesHelper
;
1270 const ::basegfx::B2DSize maReliefOffset
;
1271 const ::Color maReliefColor
;
1272 const ::basegfx::B2DSize maShadowOffset
;
1273 const ::Color maShadowColor
;
1274 const ::Color maTextFillColor
;
1275 double mnLayoutWidth
;
1278 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1279 const ::basegfx::B2DSize
& rReliefOffset
,
1280 const ::Color
& rReliefColor
,
1281 const ::basegfx::B2DSize
& rShadowOffset
,
1282 const ::Color
& rShadowColor
,
1283 const ::Color
& rTextFillColor
,
1284 const OUString
& rText
,
1285 sal_Int32 nStartPos
,
1287 const uno::Sequence
< double >& rOffsets
,
1288 VirtualDevice
const & rVDev
,
1289 const CanvasSharedPtr
& rCanvas
,
1290 const OutDevState
& rState
) :
1292 mpCanvas( rCanvas
),
1294 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
1295 maTextLinesHelper(mpCanvas
, rState
),
1296 maReliefOffset( rReliefOffset
),
1297 maReliefColor( rReliefColor
),
1298 maShadowOffset( rShadowOffset
),
1299 maShadowColor( rShadowColor
),
1300 maTextFillColor( rTextFillColor
)
1302 initLayoutWidth(mnLayoutWidth
, rOffsets
);
1304 maTextLinesHelper
.init(mnLayoutWidth
, maTextLineInfo
);
1306 initArrayAction( maState
,
1317 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1318 const ::basegfx::B2DSize
& rReliefOffset
,
1319 const ::Color
& rReliefColor
,
1320 const ::basegfx::B2DSize
& rShadowOffset
,
1321 const ::Color
& rShadowColor
,
1322 const ::Color
& rTextFillColor
,
1323 const OUString
& rText
,
1324 sal_Int32 nStartPos
,
1326 const uno::Sequence
< double >& rOffsets
,
1327 VirtualDevice
const & rVDev
,
1328 const CanvasSharedPtr
& rCanvas
,
1329 const OutDevState
& rState
,
1330 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
1332 mpCanvas( rCanvas
),
1334 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
1335 maTextLinesHelper(mpCanvas
, rState
),
1336 maReliefOffset( rReliefOffset
),
1337 maReliefColor( rReliefColor
),
1338 maShadowOffset( rShadowOffset
),
1339 maShadowColor( rShadowColor
),
1340 maTextFillColor( rTextFillColor
)
1342 initLayoutWidth(mnLayoutWidth
, rOffsets
);
1344 maTextLinesHelper
.init(mnLayoutWidth
, maTextLineInfo
);
1346 initArrayAction( maState
,
1358 css::uno::Reference
<css::rendering::XPolyPolygon2D
> EffectTextArrayAction::queryTextBounds(const uno::Reference
<rendering::XCanvas
>& rCanvas
) const
1360 const geometry::RealRectangle2D
aTextBounds(mxTextLayout
->queryTextBounds());
1361 auto aB2DBounds
= ::basegfx::unotools::b2DRectangleFromRealRectangle2D(aTextBounds
);
1362 auto aTextBoundsPoly
= ::basegfx::utils::createPolygonFromRect(aB2DBounds
);
1363 return ::basegfx::unotools::xPolyPolygonFromB2DPolygon(rCanvas
->getDevice(), aTextBoundsPoly
);
1366 bool EffectTextArrayAction::operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
, bool bNormalText
) const
1368 const rendering::ViewState
& rViewState( mpCanvas
->getViewState() );
1369 const uno::Reference
< rendering::XCanvas
>& rCanvas( mpCanvas
->getUNOCanvas() );
1371 //rhbz#1589029 non-transparent text fill background support
1372 if (rTextFillColor
!= COL_AUTO
)
1374 rendering::RenderState
aLocalState(rRenderState
);
1375 aLocalState
.DeviceColor
= vcl::unotools::colorToDoubleSequence(
1376 rTextFillColor
, rCanvas
->getDevice()->getDeviceColorSpace());
1377 auto xTextBounds
= queryTextBounds(rCanvas
);
1378 // background of text
1379 rCanvas
->fillPolyPolygon(xTextBounds
, rViewState
, aLocalState
);
1383 maTextLinesHelper
.render(rRenderState
, bNormalText
);
1385 rCanvas
->drawTextLayout( mxTextLayout
,
1392 bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1394 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::render()" );
1395 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex
<< this );
1397 rendering::RenderState
aLocalState( maState
);
1398 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1400 return renderEffectText( *this,
1402 mpCanvas
->getUNOCanvas(),
1410 class EffectTextArrayRenderHelper
: public TextRenderer
1413 EffectTextArrayRenderHelper( const uno::Reference
< rendering::XCanvas
>& rCanvas
,
1414 const uno::Reference
< rendering::XTextLayout
>& rTextLayout
,
1415 const TextLinesHelper
& rTextLinesHelper
,
1416 const rendering::ViewState
& rViewState
) :
1417 mrCanvas( rCanvas
),
1418 mrTextLayout( rTextLayout
),
1419 mrTextLinesHelper( rTextLinesHelper
),
1420 mrViewState( rViewState
)
1424 // TextRenderer interface
1425 virtual bool operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
,bool bNormalText
) const override
1427 mrTextLinesHelper
.render(rRenderState
, bNormalText
);
1429 //rhbz#1589029 non-transparent text fill background support
1430 if (rTextFillColor
!= COL_AUTO
)
1432 rendering::RenderState
aLocalState(rRenderState
);
1433 aLocalState
.DeviceColor
= vcl::unotools::colorToDoubleSequence(
1434 rTextFillColor
, mrCanvas
->getDevice()->getDeviceColorSpace());
1435 auto xTextBounds
= queryTextBounds();
1436 // background of text
1437 mrCanvas
->fillPolyPolygon(xTextBounds
, mrViewState
, aLocalState
);
1440 mrCanvas
->drawTextLayout( mrTextLayout
,
1449 css::uno::Reference
<css::rendering::XPolyPolygon2D
> queryTextBounds() const
1451 const geometry::RealRectangle2D
aTextBounds(mrTextLayout
->queryTextBounds());
1452 auto aB2DBounds
= ::basegfx::unotools::b2DRectangleFromRealRectangle2D(aTextBounds
);
1453 auto aTextBoundsPoly
= ::basegfx::utils::createPolygonFromRect(aB2DBounds
);
1454 return ::basegfx::unotools::xPolyPolygonFromB2DPolygon(mrCanvas
->getDevice(), aTextBoundsPoly
);
1457 const uno::Reference
< rendering::XCanvas
>& mrCanvas
;
1458 const uno::Reference
< rendering::XTextLayout
>& mrTextLayout
;
1459 const TextLinesHelper
& mrTextLinesHelper
;
1460 const rendering::ViewState
& mrViewState
;
1463 bool EffectTextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1464 const Subset
& rSubset
) const
1466 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::renderSubset()" );
1467 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex
<< this );
1469 rendering::RenderState
aLocalState( maState
);
1470 uno::Reference
< rendering::XTextLayout
> xTextLayout( mxTextLayout
);
1471 const geometry::RealRectangle2D
aTextBounds( mxTextLayout
->queryTextBounds() );
1473 double nMinPos(0.0);
1474 double nMaxPos(aTextBounds
.X2
- aTextBounds
.X1
);
1476 createSubsetLayout( xTextLayout
,
1484 if( !xTextLayout
.is() )
1485 return true; // empty layout, render nothing
1488 // create and setup local line polygon
1489 // ===================================
1491 uno::Reference
< rendering::XCanvas
> xCanvas( mpCanvas
->getUNOCanvas() );
1492 const rendering::ViewState
& rViewState( mpCanvas
->getViewState() );
1494 TextLinesHelper aHelper
= maTextLinesHelper
;
1495 aHelper
.init(nMaxPos
- nMinPos
, maTextLineInfo
);
1498 // render everything
1499 // =================
1501 return renderEffectText(
1502 EffectTextArrayRenderHelper( xCanvas
,
1515 ::basegfx::B2DRange
EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1517 rendering::RenderState
aLocalState( maState
);
1518 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1520 ::basegfx::B2DSize aSize
= maTextLinesHelper
.getOverallSize();
1522 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1523 mxTextLayout
->queryTextBounds() ),
1524 ::basegfx::B2DRange( 0,0,
1530 mpCanvas
->getViewState() );
1533 ::basegfx::B2DRange
EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1534 const Subset
& rSubset
) const
1536 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::getBounds( subset )" );
1537 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex
<< this );
1539 rendering::RenderState
aLocalState( maState
);
1540 uno::Reference
< rendering::XTextLayout
> xTextLayout( mxTextLayout
);
1541 const geometry::RealRectangle2D
aTextBounds( mxTextLayout
->queryTextBounds() );
1543 double nMinPos(0.0);
1544 double nMaxPos(aTextBounds
.X2
- aTextBounds
.X1
);
1546 createSubsetLayout( xTextLayout
,
1554 if( !xTextLayout
.is() )
1555 return ::basegfx::B2DRange(); // empty layout, empty bounds
1558 // create and setup local line polygon
1559 // ===================================
1561 const ::basegfx::B2DPolyPolygon
aPoly(
1562 tools::createTextLinesPolyPolygon(
1563 0.0, nMaxPos
- nMinPos
,
1566 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1567 xTextLayout
->queryTextBounds() ),
1568 ::basegfx::utils::getRange( aPoly
),
1572 mpCanvas
->getViewState() );
1575 sal_Int32
EffectTextArrayAction::getActionCount() const
1577 const rendering::StringContext
& rOrigContext( mxTextLayout
->getText() );
1579 return rOrigContext
.Length
;
1583 class OutlineAction
:
1588 OutlineAction( const ::basegfx::B2DPoint
& rStartPoint
,
1589 const ::basegfx::B2DSize
& rReliefOffset
,
1590 const ::Color
& rReliefColor
,
1591 const ::basegfx::B2DSize
& rShadowOffset
,
1592 const ::Color
& rShadowColor
,
1593 const ::basegfx::B2DRectangle
& rOutlineBounds
,
1594 const uno::Reference
< rendering::XPolyPolygon2D
>& rTextPoly
,
1595 const uno::Sequence
< double >& rOffsets
,
1596 VirtualDevice
const & rVDev
,
1597 const CanvasSharedPtr
& rCanvas
,
1598 const OutDevState
& rState
);
1599 OutlineAction( const ::basegfx::B2DPoint
& rStartPoint
,
1600 const ::basegfx::B2DSize
& rReliefOffset
,
1601 const ::Color
& rReliefColor
,
1602 const ::basegfx::B2DSize
& rShadowOffset
,
1603 const ::Color
& rShadowColor
,
1604 const ::basegfx::B2DRectangle
& rOutlineBounds
,
1605 const uno::Reference
< rendering::XPolyPolygon2D
>& rTextPoly
,
1606 const uno::Sequence
< double >& rOffsets
,
1607 VirtualDevice
const & rVDev
,
1608 const CanvasSharedPtr
& rCanvas
,
1609 const OutDevState
& rState
,
1610 const ::basegfx::B2DHomMatrix
& rTextTransform
);
1612 OutlineAction(const OutlineAction
&) = delete;
1613 const OutlineAction
& operator=(const OutlineAction
&) = delete;
1615 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1616 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1617 const Subset
& rSubset
) const override
;
1619 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1620 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1621 const Subset
& rSubset
) const override
;
1623 virtual sal_Int32
getActionCount() const override
;
1626 // TextRenderer interface
1627 virtual bool operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
, bool bNormalText
) const override
;
1629 // TODO(P2): This is potentially a real mass object
1630 // (every character might be a separate TextAction),
1631 // thus, make it as lightweight as possible. For
1632 // example, share common RenderState among several
1633 // TextActions, maybe using maOffsets for the
1636 uno::Reference
< rendering::XPolyPolygon2D
> mxTextPoly
;
1638 const uno::Sequence
< double > maOffsets
;
1639 const CanvasSharedPtr mpCanvas
;
1640 rendering::RenderState maState
;
1641 double mnOutlineWidth
;
1642 const uno::Sequence
< double > maFillColor
;
1643 const tools::TextLineInfo maTextLineInfo
;
1644 ::basegfx::B2DSize maLinesOverallSize
;
1645 const ::basegfx::B2DRectangle maOutlineBounds
;
1646 uno::Reference
< rendering::XPolyPolygon2D
> mxTextLines
;
1647 const ::basegfx::B2DSize maReliefOffset
;
1648 const ::Color maReliefColor
;
1649 const ::basegfx::B2DSize maShadowOffset
;
1650 const ::Color maShadowColor
;
1651 const ::Color maTextFillColor
;
1654 double calcOutlineWidth( const OutDevState
& rState
,
1655 VirtualDevice
const & rVDev
)
1657 const ::basegfx::B2DSize
aFontSize( 0,
1658 rVDev
.GetFont().GetFontHeight() / 64.0 );
1660 const double nOutlineWidth(
1661 (rState
.mapModeTransform
* aFontSize
).getY() );
1663 return nOutlineWidth
< 1.0 ? 1.0 : nOutlineWidth
;
1666 OutlineAction::OutlineAction( const ::basegfx::B2DPoint
& rStartPoint
,
1667 const ::basegfx::B2DSize
& rReliefOffset
,
1668 const ::Color
& rReliefColor
,
1669 const ::basegfx::B2DSize
& rShadowOffset
,
1670 const ::Color
& rShadowColor
,
1671 const ::basegfx::B2DRectangle
& rOutlineBounds
,
1672 const uno::Reference
< rendering::XPolyPolygon2D
>& rTextPoly
,
1673 const uno::Sequence
< double >& rOffsets
,
1674 VirtualDevice
const & rVDev
,
1675 const CanvasSharedPtr
& rCanvas
,
1676 const OutDevState
& rState
) :
1677 mxTextPoly( rTextPoly
),
1678 maOffsets( rOffsets
),
1679 mpCanvas( rCanvas
),
1681 mnOutlineWidth( calcOutlineWidth(rState
,rVDev
) ),
1683 vcl::unotools::colorToDoubleSequence(
1685 rCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1686 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
1687 maLinesOverallSize(),
1688 maOutlineBounds( rOutlineBounds
),
1690 maReliefOffset( rReliefOffset
),
1691 maReliefColor( rReliefColor
),
1692 maShadowOffset( rShadowOffset
),
1693 maShadowColor( rShadowColor
)
1695 double nLayoutWidth
= 0.0;
1697 initLayoutWidth(nLayoutWidth
, rOffsets
);
1699 initEffectLinePolyPolygon( maLinesOverallSize
,
1711 OutlineAction::OutlineAction( const ::basegfx::B2DPoint
& rStartPoint
,
1712 const ::basegfx::B2DSize
& rReliefOffset
,
1713 const ::Color
& rReliefColor
,
1714 const ::basegfx::B2DSize
& rShadowOffset
,
1715 const ::Color
& rShadowColor
,
1716 const ::basegfx::B2DRectangle
& rOutlineBounds
,
1717 const uno::Reference
< rendering::XPolyPolygon2D
>& rTextPoly
,
1718 const uno::Sequence
< double >& rOffsets
,
1719 VirtualDevice
const & rVDev
,
1720 const CanvasSharedPtr
& rCanvas
,
1721 const OutDevState
& rState
,
1722 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
1723 mxTextPoly( rTextPoly
),
1724 maOffsets( rOffsets
),
1725 mpCanvas( rCanvas
),
1727 mnOutlineWidth( calcOutlineWidth(rState
,rVDev
) ),
1729 vcl::unotools::colorToDoubleSequence(
1731 rCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1732 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
1733 maLinesOverallSize(),
1734 maOutlineBounds( rOutlineBounds
),
1736 maReliefOffset( rReliefOffset
),
1737 maReliefColor( rReliefColor
),
1738 maShadowOffset( rShadowOffset
),
1739 maShadowColor( rShadowColor
)
1741 double nLayoutWidth
= 0.0;
1742 initLayoutWidth(nLayoutWidth
, rOffsets
);
1744 initEffectLinePolyPolygon( maLinesOverallSize
,
1757 bool OutlineAction::operator()( const rendering::RenderState
& rRenderState
, const ::Color
& /*rTextFillColor*/, bool /*bNormalText*/ ) const
1759 const rendering::ViewState
& rViewState( mpCanvas
->getViewState() );
1760 const uno::Reference
< rendering::XCanvas
>& rCanvas( mpCanvas
->getUNOCanvas() );
1762 rendering::StrokeAttributes aStrokeAttributes
;
1764 aStrokeAttributes
.StrokeWidth
= mnOutlineWidth
;
1765 aStrokeAttributes
.MiterLimit
= 1.0;
1766 aStrokeAttributes
.StartCapType
= rendering::PathCapType::BUTT
;
1767 aStrokeAttributes
.EndCapType
= rendering::PathCapType::BUTT
;
1768 aStrokeAttributes
.JoinType
= rendering::PathJoinType::MITER
;
1770 rendering::RenderState
aLocalState( rRenderState
);
1771 aLocalState
.DeviceColor
= maFillColor
;
1773 // TODO(P1): implement caching
1775 // background of text
1776 rCanvas
->fillPolyPolygon( mxTextPoly
,
1780 // border line of text
1781 rCanvas
->strokePolyPolygon( mxTextPoly
,
1784 aStrokeAttributes
);
1786 // underlines/strikethrough - background
1787 rCanvas
->fillPolyPolygon( mxTextLines
,
1790 // underlines/strikethrough - border
1791 rCanvas
->strokePolyPolygon( mxTextLines
,
1794 aStrokeAttributes
);
1799 bool OutlineAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1801 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::render()" );
1802 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex
<< this );
1804 rendering::RenderState
aLocalState( maState
);
1805 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1807 return renderEffectText( *this,
1809 mpCanvas
->getUNOCanvas(),
1817 #if 0 // see #if'ed out use in OutlineAction::renderSubset below:
1818 class OutlineTextArrayRenderHelper
: public TextRenderer
1821 OutlineTextArrayRenderHelper( const uno::Reference
< rendering::XCanvas
>& rCanvas
,
1822 const uno::Reference
< rendering::XPolyPolygon2D
>& rTextPolygon
,
1823 const uno::Reference
< rendering::XPolyPolygon2D
>& rLinePolygon
,
1824 const rendering::ViewState
& rViewState
,
1825 double nOutlineWidth
) :
1827 vcl::unotools::colorToDoubleSequence(
1829 rCanvas
->getDevice()->getDeviceColorSpace() )),
1830 mnOutlineWidth( nOutlineWidth
),
1831 mrCanvas( rCanvas
),
1832 mrTextPolygon( rTextPolygon
),
1833 mrLinePolygon( rLinePolygon
),
1834 mrViewState( rViewState
)
1838 // TextRenderer interface
1839 virtual bool operator()( const rendering::RenderState
& rRenderState
) const
1841 rendering::StrokeAttributes aStrokeAttributes
;
1843 aStrokeAttributes
.StrokeWidth
= mnOutlineWidth
;
1844 aStrokeAttributes
.MiterLimit
= 1.0;
1845 aStrokeAttributes
.StartCapType
= rendering::PathCapType::BUTT
;
1846 aStrokeAttributes
.EndCapType
= rendering::PathCapType::BUTT
;
1847 aStrokeAttributes
.JoinType
= rendering::PathJoinType::MITER
;
1849 rendering::RenderState
aLocalState( rRenderState
);
1850 aLocalState
.DeviceColor
= maFillColor
;
1852 // TODO(P1): implement caching
1854 // background of text
1855 mrCanvas
->fillPolyPolygon( mrTextPolygon
,
1859 // border line of text
1860 mrCanvas
->strokePolyPolygon( mrTextPolygon
,
1863 aStrokeAttributes
);
1865 // underlines/strikethrough - background
1866 mrCanvas
->fillPolyPolygon( mrLinePolygon
,
1869 // underlines/strikethrough - border
1870 mrCanvas
->strokePolyPolygon( mrLinePolygon
,
1873 aStrokeAttributes
);
1879 const uno::Sequence
< double > maFillColor
;
1880 double mnOutlineWidth
;
1881 const uno::Reference
< rendering::XCanvas
>& mrCanvas
;
1882 const uno::Reference
< rendering::XPolyPolygon2D
>& mrTextPolygon
;
1883 const uno::Reference
< rendering::XPolyPolygon2D
>& mrLinePolygon
;
1884 const rendering::ViewState
& mrViewState
;
1888 bool OutlineAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1889 const Subset
& rSubset
) const
1891 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction::renderSubset()" );
1892 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction: 0x" << std::hex
<< this );
1894 if( rSubset
.mnSubsetBegin
== rSubset
.mnSubsetEnd
)
1895 return true; // empty range, render nothing
1898 // TODO(F3): Subsetting NYI for outline text!
1899 return render( rTransformation
);
1901 const rendering::StringContext
rOrigContext( mxTextLayout
->getText() );
1903 if( rSubset
.mnSubsetBegin
== 0 &&
1904 rSubset
.mnSubsetEnd
== rOrigContext
.Length
)
1906 // full range, no need for subsetting
1907 return render( rTransformation
);
1910 rendering::RenderState
aLocalState( maState
);
1911 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1914 // create and setup local Text polygon
1915 // ===================================
1917 uno::Reference
< rendering::XPolyPolygon2D
> xTextPolygon();
1919 // TODO(P3): Provide an API method for that!
1921 if( !xTextLayout
.is() )
1924 // render everything
1925 // =================
1927 return renderEffectText(
1928 OutlineTextArrayRenderHelper(
1944 ::basegfx::B2DRange
OutlineAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1946 rendering::RenderState
aLocalState( maState
);
1947 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1949 return calcEffectTextBounds( maOutlineBounds
,
1950 ::basegfx::B2DRange( 0,0,
1951 maLinesOverallSize
.getX(),
1952 maLinesOverallSize
.getY() ),
1956 mpCanvas
->getViewState() );
1959 ::basegfx::B2DRange
OutlineAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1960 const Subset
& /*rSubset*/ ) const
1962 SAL_WARN( "cppcanvas.emf", "OutlineAction::getBounds(): Subset not yet supported by this object" );
1964 return getBounds( rTransformation
);
1967 sal_Int32
OutlineAction::getActionCount() const
1969 // TODO(F3): Subsetting NYI for outline text!
1970 return maOffsets
.getLength();
1974 // Action factory methods
1977 /** Create an outline action
1979 This method extracts the polygonal outline from the
1980 text, and creates a properly setup OutlineAction from
1983 std::shared_ptr
<Action
> createOutline( const ::basegfx::B2DPoint
& rStartPoint
,
1984 const ::basegfx::B2DSize
& rReliefOffset
,
1985 const ::Color
& rReliefColor
,
1986 const ::basegfx::B2DSize
& rShadowOffset
,
1987 const ::Color
& rShadowColor
,
1988 const OUString
& rText
,
1989 sal_Int32 nStartPos
,
1991 const ::tools::Long
* pDXArray
,
1992 VirtualDevice
& rVDev
,
1993 const CanvasSharedPtr
& rCanvas
,
1994 const OutDevState
& rState
,
1995 const Renderer::Parameters
& rParms
)
1997 // operate on raw DX array here (in logical coordinate
1998 // system), to have a higher resolution
1999 // PolyPolygon. That polygon is then converted to
2000 // device coordinate system.
2002 // #i68512# Temporarily switch off font rotation
2003 // (which is already contained in the render state
2004 // transformation matrix - otherwise, glyph polygons
2005 // will be rotated twice)
2006 const vcl::Font
aOrigFont( rVDev
.GetFont() );
2007 vcl::Font
aUnrotatedFont( aOrigFont
);
2008 aUnrotatedFont
.SetOrientation(Degree10(0));
2009 rVDev
.SetFont( aUnrotatedFont
);
2011 // TODO(F3): Don't understand parameter semantics of
2012 // GetTextOutlines()
2013 ::basegfx::B2DPolyPolygon aResultingPolyPolygon
;
2014 PolyPolyVector aVCLPolyPolyVector
;
2015 const bool bHaveOutlines( rVDev
.GetTextOutlines( aVCLPolyPolyVector
, rText
,
2016 static_cast<sal_uInt16
>(nStartPos
),
2017 static_cast<sal_uInt16
>(nStartPos
),
2018 static_cast<sal_uInt16
>(nLen
),
2020 rVDev
.SetFont(aOrigFont
);
2022 if( !bHaveOutlines
)
2023 return std::shared_ptr
<Action
>();
2025 // remove offsetting from mapmode transformation
2026 // (outline polygons must stay at origin, only need to
2028 ::basegfx::B2DHomMatrix
aMapModeTransform(
2029 rState
.mapModeTransform
);
2030 aMapModeTransform
.set(0,2, 0.0);
2031 aMapModeTransform
.set(1,2, 0.0);
2033 for( const auto& rVCLPolyPolygon
: aVCLPolyPolyVector
)
2035 ::basegfx::B2DPolyPolygon aPolyPolygon
= rVCLPolyPolygon
.getB2DPolyPolygon();
2036 aPolyPolygon
.transform( aMapModeTransform
);
2038 // append result to collecting polypoly
2039 for( sal_uInt32 i
=0; i
<aPolyPolygon
.count(); ++i
)
2041 // #i47795# Ensure closed polygons (since
2042 // FreeType returns the glyph outlines
2044 const ::basegfx::B2DPolygon
& rPoly( aPolyPolygon
.getB2DPolygon( i
) );
2045 const sal_uInt32
nCount( rPoly
.count() );
2049 // polygon either degenerate, or
2051 aResultingPolyPolygon
.append( rPoly
);
2055 ::basegfx::B2DPolygon
aPoly(rPoly
);
2056 aPoly
.setClosed(true);
2058 aResultingPolyPolygon
.append( aPoly
);
2063 const uno::Sequence
< double > aCharWidthSeq(
2065 setupDXArray( pDXArray
, nLen
, rState
) :
2066 setupDXArray( rText
,
2071 const uno::Reference
< rendering::XPolyPolygon2D
> xTextPoly(
2072 ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
2073 rCanvas
->getUNOCanvas()->getDevice(),
2074 aResultingPolyPolygon
) );
2076 if( rParms
.maTextTransformation
)
2078 return std::make_shared
<OutlineAction
>(
2084 ::basegfx::utils::getRange(aResultingPolyPolygon
),
2090 *rParms
.maTextTransformation
);
2094 return std::make_shared
<OutlineAction
>(
2100 ::basegfx::utils::getRange(aResultingPolyPolygon
),
2112 std::shared_ptr
<Action
> TextActionFactory::createTextAction( const ::Point
& rStartPoint
,
2113 const ::Size
& rReliefOffset
,
2114 const ::Color
& rReliefColor
,
2115 const ::Size
& rShadowOffset
,
2116 const ::Color
& rShadowColor
,
2117 const ::Color
& rTextFillColor
,
2118 const OUString
& rText
,
2119 sal_Int32 nStartPos
,
2121 const ::tools::Long
* pDXArray
,
2122 VirtualDevice
& rVDev
,
2123 const CanvasSharedPtr
& rCanvas
,
2124 const OutDevState
& rState
,
2125 const Renderer::Parameters
& rParms
,
2128 const ::Size
aBaselineOffset( tools::getBaselineOffset( rState
,
2130 // #143885# maintain (nearly) full precision positioning,
2131 // by circumventing integer-based OutDev-mapping
2132 const ::basegfx::B2DPoint
aStartPoint(
2133 rState
.mapModeTransform
*
2134 ::basegfx::B2DPoint(rStartPoint
.X() + aBaselineOffset
.Width(),
2135 rStartPoint
.Y() + aBaselineOffset
.Height()) );
2137 const ::basegfx::B2DSize
aReliefOffset(
2138 rState
.mapModeTransform
* vcl::unotools::b2DSizeFromSize( rReliefOffset
) );
2139 const ::basegfx::B2DSize
aShadowOffset(
2140 rState
.mapModeTransform
* vcl::unotools::b2DSizeFromSize( rShadowOffset
) );
2142 if( rState
.isTextOutlineModeSet
)
2144 return createOutline(
2160 // convert DX array to device coordinate system (and
2161 // create it in the first place, if pDXArray is NULL)
2162 const uno::Sequence
< double > aCharWidths(
2164 setupDXArray( pDXArray
, nLen
, rState
) :
2165 setupDXArray( rText
,
2171 // determine type of text action to create
2172 // =======================================
2174 const ::Color
aEmptyColor( COL_AUTO
);
2176 std::shared_ptr
<Action
> ret
;
2178 // no DX array, and no need to subset - no need to store
2180 if( !pDXArray
&& !bSubsettable
)
2183 if( !rState
.textOverlineStyle
&&
2184 !rState
.textUnderlineStyle
&&
2185 !rState
.textStrikeoutStyle
&&
2186 rReliefColor
== aEmptyColor
&&
2187 rShadowColor
== aEmptyColor
&&
2188 rTextFillColor
== aEmptyColor
)
2191 if( rParms
.maTextTransformation
)
2193 ret
= std::make_shared
<TextAction
>(
2200 *rParms
.maTextTransformation
);
2204 ret
= std::make_shared
<TextAction
>(
2215 // at least one of the effects requested
2216 if( rParms
.maTextTransformation
)
2217 ret
= std::make_shared
<EffectTextAction
>(
2230 *rParms
.maTextTransformation
);
2232 ret
= std::make_shared
<EffectTextAction
>(
2249 // DX array necessary - any effects?
2250 if( !rState
.textOverlineStyle
&&
2251 !rState
.textUnderlineStyle
&&
2252 !rState
.textStrikeoutStyle
&&
2253 rReliefColor
== aEmptyColor
&&
2254 rShadowColor
== aEmptyColor
&&
2255 rTextFillColor
== aEmptyColor
)
2258 if( rParms
.maTextTransformation
)
2259 ret
= std::make_shared
<TextArrayAction
>(
2267 *rParms
.maTextTransformation
);
2269 ret
= std::make_shared
<TextArrayAction
>(
2280 // at least one of the effects requested
2281 if( rParms
.maTextTransformation
)
2282 ret
= std::make_shared
<EffectTextArrayAction
>(
2296 *rParms
.maTextTransformation
);
2298 ret
= std::make_shared
<EffectTextArrayAction
>(
2318 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */