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 <comphelper/diagnose_ex.hxx>
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>
37 #include <vcl/canvastools.hxx>
38 #include <vcl/virdev.hxx>
40 #include <basegfx/utils/canvastools.hxx>
41 #include <canvas/canvastools.hxx>
43 #include <sal/log.hxx>
45 #include "textaction.hxx"
46 #include "textlineshelper.hxx"
47 #include <outdevstate.hxx>
48 #include "mtftools.hxx"
51 using namespace ::com::sun::star
;
53 namespace cppcanvas::internal
57 void init( rendering::RenderState
& o_rRenderState
,
58 const ::basegfx::B2DPoint
& rStartPoint
,
59 const OutDevState
& rState
,
60 const CanvasSharedPtr
& rCanvas
)
62 tools::initRenderState(o_rRenderState
,rState
);
64 // #i36950# Offset clip back to origin (as it's also moved
66 // #i53964# Also take VCL font rotation into account,
67 // since this, opposed to the FontMatrix rotation
68 // elsewhere, _does_ get incorporated into the render
70 tools::modifyClip( o_rRenderState
,
75 &rState
.fontRotation
);
77 basegfx::B2DHomMatrix
aLocalTransformation(basegfx::utils::createRotateB2DHomMatrix(rState
.fontRotation
));
78 aLocalTransformation
.translate( rStartPoint
.getX(),
80 ::canvas::tools::appendToRenderState( o_rRenderState
,
81 aLocalTransformation
);
83 o_rRenderState
.DeviceColor
= rState
.textColor
;
86 void init( rendering::RenderState
& o_rRenderState
,
87 const ::basegfx::B2DPoint
& rStartPoint
,
88 const OutDevState
& rState
,
89 const CanvasSharedPtr
& rCanvas
,
90 const ::basegfx::B2DHomMatrix
& rTextTransform
)
92 init( o_rRenderState
, rStartPoint
, rState
, rCanvas
);
94 // TODO(F2): Also inversely-transform clip with
95 // rTextTransform (which is actually rather hard, as the
96 // text transform is _prepended_ to the render state)!
98 // prepend extra font transform to render state
99 // (prepend it, because it's interpreted in the unit
100 // rect coordinate space)
101 ::canvas::tools::prependToRenderState( o_rRenderState
,
105 void init( rendering::RenderState
& o_rRenderState
,
106 uno::Reference
< rendering::XCanvasFont
>& o_rFont
,
107 const ::basegfx::B2DPoint
& rStartPoint
,
108 const OutDevState
& rState
,
109 const CanvasSharedPtr
& rCanvas
)
111 // ensure that o_rFont is valid. It is possible that
112 // text actions are generated without previously
113 // setting a font. Then, just take a default font
116 // Use completely default FontRequest
117 const rendering::FontRequest aFontRequest
;
119 geometry::Matrix2D aFontMatrix
;
120 ::canvas::tools::setIdentityMatrix2D( aFontMatrix
);
122 o_rFont
= rCanvas
->getUNOCanvas()->createFont(
124 uno::Sequence
< beans::PropertyValue
>(),
128 init( o_rRenderState
,
134 void init( rendering::RenderState
& o_rRenderState
,
135 uno::Reference
< rendering::XCanvasFont
>& o_rFont
,
136 const ::basegfx::B2DPoint
& rStartPoint
,
137 const OutDevState
& rState
,
138 const CanvasSharedPtr
& rCanvas
,
139 const ::basegfx::B2DHomMatrix
& rTextTransform
)
141 init( o_rRenderState
, o_rFont
, rStartPoint
, rState
, rCanvas
);
143 // TODO(F2): Also inversely-transform clip with
144 // rTextTransform (which is actually rather hard, as the
145 // text transform is _prepended_ to the render state)!
147 // prepend extra font transform to render state
148 // (prepend it, because it's interpreted in the unit
149 // rect coordinate space)
150 ::canvas::tools::prependToRenderState( o_rRenderState
,
154 void initLayoutWidth(double& rLayoutWidth
, const uno::Sequence
<double>& rOffsets
)
156 ENSURE_OR_THROW(rOffsets
.hasElements(),
157 "::cppcanvas::internal::initLayoutWidth(): zero-length array" );
158 rLayoutWidth
= *(std::max_element(rOffsets
.begin(), rOffsets
.end()));
161 uno::Sequence
< double > setupDXArray( KernArraySpan rCharWidths
,
163 const OutDevState
& rState
)
165 // convert character widths from logical units
166 uno::Sequence
< double > aCharWidthSeq( nLen
);
167 double* pOutputWidths( aCharWidthSeq
.getArray() );
169 // #143885# maintain (nearly) full precision of DX
170 // array, by circumventing integer-based
172 const double nScale( rState
.mapModeTransform
.get(0,0) );
173 for( int i
= 0; i
< nLen
; ++i
)
175 // TODO(F2): use correct scale direction
176 *pOutputWidths
++ = rCharWidths
[i
] * nScale
;
179 return aCharWidthSeq
;
182 uno::Sequence
< double > setupDXArray( const OUString
& rText
,
185 VirtualDevice
const & rVDev
,
186 const OutDevState
& rState
)
188 // no external DX array given, create one from given
190 KernArray aCharWidths
;
192 rVDev
.GetTextArray( rText
, &aCharWidths
, nStartPos
, nLen
);
194 return setupDXArray( aCharWidths
, 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 uno::Sequence
< sal_Bool
>& rKashidas
,
233 const CanvasSharedPtr
& rCanvas
,
234 const OutDevState
& rState
,
235 const ::basegfx::B2DHomMatrix
* pTextTransform
)
237 ENSURE_OR_THROW( rOffsets
.hasElements(),
238 "::cppcanvas::internal::initArrayAction(): zero-length DX array" );
240 const ::basegfx::B2DPoint
aLocalStartPoint(
241 adaptStartPoint( rStartPoint
, rState
, rOffsets
) );
243 uno::Reference
< rendering::XCanvasFont
> xFont( rState
.xFont
);
246 init( o_rRenderState
, xFont
, aLocalStartPoint
, rState
, rCanvas
, *pTextTransform
);
248 init( o_rRenderState
, xFont
, aLocalStartPoint
, rState
, rCanvas
);
250 o_rTextLayout
= xFont
->createTextLayout(
251 rendering::StringContext( rText
, nStartPos
, nLen
),
252 rState
.textDirection
,
255 ENSURE_OR_THROW( o_rTextLayout
.is(),
256 "::cppcanvas::internal::initArrayAction(): Invalid font" );
258 o_rTextLayout
->applyLogicalAdvancements( rOffsets
);
259 o_rTextLayout
->applyKashidaPositions( rKashidas
);
263 double getLineWidth( ::VirtualDevice
const & rVDev
,
264 const OutDevState
& rState
,
265 const rendering::StringContext
& rStringContext
)
267 // TODO(F2): use correct scale direction
268 const ::basegfx::B2DSize
aSize( rVDev
.GetTextWidth( rStringContext
.Text
,
269 static_cast<sal_uInt16
>(rStringContext
.StartPosition
),
270 static_cast<sal_uInt16
>(rStringContext
.Length
) ),
273 return (rState
.mapModeTransform
* aSize
).getWidth();
276 uno::Sequence
< double >
277 calcSubsetOffsets( rendering::RenderState
& io_rRenderState
,
280 const uno::Reference
< rendering::XTextLayout
>& rOrigTextLayout
,
282 const ::cppcanvas::internal::Action::Subset
& rSubset
)
284 ENSURE_OR_THROW( rSubset
.mnSubsetEnd
> rSubset
.mnSubsetBegin
,
285 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
287 uno::Sequence
< double > aOrigOffsets( rOrigTextLayout
->queryLogicalAdvancements() );
288 const double* pOffsets( aOrigOffsets
.getConstArray() );
290 ENSURE_OR_THROW( aOrigOffsets
.getLength() >= rSubset
.mnSubsetEnd
,
291 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
294 // determine leftmost position in given subset range -
295 // as the DX array contains the output positions
296 // starting with the second character (the first is
297 // assumed to have output position 0), correct begin
299 const double nMinPos( rSubset
.mnSubsetBegin
<= 0 ? 0 :
300 *(std::min_element( pOffsets
+rSubset
.mnSubsetBegin
-1,
301 pOffsets
+rSubset
.mnSubsetEnd
)) );
303 // determine rightmost 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 nMaxPos(
309 *(std::max_element( pOffsets
+ (rSubset
.mnSubsetBegin
<= 0 ?
310 0 : rSubset
.mnSubsetBegin
-1),
311 pOffsets
+ rSubset
.mnSubsetEnd
)) );
313 // Logical advancements always increase in logical text order.
314 // For RTL text, nMaxPos is the distance from the right edge to
315 // the leftmost position in the subset, so we have to convert
316 // it to the offset from the origin (i.e. left edge ).
317 // LTR: |---- min --->|---- max --->| |
318 // RTL: | |<--- max ----|<--- min ---|
320 const double nOffset
= rOrigTextLayout
->getMainTextDirection()
321 ? nLayoutWidth
- nMaxPos
: nMinPos
;
324 // adapt render state, to move text output to given offset
327 // TODO(F1): Strictly speaking, we also have to adapt
328 // the clip here, which normally should _not_ move
329 // with the output offset. Neglected for now, as it
330 // does not matter for drawing layer output
334 ::basegfx::B2DHomMatrix aTranslation
;
335 if( rOrigTextLayout
->getFont()->getFontRequest().FontDescription
.IsVertical
== css::util::TriState_YES
)
337 // vertical text -> offset in y direction
338 aTranslation
.translate(0.0, nOffset
);
342 // horizontal text -> offset in x direction
343 aTranslation
.translate(nOffset
, 0.0);
346 ::canvas::tools::appendToRenderState( io_rRenderState
,
351 // reduce DX array to given substring
354 const sal_Int32
nNewElements( rSubset
.mnSubsetEnd
- rSubset
.mnSubsetBegin
);
355 uno::Sequence
< double > aAdaptedOffsets( nNewElements
);
356 double* pAdaptedOffsets( aAdaptedOffsets
.getArray() );
358 // move to new output position (subtract nMinPos,
359 // which is the new '0' position), copy only the range
360 // as given by rSubset.
361 std::transform( pOffsets
+ rSubset
.mnSubsetBegin
,
362 pOffsets
+ rSubset
.mnSubsetEnd
,
364 [nMinPos
](double aPos
) { return aPos
- nMinPos
; } );
369 return aAdaptedOffsets
;
372 uno::Reference
< rendering::XTextLayout
>
373 createSubsetLayout( const rendering::StringContext
& rOrigContext
,
374 const ::cppcanvas::internal::Action::Subset
& rSubset
,
375 const uno::Reference
< rendering::XTextLayout
>& rOrigTextLayout
)
377 // create temporary new text layout with subset string
380 const sal_Int32
nNewStartPos( rOrigContext
.StartPosition
+ std::min(
381 rSubset
.mnSubsetBegin
, rOrigContext
.Length
-1 ) );
382 const sal_Int32
nNewLength( std::max(
384 rSubset
.mnSubsetEnd
- rSubset
.mnSubsetBegin
,
385 rOrigContext
.Length
),
388 const rendering::StringContext
aContext( rOrigContext
.Text
,
392 uno::Reference
< rendering::XTextLayout
> xTextLayout(
393 rOrigTextLayout
->getFont()->createTextLayout( aContext
,
394 rOrigTextLayout
->getMainTextDirection(),
396 uno::UNO_SET_THROW
);
401 /** Setup subset text layout
403 @param io_rTextLayout
404 Must contain original (full set) text layout on input,
405 will contain subsetted text layout (or empty
406 reference, for empty subsets) on output.
408 @param io_rRenderState
409 Must contain original render state on input, will
410 contain shifted render state concatenated with
411 rTransformation on output.
413 @param rTransformation
414 Additional transformation, to be prepended to render
420 void createSubsetLayout( uno::Reference
< rendering::XTextLayout
>& io_rTextLayout
,
422 rendering::RenderState
& io_rRenderState
,
425 const ::basegfx::B2DHomMatrix
& rTransformation
,
426 const Action::Subset
& rSubset
)
428 ::canvas::tools::prependToRenderState(io_rRenderState
, rTransformation
);
430 if( rSubset
.mnSubsetBegin
== rSubset
.mnSubsetEnd
)
432 // empty range, empty layout
433 io_rTextLayout
.clear();
438 ENSURE_OR_THROW( io_rTextLayout
.is(),
439 "createSubsetLayout(): Invalid input layout" );
441 const rendering::StringContext
& rOrigContext( io_rTextLayout
->getText() );
443 if( rSubset
.mnSubsetBegin
== 0 &&
444 rSubset
.mnSubsetEnd
== rOrigContext
.Length
)
446 // full range, no need for subsetting
450 uno::Reference
< rendering::XTextLayout
> xTextLayout(
451 createSubsetLayout( rOrigContext
, rSubset
, io_rTextLayout
) );
453 if( xTextLayout
.is() )
455 xTextLayout
->applyLogicalAdvancements(
456 calcSubsetOffsets( io_rRenderState
,
462 uno::Sequence
< sal_Bool
> aOrigKashidaPositions(io_rTextLayout
->queryKashidaPositions());
463 uno::Sequence
< sal_Bool
> aKashidaPositions(aOrigKashidaPositions
.getArray() + rSubset
.mnSubsetBegin
,
464 rSubset
.mnSubsetEnd
- rSubset
.mnSubsetBegin
);
465 xTextLayout
->applyKashidaPositions(aKashidaPositions
);
468 io_rTextLayout
= xTextLayout
;
472 /** Interface for renderEffectText functor below.
474 This is interface is used from the renderEffectText()
475 method below, to call the client implementation.
480 virtual ~TextRenderer() {}
482 /// Render text with given RenderState
483 virtual bool operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
, bool bNormalText
) const = 0;
486 /** Render effect text.
489 Functor object, will be called to render the actual
490 part of the text effect (the text itself and the means
491 to render it are unknown to this method)
493 bool renderEffectText( const TextRenderer
& rRenderer
,
494 const rendering::RenderState
& rRenderState
,
495 const uno::Reference
< rendering::XCanvas
>& xCanvas
,
496 const ::Color
& rShadowColor
,
497 const ::basegfx::B2DSize
& rShadowOffset
,
498 const ::Color
& rReliefColor
,
499 const ::basegfx::B2DSize
& rReliefOffset
,
500 const ::Color
& rTextFillColor
)
502 ::Color
aEmptyColor( COL_AUTO
);
503 uno::Reference
<rendering::XColorSpace
> xColorSpace(
504 xCanvas
->getDevice()->getDeviceColorSpace() );
506 // draw shadow text, if enabled
507 if( rShadowColor
!= aEmptyColor
)
509 rendering::RenderState
aShadowState( rRenderState
);
510 ::basegfx::B2DHomMatrix aTranslate
;
512 aTranslate
.translate(rShadowOffset
.getWidth(),
513 rShadowOffset
.getHeight());
515 ::canvas::tools::appendToRenderState(aShadowState
, aTranslate
);
517 aShadowState
.DeviceColor
=
518 vcl::unotools::colorToDoubleSequence( rShadowColor
,
521 rRenderer( aShadowState
, rTextFillColor
, false );
524 // draw relief text, if enabled
525 if( rReliefColor
!= aEmptyColor
)
527 rendering::RenderState
aReliefState( rRenderState
);
528 ::basegfx::B2DHomMatrix aTranslate
;
530 aTranslate
.translate(rReliefOffset
.getWidth(),
531 rReliefOffset
.getHeight());
533 ::canvas::tools::appendToRenderState(aReliefState
, aTranslate
);
535 aReliefState
.DeviceColor
=
536 vcl::unotools::colorToDoubleSequence( rReliefColor
,
539 rRenderer( aReliefState
, rTextFillColor
, false );
543 rRenderer( rRenderState
, rTextFillColor
, true );
549 ::basegfx::B2DRange
calcEffectTextBounds( const ::basegfx::B2DRange
& rTextBounds
,
550 const ::basegfx::B2DRange
& rLineBounds
,
551 const ::basegfx::B2DSize
& rReliefOffset
,
552 const ::basegfx::B2DSize
& rShadowOffset
,
553 const rendering::RenderState
& rRenderState
,
554 const rendering::ViewState
& rViewState
)
556 ::basegfx::B2DRange
aBounds( rTextBounds
);
558 // add extends of text lines
559 aBounds
.expand( rLineBounds
);
561 // TODO(Q3): Provide this functionality at the B2DRange
562 ::basegfx::B2DRange
aTotalBounds( aBounds
);
564 ::basegfx::B2DRange( aBounds
.getMinX() + rReliefOffset
.getWidth(),
565 aBounds
.getMinY() + rReliefOffset
.getHeight(),
566 aBounds
.getMaxX() + rReliefOffset
.getWidth(),
567 aBounds
.getMaxY() + rReliefOffset
.getHeight() ) );
569 ::basegfx::B2DRange( aBounds
.getMinX() + rShadowOffset
.getWidth(),
570 aBounds
.getMinY() + rShadowOffset
.getHeight(),
571 aBounds
.getMaxX() + rShadowOffset
.getWidth(),
572 aBounds
.getMaxY() + rShadowOffset
.getHeight() ) );
574 return tools::calcDevicePixelBounds( aTotalBounds
,
579 void initEffectLinePolyPolygon( ::basegfx::B2DSize
& o_rOverallSize
,
580 uno::Reference
< rendering::XPolyPolygon2D
>& o_rTextLines
,
581 const CanvasSharedPtr
& rCanvas
,
583 const tools::TextLineInfo
& rLineInfo
)
585 const ::basegfx::B2DPolyPolygon
aPoly(
586 tools::createTextLinesPolyPolygon( 0.0, nLineWidth
,
588 auto aRange
= basegfx::utils::getRange( aPoly
).getRange();
589 o_rOverallSize
= basegfx::B2DSize(aRange
.getX(), aRange
.getY());
591 o_rTextLines
= ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
592 rCanvas
->getUNOCanvas()->getDevice(),
597 class TextAction
: public Action
600 TextAction( const ::basegfx::B2DPoint
& rStartPoint
,
601 const OUString
& rString
,
604 const CanvasSharedPtr
& rCanvas
,
605 const OutDevState
& rState
);
607 TextAction( const ::basegfx::B2DPoint
& rStartPoint
,
608 const OUString
& rString
,
611 const CanvasSharedPtr
& rCanvas
,
612 const OutDevState
& rState
,
613 const ::basegfx::B2DHomMatrix
& rTextTransform
);
615 TextAction(const TextAction
&) = delete;
616 const TextAction
& operator=(const TextAction
&) = delete;
618 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
619 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
620 const Subset
& rSubset
) const override
;
622 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
623 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
624 const Subset
& rSubset
) const override
;
626 virtual sal_Int32
getActionCount() const override
;
629 // TODO(P2): This is potentially a real mass object
630 // (every character might be a separate TextAction),
631 // thus, make it as lightweight as possible. For
632 // example, share common RenderState among several
633 // TextActions, maybe using maOffsets for the
636 uno::Reference
< rendering::XCanvasFont
> mxFont
;
637 const rendering::StringContext maStringContext
;
638 const CanvasSharedPtr mpCanvas
;
639 rendering::RenderState maState
;
640 const sal_Int8 maTextDirection
;
643 TextAction::TextAction( const ::basegfx::B2DPoint
& rStartPoint
,
644 const OUString
& rString
,
647 const CanvasSharedPtr
& rCanvas
,
648 const OutDevState
& rState
) :
649 mxFont( rState
.xFont
),
650 maStringContext( rString
, nStartPos
, nLen
),
652 maTextDirection( rState
.textDirection
)
654 init( maState
, mxFont
,
658 ENSURE_OR_THROW( mxFont
.is(),
659 "::cppcanvas::internal::TextAction(): Invalid font" );
662 TextAction::TextAction( const ::basegfx::B2DPoint
& rStartPoint
,
663 const OUString
& rString
,
666 const CanvasSharedPtr
& rCanvas
,
667 const OutDevState
& rState
,
668 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
669 mxFont( rState
.xFont
),
670 maStringContext( rString
, nStartPos
, nLen
),
672 maTextDirection( rState
.textDirection
)
674 init( maState
, mxFont
,
676 rState
, rCanvas
, rTextTransform
);
678 ENSURE_OR_THROW( mxFont
.is(),
679 "::cppcanvas::internal::TextAction(): Invalid font" );
682 bool TextAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
684 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextAction::render()" );
685 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextAction: 0x" << std::hex
<< this );
687 rendering::RenderState
aLocalState( maState
);
688 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
690 mpCanvas
->getUNOCanvas()->drawText( maStringContext
, mxFont
,
691 mpCanvas
->getViewState(), aLocalState
, maTextDirection
);
696 bool TextAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
697 const Subset
& /*rSubset*/ ) const
699 SAL_WARN( "cppcanvas.emf", "TextAction::renderSubset(): Subset not supported by this object" );
701 // TODO(P1): Retrieve necessary font metric info for
702 // TextAction from XCanvas. Currently, the
703 // TextActionFactory does not generate this object for
704 // _subsettable_ text
705 return render( rTransformation
);
708 ::basegfx::B2DRange
TextAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
710 // create XTextLayout, to have the
711 // XTextLayout::queryTextBounds() method available
712 uno::Reference
< rendering::XTextLayout
> xTextLayout(
713 mxFont
->createTextLayout(
718 rendering::RenderState
aLocalState( maState
);
719 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
721 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
722 xTextLayout
->queryTextBounds() ),
723 mpCanvas
->getViewState(),
727 ::basegfx::B2DRange
TextAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
728 const Subset
& /*rSubset*/ ) const
730 SAL_WARN( "cppcanvas.emf", "TextAction::getBounds(): Subset not supported by this object" );
732 // TODO(P1): Retrieve necessary font metric info for
733 // TextAction from XCanvas. Currently, the
734 // TextActionFactory does not generate this object for
735 // _subsettable_ text
736 return getBounds( rTransformation
);
739 sal_Int32
TextAction::getActionCount() const
741 // TODO(P1): Retrieve necessary font metric info for
742 // TextAction from XCanvas. Currently, the
743 // TextActionFactory does not generate this object for
744 // _subsettable_ text
749 class EffectTextAction
:
754 EffectTextAction( const ::basegfx::B2DPoint
& rStartPoint
,
755 const ::basegfx::B2DSize
& rReliefOffset
,
756 const ::Color
& rReliefColor
,
757 const ::basegfx::B2DSize
& rShadowOffset
,
758 const ::Color
& rShadowColor
,
759 const ::Color
& rTextFillColor
,
760 const OUString
& rText
,
763 VirtualDevice
const & rVDev
,
764 const CanvasSharedPtr
& rCanvas
,
765 const OutDevState
& rState
);
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 ::Color
& rTextFillColor
,
773 const OUString
& rText
,
776 VirtualDevice
const & rVDev
,
777 const CanvasSharedPtr
& rCanvas
,
778 const OutDevState
& rState
,
779 const ::basegfx::B2DHomMatrix
& rTextTransform
);
781 EffectTextAction(const EffectTextAction
&) = delete;
782 const EffectTextAction
& operator=(const EffectTextAction
&) = delete;
784 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
785 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
786 const Subset
& rSubset
) const override
;
788 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
789 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
790 const Subset
& rSubset
) const override
;
792 virtual sal_Int32
getActionCount() const override
;
795 /// Interface TextRenderer
796 virtual bool operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
, bool bNormalText
) const override
;
798 geometry::RealRectangle2D
queryTextBounds() const;
799 css::uno::Reference
<css::rendering::XPolyPolygon2D
> queryTextBounds(const uno::Reference
<rendering::XCanvas
>& rCanvas
) const;
801 // TODO(P2): This is potentially a real mass object
802 // (every character might be a separate TextAction),
803 // thus, make it as lightweight as possible. For
804 // example, share common RenderState among several
805 // TextActions, maybe using maOffsets for the
808 uno::Reference
< rendering::XCanvasFont
> mxFont
;
809 const rendering::StringContext maStringContext
;
810 const CanvasSharedPtr mpCanvas
;
811 rendering::RenderState maState
;
812 const tools::TextLineInfo maTextLineInfo
;
813 ::basegfx::B2DSize maLinesOverallSize
;
814 uno::Reference
< rendering::XPolyPolygon2D
> mxTextLines
;
815 const ::basegfx::B2DSize maReliefOffset
;
816 const ::Color maReliefColor
;
817 const ::basegfx::B2DSize maShadowOffset
;
818 const ::Color maShadowColor
;
819 const ::Color maTextFillColor
;
820 const sal_Int8 maTextDirection
;
823 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint
& rStartPoint
,
824 const ::basegfx::B2DSize
& rReliefOffset
,
825 const ::Color
& rReliefColor
,
826 const ::basegfx::B2DSize
& rShadowOffset
,
827 const ::Color
& rShadowColor
,
828 const ::Color
& rTextFillColor
,
829 const OUString
& rText
,
832 VirtualDevice
const & rVDev
,
833 const CanvasSharedPtr
& rCanvas
,
834 const OutDevState
& rState
) :
835 mxFont( rState
.xFont
),
836 maStringContext( rText
, nStartPos
, nLen
),
838 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
839 maReliefOffset( rReliefOffset
),
840 maReliefColor( rReliefColor
),
841 maShadowOffset( rShadowOffset
),
842 maShadowColor( rShadowColor
),
843 maTextFillColor( rTextFillColor
),
844 maTextDirection( rState
.textDirection
)
846 const double nLineWidth(getLineWidth( rVDev
, rState
, maStringContext
));
847 initEffectLinePolyPolygon( maLinesOverallSize
,
853 init( maState
, mxFont
,
857 ENSURE_OR_THROW( mxFont
.is() && mxTextLines
.is(),
858 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
861 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint
& rStartPoint
,
862 const ::basegfx::B2DSize
& rReliefOffset
,
863 const ::Color
& rReliefColor
,
864 const ::basegfx::B2DSize
& rShadowOffset
,
865 const ::Color
& rShadowColor
,
866 const ::Color
& rTextFillColor
,
867 const OUString
& rText
,
870 VirtualDevice
const & rVDev
,
871 const CanvasSharedPtr
& rCanvas
,
872 const OutDevState
& rState
,
873 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
874 mxFont( rState
.xFont
),
875 maStringContext( rText
, nStartPos
, nLen
),
877 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
878 maReliefOffset( rReliefOffset
),
879 maReliefColor( rReliefColor
),
880 maShadowOffset( rShadowOffset
),
881 maShadowColor( rShadowColor
),
882 maTextFillColor( rTextFillColor
),
883 maTextDirection( rState
.textDirection
)
885 const double nLineWidth( getLineWidth( rVDev
, rState
, maStringContext
) );
886 initEffectLinePolyPolygon( maLinesOverallSize
,
892 init( maState
, mxFont
,
894 rState
, rCanvas
, rTextTransform
);
896 ENSURE_OR_THROW( mxFont
.is() && mxTextLines
.is(),
897 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
900 bool EffectTextAction::operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
, bool /*bNormalText*/ ) const
902 const rendering::ViewState
& rViewState( mpCanvas
->getViewState() );
903 const uno::Reference
< rendering::XCanvas
>& rCanvas( mpCanvas
->getUNOCanvas() );
905 //rhbz#1589029 non-transparent text fill background support
906 if (rTextFillColor
!= COL_AUTO
)
908 rendering::RenderState
aLocalState( rRenderState
);
909 aLocalState
.DeviceColor
= vcl::unotools::colorToDoubleSequence(
910 rTextFillColor
, rCanvas
->getDevice()->getDeviceColorSpace());
911 auto xTextBounds
= queryTextBounds(rCanvas
);
912 // background of text
913 rCanvas
->fillPolyPolygon(xTextBounds
, rViewState
, aLocalState
);
917 rCanvas
->fillPolyPolygon( mxTextLines
,
921 rCanvas
->drawText( maStringContext
, mxFont
,
929 bool EffectTextAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
931 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextAction::render()" );
932 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextAction: 0x" << std::hex
<< this );
934 rendering::RenderState
aLocalState( maState
);
935 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
937 return renderEffectText( *this,
939 mpCanvas
->getUNOCanvas(),
947 bool EffectTextAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
948 const Subset
& /*rSubset*/ ) const
950 SAL_WARN( "cppcanvas.emf", "EffectTextAction::renderSubset(): Subset not supported by this object" );
952 // TODO(P1): Retrieve necessary font metric info for
953 // TextAction from XCanvas. Currently, the
954 // TextActionFactory does not generate this object for
956 return render( rTransformation
);
959 geometry::RealRectangle2D
EffectTextAction::queryTextBounds() const
961 // create XTextLayout, to have the
962 // XTextLayout::queryTextBounds() method available
963 uno::Reference
< rendering::XTextLayout
> xTextLayout(
964 mxFont
->createTextLayout(
969 return xTextLayout
->queryTextBounds();
972 css::uno::Reference
<css::rendering::XPolyPolygon2D
> EffectTextAction::queryTextBounds(const uno::Reference
<rendering::XCanvas
>& rCanvas
) const
974 auto aTextBounds
= queryTextBounds();
975 auto aB2DBounds
= ::basegfx::unotools::b2DRectangleFromRealRectangle2D(aTextBounds
);
976 auto aTextBoundsPoly
= ::basegfx::utils::createPolygonFromRect(aB2DBounds
);
977 return ::basegfx::unotools::xPolyPolygonFromB2DPolygon(rCanvas
->getDevice(), aTextBoundsPoly
);
980 ::basegfx::B2DRange
EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
982 rendering::RenderState
aLocalState( maState
);
983 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
985 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
987 ::basegfx::B2DRange( 0,0,
988 maLinesOverallSize
.getWidth(),
989 maLinesOverallSize
.getHeight() ),
993 mpCanvas
->getViewState() );
996 ::basegfx::B2DRange
EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
997 const Subset
& /*rSubset*/ ) const
999 SAL_WARN( "cppcanvas.emf", "EffectTextAction::getBounds(): Subset not supported by this object" );
1001 // TODO(P1): Retrieve necessary font metric info for
1002 // TextAction from XCanvas. Currently, the
1003 // TextActionFactory does not generate this object for
1004 // _subsettable_ text
1005 return getBounds( rTransformation
);
1008 sal_Int32
EffectTextAction::getActionCount() const
1010 // TODO(P1): Retrieve necessary font metric info for
1011 // TextAction from XCanvas. Currently, the
1012 // TextActionFactory does not generate this object for
1018 class TextArrayAction
: public Action
1021 TextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1022 const OUString
& rString
,
1023 sal_Int32 nStartPos
,
1025 const uno::Sequence
< double >& rOffsets
,
1026 const uno::Sequence
< sal_Bool
>& rKashidas
,
1027 const CanvasSharedPtr
& rCanvas
,
1028 const OutDevState
& rState
);
1030 TextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1031 const OUString
& rString
,
1032 sal_Int32 nStartPos
,
1034 const uno::Sequence
< double >& rOffsets
,
1035 const uno::Sequence
< sal_Bool
>& rKashidas
,
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 uno::Sequence
< sal_Bool
>& rKashidas
,
1073 const CanvasSharedPtr
& rCanvas
,
1074 const OutDevState
& rState
) :
1077 initLayoutWidth(mnLayoutWidth
, rOffsets
);
1079 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 uno::Sequence
< sal_Bool
>& rKashidas
,
1097 const CanvasSharedPtr
& rCanvas
,
1098 const OutDevState
& rState
,
1099 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
1102 initLayoutWidth(mnLayoutWidth
, rOffsets
);
1104 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 const uno::Sequence
< sal_Bool
>& rKashidas
,
1222 VirtualDevice
const & rVDev
,
1223 const CanvasSharedPtr
& rCanvas
,
1224 const OutDevState
& rState
);
1225 EffectTextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1226 const ::basegfx::B2DSize
& rReliefOffset
,
1227 const ::Color
& rReliefColor
,
1228 const ::basegfx::B2DSize
& rShadowOffset
,
1229 const ::Color
& rShadowColor
,
1230 const ::Color
& rTextFillColor
,
1231 const OUString
& rText
,
1232 sal_Int32 nStartPos
,
1234 const uno::Sequence
< double >& rOffsets
,
1235 const uno::Sequence
< sal_Bool
>& rKashidas
,
1236 VirtualDevice
const & rVDev
,
1237 const CanvasSharedPtr
& rCanvas
,
1238 const OutDevState
& rState
,
1239 const ::basegfx::B2DHomMatrix
& rTextTransform
);
1241 EffectTextArrayAction(const EffectTextArrayAction
&) = delete;
1242 const EffectTextArrayAction
& operator=(const EffectTextArrayAction
&) = delete;
1244 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1245 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1246 const Subset
& rSubset
) const override
;
1248 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1249 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1250 const Subset
& rSubset
) const override
;
1252 virtual sal_Int32
getActionCount() const override
;
1255 // TextRenderer interface
1256 virtual bool operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
, bool bNormalText
) const override
;
1258 css::uno::Reference
<css::rendering::XPolyPolygon2D
> queryTextBounds(const uno::Reference
<rendering::XCanvas
>& rCanvas
) const;
1260 // TODO(P2): This is potentially a real mass object
1261 // (every character might be a separate TextAction),
1262 // thus, make it as lightweight as possible. For
1263 // example, share common RenderState among several
1264 // TextActions, maybe using maOffsets for the
1267 uno::Reference
< rendering::XTextLayout
> mxTextLayout
;
1268 const CanvasSharedPtr mpCanvas
;
1269 rendering::RenderState maState
;
1270 const tools::TextLineInfo maTextLineInfo
;
1271 TextLinesHelper maTextLinesHelper
;
1272 const ::basegfx::B2DSize maReliefOffset
;
1273 const ::Color maReliefColor
;
1274 const ::basegfx::B2DSize maShadowOffset
;
1275 const ::Color maShadowColor
;
1276 const ::Color maTextFillColor
;
1277 double mnLayoutWidth
;
1280 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1281 const ::basegfx::B2DSize
& rReliefOffset
,
1282 const ::Color
& rReliefColor
,
1283 const ::basegfx::B2DSize
& rShadowOffset
,
1284 const ::Color
& rShadowColor
,
1285 const ::Color
& rTextFillColor
,
1286 const OUString
& rText
,
1287 sal_Int32 nStartPos
,
1289 const uno::Sequence
< double >& rOffsets
,
1290 const uno::Sequence
< sal_Bool
>& rKashidas
,
1291 VirtualDevice
const & rVDev
,
1292 const CanvasSharedPtr
& rCanvas
,
1293 const OutDevState
& rState
) :
1294 mpCanvas( rCanvas
),
1295 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
1296 maTextLinesHelper(mpCanvas
, rState
),
1297 maReliefOffset( rReliefOffset
),
1298 maReliefColor( rReliefColor
),
1299 maShadowOffset( rShadowOffset
),
1300 maShadowColor( rShadowColor
),
1301 maTextFillColor( rTextFillColor
)
1303 initLayoutWidth(mnLayoutWidth
, rOffsets
);
1305 maTextLinesHelper
.init(mnLayoutWidth
, maTextLineInfo
);
1307 initArrayAction( maState
,
1319 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint
& rStartPoint
,
1320 const ::basegfx::B2DSize
& rReliefOffset
,
1321 const ::Color
& rReliefColor
,
1322 const ::basegfx::B2DSize
& rShadowOffset
,
1323 const ::Color
& rShadowColor
,
1324 const ::Color
& rTextFillColor
,
1325 const OUString
& rText
,
1326 sal_Int32 nStartPos
,
1328 const uno::Sequence
< double >& rOffsets
,
1329 const uno::Sequence
< sal_Bool
>& rKashidas
,
1330 VirtualDevice
const & rVDev
,
1331 const CanvasSharedPtr
& rCanvas
,
1332 const OutDevState
& rState
,
1333 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
1334 mpCanvas( rCanvas
),
1335 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
1336 maTextLinesHelper(mpCanvas
, rState
),
1337 maReliefOffset( rReliefOffset
),
1338 maReliefColor( rReliefColor
),
1339 maShadowOffset( rShadowOffset
),
1340 maShadowColor( rShadowColor
),
1341 maTextFillColor( rTextFillColor
)
1343 initLayoutWidth(mnLayoutWidth
, rOffsets
);
1345 maTextLinesHelper
.init(mnLayoutWidth
, maTextLineInfo
);
1347 initArrayAction( maState
,
1360 css::uno::Reference
<css::rendering::XPolyPolygon2D
> EffectTextArrayAction::queryTextBounds(const uno::Reference
<rendering::XCanvas
>& rCanvas
) const
1362 const geometry::RealRectangle2D
aTextBounds(mxTextLayout
->queryTextBounds());
1363 auto aB2DBounds
= ::basegfx::unotools::b2DRectangleFromRealRectangle2D(aTextBounds
);
1364 auto aTextBoundsPoly
= ::basegfx::utils::createPolygonFromRect(aB2DBounds
);
1365 return ::basegfx::unotools::xPolyPolygonFromB2DPolygon(rCanvas
->getDevice(), aTextBoundsPoly
);
1368 bool EffectTextArrayAction::operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
, bool bNormalText
) const
1370 const rendering::ViewState
& rViewState( mpCanvas
->getViewState() );
1371 const uno::Reference
< rendering::XCanvas
>& rCanvas( mpCanvas
->getUNOCanvas() );
1373 //rhbz#1589029 non-transparent text fill background support
1374 if (rTextFillColor
!= COL_AUTO
)
1376 rendering::RenderState
aLocalState(rRenderState
);
1377 aLocalState
.DeviceColor
= vcl::unotools::colorToDoubleSequence(
1378 rTextFillColor
, rCanvas
->getDevice()->getDeviceColorSpace());
1379 auto xTextBounds
= queryTextBounds(rCanvas
);
1380 // background of text
1381 rCanvas
->fillPolyPolygon(xTextBounds
, rViewState
, aLocalState
);
1385 maTextLinesHelper
.render(rRenderState
, bNormalText
);
1387 rCanvas
->drawTextLayout( mxTextLayout
,
1394 bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1396 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::render()" );
1397 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex
<< this );
1399 rendering::RenderState
aLocalState( maState
);
1400 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1402 return renderEffectText( *this,
1404 mpCanvas
->getUNOCanvas(),
1412 class EffectTextArrayRenderHelper
: public TextRenderer
1415 EffectTextArrayRenderHelper( const uno::Reference
< rendering::XCanvas
>& rCanvas
,
1416 const uno::Reference
< rendering::XTextLayout
>& rTextLayout
,
1417 const TextLinesHelper
& rTextLinesHelper
,
1418 const rendering::ViewState
& rViewState
) :
1419 mrCanvas( rCanvas
),
1420 mrTextLayout( rTextLayout
),
1421 mrTextLinesHelper( rTextLinesHelper
),
1422 mrViewState( rViewState
)
1426 // TextRenderer interface
1427 virtual bool operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
,bool bNormalText
) const override
1429 mrTextLinesHelper
.render(rRenderState
, bNormalText
);
1431 //rhbz#1589029 non-transparent text fill background support
1432 if (rTextFillColor
!= COL_AUTO
)
1434 rendering::RenderState
aLocalState(rRenderState
);
1435 aLocalState
.DeviceColor
= vcl::unotools::colorToDoubleSequence(
1436 rTextFillColor
, mrCanvas
->getDevice()->getDeviceColorSpace());
1437 auto xTextBounds
= queryTextBounds();
1438 // background of text
1439 mrCanvas
->fillPolyPolygon(xTextBounds
, mrViewState
, aLocalState
);
1442 mrCanvas
->drawTextLayout( mrTextLayout
,
1451 css::uno::Reference
<css::rendering::XPolyPolygon2D
> queryTextBounds() const
1453 const geometry::RealRectangle2D
aTextBounds(mrTextLayout
->queryTextBounds());
1454 auto aB2DBounds
= ::basegfx::unotools::b2DRectangleFromRealRectangle2D(aTextBounds
);
1455 auto aTextBoundsPoly
= ::basegfx::utils::createPolygonFromRect(aB2DBounds
);
1456 return ::basegfx::unotools::xPolyPolygonFromB2DPolygon(mrCanvas
->getDevice(), aTextBoundsPoly
);
1459 const uno::Reference
< rendering::XCanvas
>& mrCanvas
;
1460 const uno::Reference
< rendering::XTextLayout
>& mrTextLayout
;
1461 const TextLinesHelper
& mrTextLinesHelper
;
1462 const rendering::ViewState
& mrViewState
;
1465 bool EffectTextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1466 const Subset
& rSubset
) const
1468 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::renderSubset()" );
1469 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex
<< this );
1471 rendering::RenderState
aLocalState( maState
);
1472 uno::Reference
< rendering::XTextLayout
> xTextLayout( mxTextLayout
);
1473 const geometry::RealRectangle2D
aTextBounds( mxTextLayout
->queryTextBounds() );
1475 double nMinPos(0.0);
1476 double nMaxPos(aTextBounds
.X2
- aTextBounds
.X1
);
1478 createSubsetLayout( xTextLayout
,
1486 if( !xTextLayout
.is() )
1487 return true; // empty layout, render nothing
1490 // create and setup local line polygon
1491 // ===================================
1493 uno::Reference
< rendering::XCanvas
> xCanvas( mpCanvas
->getUNOCanvas() );
1494 const rendering::ViewState
& rViewState( mpCanvas
->getViewState() );
1496 TextLinesHelper aHelper
= maTextLinesHelper
;
1497 aHelper
.init(nMaxPos
- nMinPos
, maTextLineInfo
);
1500 // render everything
1501 // =================
1503 return renderEffectText(
1504 EffectTextArrayRenderHelper( xCanvas
,
1517 ::basegfx::B2DRange
EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1519 rendering::RenderState
aLocalState( maState
);
1520 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1522 ::basegfx::B2DSize aSize
= maTextLinesHelper
.getOverallSize();
1524 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1525 mxTextLayout
->queryTextBounds() ),
1526 basegfx::B2DRange(0, 0,
1532 mpCanvas
->getViewState() );
1535 ::basegfx::B2DRange
EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1536 const Subset
& rSubset
) const
1538 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::getBounds( subset )" );
1539 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex
<< this );
1541 rendering::RenderState
aLocalState( maState
);
1542 uno::Reference
< rendering::XTextLayout
> xTextLayout( mxTextLayout
);
1543 const geometry::RealRectangle2D
aTextBounds( mxTextLayout
->queryTextBounds() );
1545 double nMinPos(0.0);
1546 double nMaxPos(aTextBounds
.X2
- aTextBounds
.X1
);
1548 createSubsetLayout( xTextLayout
,
1556 if( !xTextLayout
.is() )
1557 return ::basegfx::B2DRange(); // empty layout, empty bounds
1560 // create and setup local line polygon
1561 // ===================================
1563 const ::basegfx::B2DPolyPolygon
aPoly(
1564 tools::createTextLinesPolyPolygon(
1565 0.0, nMaxPos
- nMinPos
,
1568 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1569 xTextLayout
->queryTextBounds() ),
1570 ::basegfx::utils::getRange( aPoly
),
1574 mpCanvas
->getViewState() );
1577 sal_Int32
EffectTextArrayAction::getActionCount() const
1579 const rendering::StringContext
& rOrigContext( mxTextLayout
->getText() );
1581 return rOrigContext
.Length
;
1585 class OutlineAction
:
1590 OutlineAction( const ::basegfx::B2DPoint
& rStartPoint
,
1591 const ::basegfx::B2DSize
& rReliefOffset
,
1592 const ::Color
& rReliefColor
,
1593 const ::basegfx::B2DSize
& rShadowOffset
,
1594 const ::Color
& rShadowColor
,
1595 const ::basegfx::B2DRectangle
& rOutlineBounds
,
1596 uno::Reference
< rendering::XPolyPolygon2D
> xTextPoly
,
1597 const uno::Sequence
< double >& rOffsets
,
1598 VirtualDevice
const & rVDev
,
1599 const CanvasSharedPtr
& rCanvas
,
1600 const OutDevState
& rState
);
1601 OutlineAction( const ::basegfx::B2DPoint
& rStartPoint
,
1602 const ::basegfx::B2DSize
& rReliefOffset
,
1603 const ::Color
& rReliefColor
,
1604 const ::basegfx::B2DSize
& rShadowOffset
,
1605 const ::Color
& rShadowColor
,
1606 const ::basegfx::B2DRectangle
& rOutlineBounds
,
1607 uno::Reference
< rendering::XPolyPolygon2D
> xTextPoly
,
1608 const uno::Sequence
< double >& rOffsets
,
1609 VirtualDevice
const & rVDev
,
1610 const CanvasSharedPtr
& rCanvas
,
1611 const OutDevState
& rState
,
1612 const ::basegfx::B2DHomMatrix
& rTextTransform
);
1614 OutlineAction(const OutlineAction
&) = delete;
1615 const OutlineAction
& operator=(const OutlineAction
&) = delete;
1617 virtual bool render( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1618 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1619 const Subset
& rSubset
) const override
;
1621 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
1622 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1623 const Subset
& rSubset
) const override
;
1625 virtual sal_Int32
getActionCount() const override
;
1628 // TextRenderer interface
1629 virtual bool operator()( const rendering::RenderState
& rRenderState
, const ::Color
& rTextFillColor
, bool bNormalText
) const override
;
1631 // TODO(P2): This is potentially a real mass object
1632 // (every character might be a separate TextAction),
1633 // thus, make it as lightweight as possible. For
1634 // example, share common RenderState among several
1635 // TextActions, maybe using maOffsets for the
1638 uno::Reference
< rendering::XPolyPolygon2D
> mxTextPoly
;
1640 const uno::Sequence
< double > maOffsets
;
1641 const CanvasSharedPtr mpCanvas
;
1642 rendering::RenderState maState
;
1643 double mnOutlineWidth
;
1644 const uno::Sequence
< double > maFillColor
;
1645 const tools::TextLineInfo maTextLineInfo
;
1646 ::basegfx::B2DSize maLinesOverallSize
;
1647 const ::basegfx::B2DRectangle maOutlineBounds
;
1648 uno::Reference
< rendering::XPolyPolygon2D
> mxTextLines
;
1649 const ::basegfx::B2DSize maReliefOffset
;
1650 const ::Color maReliefColor
;
1651 const ::basegfx::B2DSize maShadowOffset
;
1652 const ::Color maShadowColor
;
1653 const ::Color maTextFillColor
;
1656 double calcOutlineWidth( const OutDevState
& rState
,
1657 VirtualDevice
const & rVDev
)
1659 const ::basegfx::B2DSize
aFontSize( 0,
1660 rVDev
.GetFont().GetFontHeight() / 64.0 );
1662 const double nOutlineWidth(
1663 (rState
.mapModeTransform
* aFontSize
).getHeight() );
1665 return nOutlineWidth
< 1.0 ? 1.0 : nOutlineWidth
;
1668 OutlineAction::OutlineAction( const ::basegfx::B2DPoint
& rStartPoint
,
1669 const ::basegfx::B2DSize
& rReliefOffset
,
1670 const ::Color
& rReliefColor
,
1671 const ::basegfx::B2DSize
& rShadowOffset
,
1672 const ::Color
& rShadowColor
,
1673 const ::basegfx::B2DRectangle
& rOutlineBounds
,
1674 uno::Reference
< rendering::XPolyPolygon2D
> xTextPoly
,
1675 const uno::Sequence
< double >& rOffsets
,
1676 VirtualDevice
const & rVDev
,
1677 const CanvasSharedPtr
& rCanvas
,
1678 const OutDevState
& rState
) :
1679 mxTextPoly(std::move( xTextPoly
)),
1680 maOffsets( rOffsets
),
1681 mpCanvas( rCanvas
),
1682 mnOutlineWidth( calcOutlineWidth(rState
,rVDev
) ),
1684 vcl::unotools::colorToDoubleSequence(
1686 rCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1687 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
1688 maOutlineBounds( rOutlineBounds
),
1689 maReliefOffset( rReliefOffset
),
1690 maReliefColor( rReliefColor
),
1691 maShadowOffset( rShadowOffset
),
1692 maShadowColor( rShadowColor
)
1694 double nLayoutWidth
= 0.0;
1696 initLayoutWidth(nLayoutWidth
, rOffsets
);
1698 initEffectLinePolyPolygon( maLinesOverallSize
,
1710 OutlineAction::OutlineAction( const ::basegfx::B2DPoint
& rStartPoint
,
1711 const ::basegfx::B2DSize
& rReliefOffset
,
1712 const ::Color
& rReliefColor
,
1713 const ::basegfx::B2DSize
& rShadowOffset
,
1714 const ::Color
& rShadowColor
,
1715 const ::basegfx::B2DRectangle
& rOutlineBounds
,
1716 uno::Reference
< rendering::XPolyPolygon2D
> xTextPoly
,
1717 const uno::Sequence
< double >& rOffsets
,
1718 VirtualDevice
const & rVDev
,
1719 const CanvasSharedPtr
& rCanvas
,
1720 const OutDevState
& rState
,
1721 const ::basegfx::B2DHomMatrix
& rTextTransform
) :
1722 mxTextPoly(std::move( xTextPoly
)),
1723 maOffsets( rOffsets
),
1724 mpCanvas( rCanvas
),
1725 mnOutlineWidth( calcOutlineWidth(rState
,rVDev
) ),
1727 vcl::unotools::colorToDoubleSequence(
1729 rCanvas
->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1730 maTextLineInfo( tools::createTextLineInfo( rVDev
, rState
) ),
1731 maOutlineBounds( rOutlineBounds
),
1732 maReliefOffset( rReliefOffset
),
1733 maReliefColor( rReliefColor
),
1734 maShadowOffset( rShadowOffset
),
1735 maShadowColor( rShadowColor
)
1737 double nLayoutWidth
= 0.0;
1738 initLayoutWidth(nLayoutWidth
, rOffsets
);
1740 initEffectLinePolyPolygon( maLinesOverallSize
,
1753 bool OutlineAction::operator()( const rendering::RenderState
& rRenderState
, const ::Color
& /*rTextFillColor*/, bool /*bNormalText*/ ) const
1755 const rendering::ViewState
& rViewState( mpCanvas
->getViewState() );
1756 const uno::Reference
< rendering::XCanvas
>& rCanvas( mpCanvas
->getUNOCanvas() );
1758 rendering::StrokeAttributes aStrokeAttributes
;
1760 aStrokeAttributes
.StrokeWidth
= mnOutlineWidth
;
1761 aStrokeAttributes
.MiterLimit
= 1.0;
1762 aStrokeAttributes
.StartCapType
= rendering::PathCapType::BUTT
;
1763 aStrokeAttributes
.EndCapType
= rendering::PathCapType::BUTT
;
1764 aStrokeAttributes
.JoinType
= rendering::PathJoinType::MITER
;
1766 rendering::RenderState
aLocalState( rRenderState
);
1767 aLocalState
.DeviceColor
= maFillColor
;
1769 // TODO(P1): implement caching
1771 // background of text
1772 rCanvas
->fillPolyPolygon( mxTextPoly
,
1776 // border line of text
1777 rCanvas
->strokePolyPolygon( mxTextPoly
,
1780 aStrokeAttributes
);
1782 // underlines/strikethrough - background
1783 rCanvas
->fillPolyPolygon( mxTextLines
,
1786 // underlines/strikethrough - border
1787 rCanvas
->strokePolyPolygon( mxTextLines
,
1790 aStrokeAttributes
);
1795 bool OutlineAction::render( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1797 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::render()" );
1798 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex
<< this );
1800 rendering::RenderState
aLocalState( maState
);
1801 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1803 return renderEffectText( *this,
1805 mpCanvas
->getUNOCanvas(),
1813 #if 0 // see #if'ed out use in OutlineAction::renderSubset below:
1814 class OutlineTextArrayRenderHelper
: public TextRenderer
1817 OutlineTextArrayRenderHelper( const uno::Reference
< rendering::XCanvas
>& rCanvas
,
1818 const uno::Reference
< rendering::XPolyPolygon2D
>& rTextPolygon
,
1819 const uno::Reference
< rendering::XPolyPolygon2D
>& rLinePolygon
,
1820 const rendering::ViewState
& rViewState
,
1821 double nOutlineWidth
) :
1823 vcl::unotools::colorToDoubleSequence(
1825 rCanvas
->getDevice()->getDeviceColorSpace() )),
1826 mnOutlineWidth( nOutlineWidth
),
1827 mrCanvas( rCanvas
),
1828 mrTextPolygon( rTextPolygon
),
1829 mrLinePolygon( rLinePolygon
),
1830 mrViewState( rViewState
)
1834 // TextRenderer interface
1835 virtual bool operator()( const rendering::RenderState
& rRenderState
) const
1837 rendering::StrokeAttributes aStrokeAttributes
;
1839 aStrokeAttributes
.StrokeWidth
= mnOutlineWidth
;
1840 aStrokeAttributes
.MiterLimit
= 1.0;
1841 aStrokeAttributes
.StartCapType
= rendering::PathCapType::BUTT
;
1842 aStrokeAttributes
.EndCapType
= rendering::PathCapType::BUTT
;
1843 aStrokeAttributes
.JoinType
= rendering::PathJoinType::MITER
;
1845 rendering::RenderState
aLocalState( rRenderState
);
1846 aLocalState
.DeviceColor
= maFillColor
;
1848 // TODO(P1): implement caching
1850 // background of text
1851 mrCanvas
->fillPolyPolygon( mrTextPolygon
,
1855 // border line of text
1856 mrCanvas
->strokePolyPolygon( mrTextPolygon
,
1859 aStrokeAttributes
);
1861 // underlines/strikethrough - background
1862 mrCanvas
->fillPolyPolygon( mrLinePolygon
,
1865 // underlines/strikethrough - border
1866 mrCanvas
->strokePolyPolygon( mrLinePolygon
,
1869 aStrokeAttributes
);
1875 const uno::Sequence
< double > maFillColor
;
1876 double mnOutlineWidth
;
1877 const uno::Reference
< rendering::XCanvas
>& mrCanvas
;
1878 const uno::Reference
< rendering::XPolyPolygon2D
>& mrTextPolygon
;
1879 const uno::Reference
< rendering::XPolyPolygon2D
>& mrLinePolygon
;
1880 const rendering::ViewState
& mrViewState
;
1884 bool OutlineAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
1885 const Subset
& rSubset
) const
1887 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction::renderSubset()" );
1888 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction: 0x" << std::hex
<< this );
1890 if( rSubset
.mnSubsetBegin
== rSubset
.mnSubsetEnd
)
1891 return true; // empty range, render nothing
1894 // TODO(F3): Subsetting NYI for outline text!
1895 return render( rTransformation
);
1897 const rendering::StringContext
rOrigContext( mxTextLayout
->getText() );
1899 if( rSubset
.mnSubsetBegin
== 0 &&
1900 rSubset
.mnSubsetEnd
== rOrigContext
.Length
)
1902 // full range, no need for subsetting
1903 return render( rTransformation
);
1906 rendering::RenderState
aLocalState( maState
);
1907 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1910 // create and setup local Text polygon
1911 // ===================================
1913 uno::Reference
< rendering::XPolyPolygon2D
> xTextPolygon();
1915 // TODO(P3): Provide an API method for that!
1917 if( !xTextLayout
.is() )
1920 // render everything
1921 // =================
1923 return renderEffectText(
1924 OutlineTextArrayRenderHelper(
1940 ::basegfx::B2DRange
OutlineAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
1942 rendering::RenderState
aLocalState( maState
);
1943 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
1945 return calcEffectTextBounds( maOutlineBounds
,
1946 ::basegfx::B2DRange(0, 0,
1947 maLinesOverallSize
.getWidth(),
1948 maLinesOverallSize
.getHeight()),
1952 mpCanvas
->getViewState() );
1955 ::basegfx::B2DRange
OutlineAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
1956 const Subset
& /*rSubset*/ ) const
1958 SAL_WARN( "cppcanvas.emf", "OutlineAction::getBounds(): Subset not yet supported by this object" );
1960 return getBounds( rTransformation
);
1963 sal_Int32
OutlineAction::getActionCount() const
1965 // TODO(F3): Subsetting NYI for outline text!
1966 return maOffsets
.getLength();
1970 // Action factory methods
1973 /** Create an outline action
1975 This method extracts the polygonal outline from the
1976 text, and creates a properly setup OutlineAction from
1979 std::shared_ptr
<Action
> createOutline( const ::basegfx::B2DPoint
& rStartPoint
,
1980 const ::basegfx::B2DSize
& rReliefOffset
,
1981 const ::Color
& rReliefColor
,
1982 const ::basegfx::B2DSize
& rShadowOffset
,
1983 const ::Color
& rShadowColor
,
1984 const OUString
& rText
,
1985 sal_Int32 nStartPos
,
1987 KernArraySpan pDXArray
,
1988 o3tl::span
<const sal_Bool
> pKashidaArray
,
1989 VirtualDevice
& rVDev
,
1990 const CanvasSharedPtr
& rCanvas
,
1991 const OutDevState
& rState
,
1992 const Renderer::Parameters
& rParms
)
1994 // operate on raw DX array here (in logical coordinate
1995 // system), to have a higher resolution
1996 // PolyPolygon. That polygon is then converted to
1997 // device coordinate system.
1999 // #i68512# Temporarily switch off font rotation
2000 // (which is already contained in the render state
2001 // transformation matrix - otherwise, glyph polygons
2002 // will be rotated twice)
2003 const vcl::Font
aOrigFont( rVDev
.GetFont() );
2004 vcl::Font
aUnrotatedFont( aOrigFont
);
2005 aUnrotatedFont
.SetOrientation(0_deg10
);
2006 rVDev
.SetFont( aUnrotatedFont
);
2008 // TODO(F3): Don't understand parameter semantics of
2009 // GetTextOutlines()
2010 ::basegfx::B2DPolyPolygon aResultingPolyPolygon
;
2011 PolyPolyVector aVCLPolyPolyVector
;
2012 const bool bHaveOutlines( rVDev
.GetTextOutlines( aVCLPolyPolyVector
, rText
,
2013 static_cast<sal_uInt16
>(nStartPos
),
2014 static_cast<sal_uInt16
>(nStartPos
),
2015 static_cast<sal_uInt16
>(nLen
),
2016 0, pDXArray
, pKashidaArray
) );
2017 rVDev
.SetFont(aOrigFont
);
2019 if( !bHaveOutlines
)
2020 return std::shared_ptr
<Action
>();
2022 // remove offsetting from mapmode transformation
2023 // (outline polygons must stay at origin, only need to
2025 ::basegfx::B2DHomMatrix
aMapModeTransform(
2026 rState
.mapModeTransform
);
2027 aMapModeTransform
.set(0,2, 0.0);
2028 aMapModeTransform
.set(1,2, 0.0);
2030 for( const auto& rVCLPolyPolygon
: aVCLPolyPolyVector
)
2032 ::basegfx::B2DPolyPolygon aPolyPolygon
= rVCLPolyPolygon
.getB2DPolyPolygon();
2033 aPolyPolygon
.transform( aMapModeTransform
);
2035 // append result to collecting polypoly
2036 for( sal_uInt32 i
=0; i
<aPolyPolygon
.count(); ++i
)
2038 // #i47795# Ensure closed polygons (since
2039 // FreeType returns the glyph outlines
2041 const ::basegfx::B2DPolygon
& rPoly( aPolyPolygon
.getB2DPolygon( i
) );
2042 const sal_uInt32
nCount( rPoly
.count() );
2046 // polygon either degenerate, or
2048 aResultingPolyPolygon
.append( rPoly
);
2052 ::basegfx::B2DPolygon
aPoly(rPoly
);
2053 aPoly
.setClosed(true);
2055 aResultingPolyPolygon
.append( aPoly
);
2060 const uno::Sequence
< double > aCharWidthSeq(
2062 setupDXArray( pDXArray
, nLen
, rState
) :
2063 setupDXArray( rText
,
2068 const uno::Reference
< rendering::XPolyPolygon2D
> xTextPoly(
2069 ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
2070 rCanvas
->getUNOCanvas()->getDevice(),
2071 aResultingPolyPolygon
) );
2073 if( rParms
.maTextTransformation
)
2075 return std::make_shared
<OutlineAction
>(
2081 ::basegfx::utils::getRange(aResultingPolyPolygon
),
2087 *rParms
.maTextTransformation
);
2091 return std::make_shared
<OutlineAction
>(
2097 ::basegfx::utils::getRange(aResultingPolyPolygon
),
2109 std::shared_ptr
<Action
> TextActionFactory::createTextAction( const ::Point
& rStartPoint
,
2110 const ::Size
& rReliefOffset
,
2111 const ::Color
& rReliefColor
,
2112 const ::Size
& rShadowOffset
,
2113 const ::Color
& rShadowColor
,
2114 const ::Color
& rTextFillColor
,
2115 const OUString
& rText
,
2116 sal_Int32 nStartPos
,
2118 KernArraySpan pDXArray
,
2119 o3tl::span
<const sal_Bool
> pKashidaArray
,
2120 VirtualDevice
& rVDev
,
2121 const CanvasSharedPtr
& rCanvas
,
2122 const OutDevState
& rState
,
2123 const Renderer::Parameters
& rParms
,
2126 const ::Size
aBaselineOffset( tools::getBaselineOffset( rState
,
2128 // #143885# maintain (nearly) full precision positioning,
2129 // by circumventing integer-based OutDev-mapping
2130 const ::basegfx::B2DPoint
aStartPoint(
2131 rState
.mapModeTransform
*
2132 ::basegfx::B2DPoint(rStartPoint
.X() + aBaselineOffset
.Width(),
2133 rStartPoint
.Y() + aBaselineOffset
.Height()) );
2135 const ::basegfx::B2DSize
aReliefOffset(
2136 rState
.mapModeTransform
* vcl::unotools::b2DSizeFromSize( rReliefOffset
) );
2137 const ::basegfx::B2DSize
aShadowOffset(
2138 rState
.mapModeTransform
* vcl::unotools::b2DSizeFromSize( rShadowOffset
) );
2140 if( rState
.isTextOutlineModeSet
)
2142 return createOutline(
2159 // convert DX array to device coordinate system (and
2160 // create it in the first place, if pDXArray is NULL)
2161 const uno::Sequence
< double > aCharWidths(
2163 setupDXArray( pDXArray
, nLen
, rState
) :
2164 setupDXArray( rText
,
2170 const uno::Sequence
< sal_Bool
> aKashidas(pKashidaArray
.data(), pKashidaArray
.size());
2172 // determine type of text action to create
2173 // =======================================
2175 const ::Color
aEmptyColor( COL_AUTO
);
2177 std::shared_ptr
<Action
> ret
;
2179 // no DX array, and no need to subset - no need to store
2181 if( pDXArray
.empty() && !bSubsettable
)
2184 if( !rState
.textOverlineStyle
&&
2185 !rState
.textUnderlineStyle
&&
2186 !rState
.textStrikeoutStyle
&&
2187 rReliefColor
== aEmptyColor
&&
2188 rShadowColor
== aEmptyColor
&&
2189 rTextFillColor
== aEmptyColor
)
2192 if( rParms
.maTextTransformation
)
2194 ret
= std::make_shared
<TextAction
>(
2201 *rParms
.maTextTransformation
);
2205 ret
= std::make_shared
<TextAction
>(
2216 // at least one of the effects requested
2217 if( rParms
.maTextTransformation
)
2218 ret
= std::make_shared
<EffectTextAction
>(
2231 *rParms
.maTextTransformation
);
2233 ret
= std::make_shared
<EffectTextAction
>(
2250 // DX array necessary - any effects?
2251 if( !rState
.textOverlineStyle
&&
2252 !rState
.textUnderlineStyle
&&
2253 !rState
.textStrikeoutStyle
&&
2254 rReliefColor
== aEmptyColor
&&
2255 rShadowColor
== aEmptyColor
&&
2256 rTextFillColor
== aEmptyColor
)
2259 if( rParms
.maTextTransformation
)
2260 ret
= std::make_shared
<TextArrayAction
>(
2269 *rParms
.maTextTransformation
);
2271 ret
= std::make_shared
<TextArrayAction
>(
2283 // at least one of the effects requested
2284 if( rParms
.maTextTransformation
)
2285 ret
= std::make_shared
<EffectTextArrayAction
>(
2300 *rParms
.maTextTransformation
);
2302 ret
= std::make_shared
<EffectTextArrayAction
>(
2323 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */