Bump version to 5.0-14
[LibreOffice.git] / cppcanvas / source / mtfrenderer / textaction.cxx
blobec0b131b594d00f356a54ceb1e30ce7c45970945
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <canvas/debug.hxx>
22 #include <tools/diagnose_ex.h>
23 #include <canvas/verbosetrace.hxx>
25 #include <com/sun/star/rendering/PathCapType.hpp>
26 #include <com/sun/star/rendering/PathJoinType.hpp>
27 #include <com/sun/star/rendering/XCanvas.hpp>
28 #include <com/sun/star/rendering/XCanvasFont.hpp>
30 #include <basegfx/numeric/ftools.hxx>
31 #include <basegfx/matrix/b2dhommatrix.hxx>
32 #include <basegfx/range/b2drectangle.hxx>
33 #include <basegfx/vector/b2dsize.hxx>
34 #include <basegfx/polygon/b2dpolypolygontools.hxx>
35 #include <basegfx/polygon/b2dpolygontools.hxx>
36 #include <basegfx/matrix/b2dhommatrixtools.hxx>
38 #include <tools/gen.hxx>
39 #include <vcl/canvastools.hxx>
40 #include <vcl/virdev.hxx>
42 #include <basegfx/tools/canvastools.hxx>
43 #include <canvas/canvastools.hxx>
45 #include <boost/scoped_array.hpp>
46 #include <boost/bind.hpp>
47 #include <boost/utility.hpp>
49 #include "textaction.hxx"
50 #include "outdevstate.hxx"
51 #include "mtftools.hxx"
54 using namespace ::com::sun::star;
56 namespace cppcanvas
58 namespace internal
60 namespace
62 void init( rendering::RenderState& o_rRenderState,
63 const ::basegfx::B2DPoint& rStartPoint,
64 const OutDevState& rState,
65 const CanvasSharedPtr& rCanvas )
67 tools::initRenderState(o_rRenderState,rState);
69 // #i36950# Offset clip back to origin (as it's also moved
70 // by rStartPoint)
71 // #i53964# Also take VCL font rotation into account,
72 // since this, opposed to the FontMatrix rotation
73 // elsewhere, _does_ get incorporated into the render
74 // state transform.
75 tools::modifyClip( o_rRenderState,
76 rState,
77 rCanvas,
78 rStartPoint,
79 NULL,
80 &rState.fontRotation );
82 basegfx::B2DHomMatrix aLocalTransformation(basegfx::tools::createRotateB2DHomMatrix(rState.fontRotation));
83 aLocalTransformation.translate( rStartPoint.getX(),
84 rStartPoint.getY() );
85 ::canvas::tools::appendToRenderState( o_rRenderState,
86 aLocalTransformation );
88 o_rRenderState.DeviceColor = rState.textColor;
91 void init( rendering::RenderState& o_rRenderState,
92 const ::basegfx::B2DPoint& rStartPoint,
93 const OutDevState& rState,
94 const CanvasSharedPtr& rCanvas,
95 const ::basegfx::B2DHomMatrix& rTextTransform )
97 init( o_rRenderState, rStartPoint, rState, rCanvas );
99 // TODO(F2): Also inversely-transform clip with
100 // rTextTransform (which is actually rather hard, as the
101 // text transform is _prepended_ to the render state)!
103 // prepend extra font transform to render state
104 // (prepend it, because it's interpreted in the unit
105 // rect coordinate space)
106 ::canvas::tools::prependToRenderState( o_rRenderState,
107 rTextTransform );
110 void init( rendering::RenderState& o_rRenderState,
111 uno::Reference< rendering::XCanvasFont >& o_rFont,
112 const ::basegfx::B2DPoint& rStartPoint,
113 const OutDevState& rState,
114 const CanvasSharedPtr& rCanvas )
116 // ensure that o_rFont is valid. It is possible that
117 // text actions are generated without previously
118 // setting a font. Then, just take a default font
119 if( !o_rFont.is() )
121 // Use completely default FontRequest
122 const rendering::FontRequest aFontRequest;
124 geometry::Matrix2D aFontMatrix;
125 ::canvas::tools::setIdentityMatrix2D( aFontMatrix );
127 o_rFont = rCanvas->getUNOCanvas()->createFont(
128 aFontRequest,
129 uno::Sequence< beans::PropertyValue >(),
130 aFontMatrix );
133 init( o_rRenderState,
134 rStartPoint,
135 rState,
136 rCanvas );
139 void init( rendering::RenderState& o_rRenderState,
140 uno::Reference< rendering::XCanvasFont >& o_rFont,
141 const ::basegfx::B2DPoint& rStartPoint,
142 const OutDevState& rState,
143 const CanvasSharedPtr& rCanvas,
144 const ::basegfx::B2DHomMatrix& rTextTransform )
146 init( o_rRenderState, o_rFont, rStartPoint, rState, rCanvas );
148 // TODO(F2): Also inversely-transform clip with
149 // rTextTransform (which is actually rather hard, as the
150 // text transform is _prepended_ to the render state)!
152 // prepend extra font transform to render state
153 // (prepend it, because it's interpreted in the unit
154 // rect coordinate space)
155 ::canvas::tools::prependToRenderState( o_rRenderState,
156 rTextTransform );
159 ::basegfx::B2DPolyPolygon textLinesFromLogicalOffsets( const uno::Sequence< double >& rOffsets,
160 const tools::TextLineInfo& rTextLineInfo )
162 return tools::createTextLinesPolyPolygon(
163 0.0,
164 // extract character cell furthest to the right
165 *(::std::max_element(
166 rOffsets.getConstArray(),
167 rOffsets.getConstArray() + rOffsets.getLength() )),
168 rTextLineInfo );
171 uno::Sequence< double > setupDXArray( const long* pCharWidths,
172 sal_Int32 nLen,
173 const OutDevState& rState )
175 // convert character widths from logical units
176 uno::Sequence< double > aCharWidthSeq( nLen );
177 double* pOutputWidths( aCharWidthSeq.getArray() );
179 // #143885# maintain (nearly) full precision of DX
180 // array, by circumventing integer-based
181 // OutDev-mapping
182 const double nScale( rState.mapModeTransform.get(0,0) );
183 for( int i = 0; i < nLen; ++i )
185 // TODO(F2): use correct scale direction
186 *pOutputWidths++ = *pCharWidths++ * nScale;
189 return aCharWidthSeq;
192 uno::Sequence< double > setupDXArray( const OUString& rText,
193 sal_Int32 nStartPos,
194 sal_Int32 nLen,
195 VirtualDevice& rVDev,
196 const OutDevState& rState )
198 // no external DX array given, create one from given
199 // string
200 ::boost::scoped_array< long > pCharWidths( new long[nLen] );
202 rVDev.GetTextArray( rText, pCharWidths.get(),
203 nStartPos, nLen );
205 return setupDXArray( pCharWidths.get(), nLen, rState );
208 ::basegfx::B2DPoint adaptStartPoint( const ::basegfx::B2DPoint& rStartPoint,
209 const OutDevState& rState,
210 const uno::Sequence< double >& rOffsets )
212 ::basegfx::B2DPoint aLocalPoint( rStartPoint );
214 if( rState.textAlignment )
216 // text origin is right, not left. Modify start point
217 // accordingly, because XCanvas::drawTextLayout()
218 // always aligns left!
220 const double nOffset( rOffsets[ rOffsets.getLength()-1 ] );
222 // correct start point for rotated text: rotate around
223 // former start point
224 aLocalPoint.setX( aLocalPoint.getX() + cos( rState.fontRotation )*nOffset );
225 aLocalPoint.setY( aLocalPoint.getY() + sin( rState.fontRotation )*nOffset );
228 return aLocalPoint;
231 /** Perform common setup for array text actions
233 This method creates the XTextLayout object and
234 initializes it, e.g. with the logical advancements.
236 void initArrayAction( rendering::RenderState& o_rRenderState,
237 uno::Reference< rendering::XTextLayout >& o_rTextLayout,
238 const ::basegfx::B2DPoint& rStartPoint,
239 const OUString& rText,
240 sal_Int32 nStartPos,
241 sal_Int32 nLen,
242 const uno::Sequence< double >& rOffsets,
243 const CanvasSharedPtr& rCanvas,
244 const OutDevState& rState,
245 const ::basegfx::B2DHomMatrix* pTextTransform )
247 ENSURE_OR_THROW( rOffsets.getLength(),
248 "::cppcanvas::internal::initArrayAction(): zero-length DX array" );
250 const ::basegfx::B2DPoint aLocalStartPoint(
251 adaptStartPoint( rStartPoint, rState, rOffsets ) );
253 uno::Reference< rendering::XCanvasFont > xFont( rState.xFont );
255 if( pTextTransform )
256 init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas, *pTextTransform );
257 else
258 init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas );
260 o_rTextLayout = xFont->createTextLayout(
261 rendering::StringContext( rText, nStartPos, nLen ),
262 rState.textDirection,
263 0 );
265 ENSURE_OR_THROW( o_rTextLayout.is(),
266 "::cppcanvas::internal::initArrayAction(): Invalid font" );
268 o_rTextLayout->applyLogicalAdvancements( rOffsets );
271 double getLineWidth( ::VirtualDevice& rVDev,
272 const OutDevState& rState,
273 const rendering::StringContext& rStringContext )
275 // TODO(F2): use correct scale direction
276 const ::basegfx::B2DSize aSize( rVDev.GetTextWidth( rStringContext.Text,
277 static_cast<sal_uInt16>(rStringContext.StartPosition),
278 static_cast<sal_uInt16>(rStringContext.Length) ),
279 0 );
281 return (rState.mapModeTransform * aSize).getX();
284 uno::Sequence< double >
285 calcSubsetOffsets( rendering::RenderState& io_rRenderState,
286 double& o_rMinPos,
287 double& o_rMaxPos,
288 const uno::Reference< rendering::XTextLayout >& rOrigTextLayout,
289 const ::cppcanvas::internal::Action::Subset& rSubset )
291 ENSURE_OR_THROW( rSubset.mnSubsetEnd > rSubset.mnSubsetBegin,
292 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
294 uno::Sequence< double > aOrigOffsets( rOrigTextLayout->queryLogicalAdvancements() );
295 const double* pOffsets( aOrigOffsets.getConstArray() );
297 ENSURE_OR_THROW( aOrigOffsets.getLength() >= rSubset.mnSubsetEnd,
298 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
300 // TODO(F3): It currently seems that for RTL text, the
301 // DX offsets are nevertheless increasing in logical
302 // text order (I'd expect they are decreasing,
303 // mimicking the fact that the text is output
304 // right-to-left). This breaks text effects for ALL
305 // RTL languages.
307 // determine leftmost position in given subset range -
308 // as the DX array contains the output positions
309 // starting with the second character (the first is
310 // assumed to have output position 0), correct begin
311 // iterator.
312 const double nMinPos( rSubset.mnSubsetBegin <= 0 ? 0 :
313 *(::std::min_element( pOffsets+rSubset.mnSubsetBegin-1,
314 pOffsets+rSubset.mnSubsetEnd )) );
316 // determine rightmost position in given subset range
317 // - as the DX array contains the output positions
318 // starting with the second character (the first is
319 // assumed to have output position 0), correct begin
320 // iterator.
321 const double nMaxPos(
322 *(::std::max_element( pOffsets + (rSubset.mnSubsetBegin <= 0 ?
323 0 : rSubset.mnSubsetBegin-1),
324 pOffsets + rSubset.mnSubsetEnd )) );
327 // adapt render state, to move text output to given offset
330 // TODO(F1): Strictly speaking, we also have to adapt
331 // the clip here, which normally should _not_ move
332 // with the output offset. Neglected for now, as it
333 // does not matter for drawing layer output
335 if( rSubset.mnSubsetBegin > 0 )
337 ::basegfx::B2DHomMatrix aTranslation;
338 if( rOrigTextLayout->getFont()->getFontRequest().FontDescription.IsVertical )
340 // vertical text -> offset in y direction
341 aTranslation.translate( 0.0, nMinPos );
343 else
345 // horizontal text -> offset in x direction
346 aTranslation.translate( nMinPos, 0.0 );
349 ::canvas::tools::appendToRenderState( io_rRenderState,
350 aTranslation );
354 // reduce DX array to given substring
357 const sal_Int32 nNewElements( rSubset.mnSubsetEnd - rSubset.mnSubsetBegin );
358 uno::Sequence< double > aAdaptedOffsets( nNewElements );
359 double* pAdaptedOffsets( aAdaptedOffsets.getArray() );
361 // move to new output position (subtract nMinPos,
362 // which is the new '0' position), copy only the range
363 // as given by rSubset.
364 ::std::transform( pOffsets + rSubset.mnSubsetBegin,
365 pOffsets + rSubset.mnSubsetEnd,
366 pAdaptedOffsets,
367 ::boost::bind( ::std::minus<double>(),
369 nMinPos ) );
371 o_rMinPos = nMinPos;
372 o_rMaxPos = nMaxPos;
374 return aAdaptedOffsets;
377 uno::Reference< rendering::XTextLayout >
378 createSubsetLayout( const rendering::StringContext& rOrigContext,
379 const ::cppcanvas::internal::Action::Subset& rSubset,
380 const uno::Reference< rendering::XTextLayout >& rOrigTextLayout )
382 // create temporary new text layout with subset string
385 const sal_Int32 nNewStartPos( rOrigContext.StartPosition + ::std::min(
386 rSubset.mnSubsetBegin, rOrigContext.Length-1 ) );
387 const sal_Int32 nNewLength( ::std::max(
388 ::std::min(
389 rSubset.mnSubsetEnd - rSubset.mnSubsetBegin,
390 rOrigContext.Length ),
391 sal_Int32( 0 ) ) );
393 const rendering::StringContext aContext( rOrigContext.Text,
394 nNewStartPos,
395 nNewLength );
397 uno::Reference< rendering::XTextLayout > xTextLayout(
398 rOrigTextLayout->getFont()->createTextLayout( aContext,
399 rOrigTextLayout->getMainTextDirection(),
400 0 ),
401 uno::UNO_QUERY_THROW );
403 return xTextLayout;
406 /** Setup subset text layout
408 @param io_rTextLayout
409 Must contain original (full set) text layout on input,
410 will contain subsetted text layout (or empty
411 reference, for empty subsets) on output.
413 @param io_rRenderState
414 Must contain original render state on input, will
415 contain shifted render state concatenated with
416 rTransformation on output.
418 @param rTransformation
419 Additional transformation, to be prepended to render
420 state
422 @param rSubset
423 Subset to prepare
425 void createSubsetLayout( uno::Reference< rendering::XTextLayout >& io_rTextLayout,
426 rendering::RenderState& io_rRenderState,
427 double& o_rMinPos,
428 double& o_rMaxPos,
429 const ::basegfx::B2DHomMatrix& rTransformation,
430 const Action::Subset& rSubset )
432 ::canvas::tools::prependToRenderState(io_rRenderState, rTransformation);
434 if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd )
436 // empty range, empty layout
437 io_rTextLayout.clear();
439 return;
442 ENSURE_OR_THROW( io_rTextLayout.is(),
443 "createSubsetLayout(): Invalid input layout" );
445 const rendering::StringContext& rOrigContext( io_rTextLayout->getText() );
447 if( rSubset.mnSubsetBegin == 0 &&
448 rSubset.mnSubsetEnd == rOrigContext.Length )
450 // full range, no need for subsetting
451 return;
454 uno::Reference< rendering::XTextLayout > xTextLayout(
455 createSubsetLayout( rOrigContext, rSubset, io_rTextLayout ) );
457 if( xTextLayout.is() )
459 xTextLayout->applyLogicalAdvancements(
460 calcSubsetOffsets( io_rRenderState,
461 o_rMinPos,
462 o_rMaxPos,
463 io_rTextLayout,
464 rSubset ) );
467 io_rTextLayout = xTextLayout;
471 /** Interface for renderEffectText functor below.
473 This is interface is used from the renderEffectText()
474 method below, to call the client implementation.
476 class TextRenderer
478 public:
479 virtual ~TextRenderer() {}
481 /// Render text with given RenderState
482 virtual bool operator()( const rendering::RenderState& rRenderState ) const = 0;
485 /** Render effect text.
487 @param rRenderer
488 Functor object, will be called to render the actual
489 part of the text effect (the text itself and the means
490 to render it are unknown to this method)
492 bool renderEffectText( const TextRenderer& rRenderer,
493 const rendering::RenderState& rRenderState,
494 const rendering::ViewState& /*rViewState*/,
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 )
501 ::Color aEmptyColor( COL_AUTO );
502 uno::Reference<rendering::XColorSpace> xColorSpace(
503 xCanvas->getDevice()->getDeviceColorSpace() );
505 // draw shadow text, if enabled
506 if( rShadowColor != aEmptyColor )
508 rendering::RenderState aShadowState( rRenderState );
509 ::basegfx::B2DHomMatrix aTranslate;
511 aTranslate.translate( rShadowOffset.getX(),
512 rShadowOffset.getY() );
514 ::canvas::tools::appendToRenderState(aShadowState, aTranslate);
516 aShadowState.DeviceColor =
517 vcl::unotools::colorToDoubleSequence( rShadowColor,
518 xColorSpace );
520 rRenderer( aShadowState );
523 // draw relief text, if enabled
524 if( rReliefColor != aEmptyColor )
526 rendering::RenderState aReliefState( rRenderState );
527 ::basegfx::B2DHomMatrix aTranslate;
529 aTranslate.translate( rReliefOffset.getX(),
530 rReliefOffset.getY() );
532 ::canvas::tools::appendToRenderState(aReliefState, aTranslate);
534 aReliefState.DeviceColor =
535 vcl::unotools::colorToDoubleSequence( rReliefColor,
536 xColorSpace );
538 rRenderer( aReliefState );
541 // draw normal text
542 rRenderer( rRenderState );
544 return true;
548 ::basegfx::B2DRange calcEffectTextBounds( const ::basegfx::B2DRange& rTextBounds,
549 const ::basegfx::B2DRange& rLineBounds,
550 const ::basegfx::B2DSize& rReliefOffset,
551 const ::basegfx::B2DSize& rShadowOffset,
552 const rendering::RenderState& rRenderState,
553 const rendering::ViewState& rViewState )
555 ::basegfx::B2DRange aBounds( rTextBounds );
557 // add extends of text lines
558 aBounds.expand( rLineBounds );
560 // TODO(Q3): Provide this functionality at the B2DRange
561 ::basegfx::B2DRange aTotalBounds( aBounds );
562 aTotalBounds.expand(
563 ::basegfx::B2DRange( aBounds.getMinX() + rReliefOffset.getX(),
564 aBounds.getMinY() + rReliefOffset.getY(),
565 aBounds.getMaxX() + rReliefOffset.getX(),
566 aBounds.getMaxY() + rReliefOffset.getY() ) );
567 aTotalBounds.expand(
568 ::basegfx::B2DRange( aBounds.getMinX() + rShadowOffset.getX(),
569 aBounds.getMinY() + rShadowOffset.getY(),
570 aBounds.getMaxX() + rShadowOffset.getX(),
571 aBounds.getMaxY() + rShadowOffset.getY() ) );
573 return tools::calcDevicePixelBounds( aTotalBounds,
574 rViewState,
575 rRenderState );
578 void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize,
579 uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines,
580 const CanvasSharedPtr& rCanvas,
581 const uno::Sequence< double >& rOffsets,
582 const tools::TextLineInfo& rLineInfo )
584 const ::basegfx::B2DPolyPolygon aPoly(
585 textLinesFromLogicalOffsets(
586 rOffsets,
587 rLineInfo ) );
589 o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange();
591 o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
592 rCanvas->getUNOCanvas()->getDevice(),
593 aPoly );
596 void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize,
597 uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines,
598 const CanvasSharedPtr& rCanvas,
599 double nLineWidth,
600 const tools::TextLineInfo& rLineInfo )
602 const ::basegfx::B2DPolyPolygon aPoly(
603 tools::createTextLinesPolyPolygon( 0.0, nLineWidth,
604 rLineInfo ) );
606 o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange();
608 o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
609 rCanvas->getUNOCanvas()->getDevice(),
610 aPoly );
616 class TextAction : public Action, private ::boost::noncopyable
618 public:
619 TextAction( const ::basegfx::B2DPoint& rStartPoint,
620 const OUString& rString,
621 sal_Int32 nStartPos,
622 sal_Int32 nLen,
623 const CanvasSharedPtr& rCanvas,
624 const OutDevState& rState );
626 TextAction( const ::basegfx::B2DPoint& rStartPoint,
627 const OUString& rString,
628 sal_Int32 nStartPos,
629 sal_Int32 nLen,
630 const CanvasSharedPtr& rCanvas,
631 const OutDevState& rState,
632 const ::basegfx::B2DHomMatrix& rTextTransform );
634 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
635 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
636 const Subset& rSubset ) const SAL_OVERRIDE;
638 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
639 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
640 const Subset& rSubset ) const SAL_OVERRIDE;
642 virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
644 private:
645 // TODO(P2): This is potentially a real mass object
646 // (every character might be a separate TextAction),
647 // thus, make it as lightweight as possible. For
648 // example, share common RenderState among several
649 // TextActions, maybe using maOffsets for the
650 // translation.
652 uno::Reference< rendering::XCanvasFont > mxFont;
653 const rendering::StringContext maStringContext;
654 const CanvasSharedPtr mpCanvas;
655 rendering::RenderState maState;
656 const sal_Int8 maTextDirection;
659 TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint,
660 const OUString& rString,
661 sal_Int32 nStartPos,
662 sal_Int32 nLen,
663 const CanvasSharedPtr& rCanvas,
664 const OutDevState& rState ) :
665 mxFont( rState.xFont ),
666 maStringContext( rString, nStartPos, nLen ),
667 mpCanvas( rCanvas ),
668 maState(),
669 maTextDirection( rState.textDirection )
671 init( maState, mxFont,
672 rStartPoint,
673 rState, rCanvas );
675 ENSURE_OR_THROW( mxFont.is(),
676 "::cppcanvas::internal::TextAction(): Invalid font" );
679 TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint,
680 const OUString& rString,
681 sal_Int32 nStartPos,
682 sal_Int32 nLen,
683 const CanvasSharedPtr& rCanvas,
684 const OutDevState& rState,
685 const ::basegfx::B2DHomMatrix& rTextTransform ) :
686 mxFont( rState.xFont ),
687 maStringContext( rString, nStartPos, nLen ),
688 mpCanvas( rCanvas ),
689 maState(),
690 maTextDirection( rState.textDirection )
692 init( maState, mxFont,
693 rStartPoint,
694 rState, rCanvas, rTextTransform );
696 ENSURE_OR_THROW( mxFont.is(),
697 "::cppcanvas::internal::TextAction(): Invalid font" );
700 bool TextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
702 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextAction::render()" );
703 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextAction: 0x" << std::hex << this );
705 rendering::RenderState aLocalState( maState );
706 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
708 mpCanvas->getUNOCanvas()->drawText( maStringContext, mxFont,
709 mpCanvas->getViewState(), aLocalState, maTextDirection );
711 return true;
714 bool TextAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
715 const Subset& /*rSubset*/ ) const
717 SAL_WARN( "cppcanvas.emf", "TextAction::renderSubset(): Subset not supported by this object" );
719 // TODO(P1): Retrieve necessary font metric info for
720 // TextAction from XCanvas. Currently, the
721 // TextActionFactory does not generate this object for
722 // _subsettable_ text
723 return render( rTransformation );
726 ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
728 // create XTextLayout, to have the
729 // XTextLayout::queryTextBounds() method available
730 uno::Reference< rendering::XTextLayout > xTextLayout(
731 mxFont->createTextLayout(
732 maStringContext,
733 maTextDirection,
734 0 ) );
736 rendering::RenderState aLocalState( maState );
737 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
739 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
740 xTextLayout->queryTextBounds() ),
741 mpCanvas->getViewState(),
742 aLocalState );
745 ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
746 const Subset& /*rSubset*/ ) const
748 SAL_WARN( "cppcanvas.emf", "TextAction::getBounds(): Subset not supported by this object" );
750 // TODO(P1): Retrieve necessary font metric info for
751 // TextAction from XCanvas. Currently, the
752 // TextActionFactory does not generate this object for
753 // _subsettable_ text
754 return getBounds( rTransformation );
757 sal_Int32 TextAction::getActionCount() const
759 // TODO(P1): Retrieve necessary font metric info for
760 // TextAction from XCanvas. Currently, the
761 // TextActionFactory does not generate this object for
762 // _subsettable_ text
763 return 1;
769 class EffectTextAction :
770 public Action,
771 public TextRenderer,
772 private ::boost::noncopyable
774 public:
775 EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
776 const ::basegfx::B2DSize& rReliefOffset,
777 const ::Color& rReliefColor,
778 const ::basegfx::B2DSize& rShadowOffset,
779 const ::Color& rShadowColor,
780 const OUString& rText,
781 sal_Int32 nStartPos,
782 sal_Int32 nLen,
783 VirtualDevice& rVDev,
784 const CanvasSharedPtr& rCanvas,
785 const OutDevState& rState );
787 EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
788 const ::basegfx::B2DSize& rReliefOffset,
789 const ::Color& rReliefColor,
790 const ::basegfx::B2DSize& rShadowOffset,
791 const ::Color& rShadowColor,
792 const OUString& rText,
793 sal_Int32 nStartPos,
794 sal_Int32 nLen,
795 VirtualDevice& rVDev,
796 const CanvasSharedPtr& rCanvas,
797 const OutDevState& rState,
798 const ::basegfx::B2DHomMatrix& rTextTransform );
800 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
801 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
802 const Subset& rSubset ) const SAL_OVERRIDE;
804 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
805 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
806 const Subset& rSubset ) const SAL_OVERRIDE;
808 virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
810 private:
811 /// Interface TextRenderer
812 virtual bool operator()( const rendering::RenderState& rRenderState ) const SAL_OVERRIDE;
814 // TODO(P2): This is potentially a real mass object
815 // (every character might be a separate TextAction),
816 // thus, make it as lightweight as possible. For
817 // example, share common RenderState among several
818 // TextActions, maybe using maOffsets for the
819 // translation.
821 uno::Reference< rendering::XCanvasFont > mxFont;
822 const rendering::StringContext maStringContext;
823 const CanvasSharedPtr mpCanvas;
824 rendering::RenderState maState;
825 const tools::TextLineInfo maTextLineInfo;
826 ::basegfx::B2DSize maLinesOverallSize;
827 const double mnLineWidth;
828 uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
829 const ::basegfx::B2DSize maReliefOffset;
830 const ::Color maReliefColor;
831 const ::basegfx::B2DSize maShadowOffset;
832 const ::Color maShadowColor;
833 const sal_Int8 maTextDirection;
836 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
837 const ::basegfx::B2DSize& rReliefOffset,
838 const ::Color& rReliefColor,
839 const ::basegfx::B2DSize& rShadowOffset,
840 const ::Color& rShadowColor,
841 const OUString& rText,
842 sal_Int32 nStartPos,
843 sal_Int32 nLen,
844 VirtualDevice& rVDev,
845 const CanvasSharedPtr& rCanvas,
846 const OutDevState& rState ) :
847 mxFont( rState.xFont ),
848 maStringContext( rText, nStartPos, nLen ),
849 mpCanvas( rCanvas ),
850 maState(),
851 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
852 maLinesOverallSize(),
853 mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ),
854 mxTextLines(),
855 maReliefOffset( rReliefOffset ),
856 maReliefColor( rReliefColor ),
857 maShadowOffset( rShadowOffset ),
858 maShadowColor( rShadowColor ),
859 maTextDirection( rState.textDirection )
861 initEffectLinePolyPolygon( maLinesOverallSize,
862 mxTextLines,
863 rCanvas,
864 mnLineWidth,
865 maTextLineInfo );
867 init( maState, mxFont,
868 rStartPoint,
869 rState, rCanvas );
871 ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(),
872 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
875 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
876 const ::basegfx::B2DSize& rReliefOffset,
877 const ::Color& rReliefColor,
878 const ::basegfx::B2DSize& rShadowOffset,
879 const ::Color& rShadowColor,
880 const OUString& rText,
881 sal_Int32 nStartPos,
882 sal_Int32 nLen,
883 VirtualDevice& rVDev,
884 const CanvasSharedPtr& rCanvas,
885 const OutDevState& rState,
886 const ::basegfx::B2DHomMatrix& rTextTransform ) :
887 mxFont( rState.xFont ),
888 maStringContext( rText, nStartPos, nLen ),
889 mpCanvas( rCanvas ),
890 maState(),
891 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
892 maLinesOverallSize(),
893 mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ),
894 mxTextLines(),
895 maReliefOffset( rReliefOffset ),
896 maReliefColor( rReliefColor ),
897 maShadowOffset( rShadowOffset ),
898 maShadowColor( rShadowColor ),
899 maTextDirection( rState.textDirection )
901 initEffectLinePolyPolygon( maLinesOverallSize,
902 mxTextLines,
903 rCanvas,
904 mnLineWidth,
905 maTextLineInfo );
907 init( maState, mxFont,
908 rStartPoint,
909 rState, rCanvas, rTextTransform );
911 ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(),
912 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
915 bool EffectTextAction::operator()( const rendering::RenderState& rRenderState ) const
917 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
918 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
920 rCanvas->fillPolyPolygon( mxTextLines,
921 rViewState,
922 rRenderState );
924 rCanvas->drawText( maStringContext, mxFont,
925 rViewState,
926 rRenderState,
927 maTextDirection );
929 return true;
932 bool EffectTextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
934 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextAction::render()" );
935 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextAction: 0x" << std::hex << this );
937 rendering::RenderState aLocalState( maState );
938 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
940 return renderEffectText( *this,
941 aLocalState,
942 mpCanvas->getViewState(),
943 mpCanvas->getUNOCanvas(),
944 maShadowColor,
945 maShadowOffset,
946 maReliefColor,
947 maReliefOffset );
950 bool EffectTextAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
951 const Subset& /*rSubset*/ ) const
953 SAL_WARN( "cppcanvas.emf", "EffectTextAction::renderSubset(): Subset not supported by this object" );
955 // TODO(P1): Retrieve necessary font metric info for
956 // TextAction from XCanvas. Currently, the
957 // TextActionFactory does not generate this object for
958 // subsettable text
959 return render( rTransformation );
962 ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
964 // create XTextLayout, to have the
965 // XTextLayout::queryTextBounds() method available
966 uno::Reference< rendering::XTextLayout > xTextLayout(
967 mxFont->createTextLayout(
968 maStringContext,
969 maTextDirection,
970 0 ) );
972 rendering::RenderState aLocalState( maState );
973 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
975 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
976 xTextLayout->queryTextBounds() ),
977 ::basegfx::B2DRange( 0,0,
978 maLinesOverallSize.getX(),
979 maLinesOverallSize.getY() ),
980 maReliefOffset,
981 maShadowOffset,
982 aLocalState,
983 mpCanvas->getViewState() );
986 ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
987 const Subset& /*rSubset*/ ) const
989 SAL_WARN( "cppcanvas.emf", "EffectTextAction::getBounds(): Subset not supported by this object" );
991 // TODO(P1): Retrieve necessary font metric info for
992 // TextAction from XCanvas. Currently, the
993 // TextActionFactory does not generate this object for
994 // _subsettable_ text
995 return getBounds( rTransformation );
998 sal_Int32 EffectTextAction::getActionCount() const
1000 // TODO(P1): Retrieve necessary font metric info for
1001 // TextAction from XCanvas. Currently, the
1002 // TextActionFactory does not generate this object for
1003 // subsettable text
1004 return 1;
1010 class TextArrayAction : public Action, private ::boost::noncopyable
1012 public:
1013 TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1014 const OUString& rString,
1015 sal_Int32 nStartPos,
1016 sal_Int32 nLen,
1017 const uno::Sequence< double >& rOffsets,
1018 const CanvasSharedPtr& rCanvas,
1019 const OutDevState& rState );
1021 TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1022 const OUString& rString,
1023 sal_Int32 nStartPos,
1024 sal_Int32 nLen,
1025 const uno::Sequence< double >& rOffsets,
1026 const CanvasSharedPtr& rCanvas,
1027 const OutDevState& rState,
1028 const ::basegfx::B2DHomMatrix& rTextTransform );
1030 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
1031 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1032 const Subset& rSubset ) const SAL_OVERRIDE;
1034 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
1035 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1036 const Subset& rSubset ) const SAL_OVERRIDE;
1038 virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
1040 private:
1041 // TODO(P2): This is potentially a real mass object
1042 // (every character might be a separate TextAction),
1043 // thus, make it as lightweight as possible. For
1044 // example, share common RenderState among several
1045 // TextActions, maybe using maOffsets for the
1046 // translation.
1048 uno::Reference< rendering::XTextLayout > mxTextLayout;
1049 const CanvasSharedPtr mpCanvas;
1050 rendering::RenderState maState;
1053 TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1054 const OUString& rString,
1055 sal_Int32 nStartPos,
1056 sal_Int32 nLen,
1057 const uno::Sequence< double >& rOffsets,
1058 const CanvasSharedPtr& rCanvas,
1059 const OutDevState& rState ) :
1060 mxTextLayout(),
1061 mpCanvas( rCanvas ),
1062 maState()
1064 initArrayAction( maState,
1065 mxTextLayout,
1066 rStartPoint,
1067 rString,
1068 nStartPos,
1069 nLen,
1070 rOffsets,
1071 rCanvas,
1072 rState, NULL );
1075 TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1076 const OUString& rString,
1077 sal_Int32 nStartPos,
1078 sal_Int32 nLen,
1079 const uno::Sequence< double >& rOffsets,
1080 const CanvasSharedPtr& rCanvas,
1081 const OutDevState& rState,
1082 const ::basegfx::B2DHomMatrix& rTextTransform ) :
1083 mxTextLayout(),
1084 mpCanvas( rCanvas ),
1085 maState()
1087 initArrayAction( maState,
1088 mxTextLayout,
1089 rStartPoint,
1090 rString,
1091 nStartPos,
1092 nLen,
1093 rOffsets,
1094 rCanvas,
1095 rState,
1096 &rTextTransform );
1099 bool TextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1101 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::render()" );
1102 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex << this );
1104 rendering::RenderState aLocalState( maState );
1105 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1107 mpCanvas->getUNOCanvas()->drawTextLayout( mxTextLayout,
1108 mpCanvas->getViewState(),
1109 aLocalState );
1111 return true;
1114 bool TextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1115 const Subset& rSubset ) const
1117 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::renderSubset()" );
1118 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex << this );
1120 rendering::RenderState aLocalState( maState );
1121 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1123 double nDummy0, nDummy1;
1124 createSubsetLayout( xTextLayout,
1125 aLocalState,
1126 nDummy0,
1127 nDummy1,
1128 rTransformation,
1129 rSubset );
1131 if( !xTextLayout.is() )
1132 return true; // empty layout, render nothing
1134 mpCanvas->getUNOCanvas()->drawTextLayout( xTextLayout,
1135 mpCanvas->getViewState(),
1136 aLocalState );
1138 return true;
1141 ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1143 rendering::RenderState aLocalState( maState );
1144 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1146 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1147 mxTextLayout->queryTextBounds() ),
1148 mpCanvas->getViewState(),
1149 aLocalState );
1152 ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1153 const Subset& rSubset ) const
1155 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::getBounds( subset )" );
1156 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex << this );
1158 rendering::RenderState aLocalState( maState );
1159 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1161 double nDummy0, nDummy1;
1162 createSubsetLayout( xTextLayout,
1163 aLocalState,
1164 nDummy0,
1165 nDummy1,
1166 rTransformation,
1167 rSubset );
1169 if( !xTextLayout.is() )
1170 return ::basegfx::B2DRange(); // empty layout, empty bounds
1172 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1173 xTextLayout->queryTextBounds() ),
1174 mpCanvas->getViewState(),
1175 aLocalState );
1178 sal_Int32 TextArrayAction::getActionCount() const
1180 const rendering::StringContext& rOrigContext( mxTextLayout->getText() );
1182 return rOrigContext.Length;
1188 class EffectTextArrayAction :
1189 public Action,
1190 public TextRenderer,
1191 private ::boost::noncopyable
1193 public:
1194 EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1195 const ::basegfx::B2DSize& rReliefOffset,
1196 const ::Color& rReliefColor,
1197 const ::basegfx::B2DSize& rShadowOffset,
1198 const ::Color& rShadowColor,
1199 const OUString& rText,
1200 sal_Int32 nStartPos,
1201 sal_Int32 nLen,
1202 const uno::Sequence< double >& rOffsets,
1203 VirtualDevice& rVDev,
1204 const CanvasSharedPtr& rCanvas,
1205 const OutDevState& rState );
1206 EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1207 const ::basegfx::B2DSize& rReliefOffset,
1208 const ::Color& rReliefColor,
1209 const ::basegfx::B2DSize& rShadowOffset,
1210 const ::Color& rShadowColor,
1211 const OUString& rText,
1212 sal_Int32 nStartPos,
1213 sal_Int32 nLen,
1214 const uno::Sequence< double >& rOffsets,
1215 VirtualDevice& rVDev,
1216 const CanvasSharedPtr& rCanvas,
1217 const OutDevState& rState,
1218 const ::basegfx::B2DHomMatrix& rTextTransform );
1220 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
1221 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1222 const Subset& rSubset ) const SAL_OVERRIDE;
1224 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
1225 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1226 const Subset& rSubset ) const SAL_OVERRIDE;
1228 virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
1230 private:
1231 // TextRenderer interface
1232 virtual bool operator()( const rendering::RenderState& rRenderState ) const SAL_OVERRIDE;
1234 // TODO(P2): This is potentially a real mass object
1235 // (every character might be a separate TextAction),
1236 // thus, make it as lightweight as possible. For
1237 // example, share common RenderState among several
1238 // TextActions, maybe using maOffsets for the
1239 // translation.
1241 uno::Reference< rendering::XTextLayout > mxTextLayout;
1242 const CanvasSharedPtr mpCanvas;
1243 rendering::RenderState maState;
1244 const tools::TextLineInfo maTextLineInfo;
1245 ::basegfx::B2DSize maLinesOverallSize;
1246 uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
1247 const ::basegfx::B2DSize maReliefOffset;
1248 const ::Color maReliefColor;
1249 const ::basegfx::B2DSize maShadowOffset;
1250 const ::Color maShadowColor;
1253 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1254 const ::basegfx::B2DSize& rReliefOffset,
1255 const ::Color& rReliefColor,
1256 const ::basegfx::B2DSize& rShadowOffset,
1257 const ::Color& rShadowColor,
1258 const OUString& rText,
1259 sal_Int32 nStartPos,
1260 sal_Int32 nLen,
1261 const uno::Sequence< double >& rOffsets,
1262 VirtualDevice& rVDev,
1263 const CanvasSharedPtr& rCanvas,
1264 const OutDevState& rState ) :
1265 mxTextLayout(),
1266 mpCanvas( rCanvas ),
1267 maState(),
1268 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1269 maLinesOverallSize(),
1270 mxTextLines(),
1271 maReliefOffset( rReliefOffset ),
1272 maReliefColor( rReliefColor ),
1273 maShadowOffset( rShadowOffset ),
1274 maShadowColor( rShadowColor )
1276 initEffectLinePolyPolygon( maLinesOverallSize,
1277 mxTextLines,
1278 rCanvas,
1279 rOffsets,
1280 maTextLineInfo );
1282 initArrayAction( maState,
1283 mxTextLayout,
1284 rStartPoint,
1285 rText,
1286 nStartPos,
1287 nLen,
1288 rOffsets,
1289 rCanvas,
1290 rState, NULL );
1293 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1294 const ::basegfx::B2DSize& rReliefOffset,
1295 const ::Color& rReliefColor,
1296 const ::basegfx::B2DSize& rShadowOffset,
1297 const ::Color& rShadowColor,
1298 const OUString& rText,
1299 sal_Int32 nStartPos,
1300 sal_Int32 nLen,
1301 const uno::Sequence< double >& rOffsets,
1302 VirtualDevice& rVDev,
1303 const CanvasSharedPtr& rCanvas,
1304 const OutDevState& rState,
1305 const ::basegfx::B2DHomMatrix& rTextTransform ) :
1306 mxTextLayout(),
1307 mpCanvas( rCanvas ),
1308 maState(),
1309 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1310 maLinesOverallSize(),
1311 mxTextLines(),
1312 maReliefOffset( rReliefOffset ),
1313 maReliefColor( rReliefColor ),
1314 maShadowOffset( rShadowOffset ),
1315 maShadowColor( rShadowColor )
1317 initEffectLinePolyPolygon( maLinesOverallSize,
1318 mxTextLines,
1319 rCanvas,
1320 rOffsets,
1321 maTextLineInfo );
1323 initArrayAction( maState,
1324 mxTextLayout,
1325 rStartPoint,
1326 rText,
1327 nStartPos,
1328 nLen,
1329 rOffsets,
1330 rCanvas,
1331 rState,
1332 &rTextTransform );
1335 bool EffectTextArrayAction::operator()( const rendering::RenderState& rRenderState ) const
1337 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1338 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
1340 rCanvas->fillPolyPolygon( mxTextLines,
1341 rViewState,
1342 rRenderState );
1344 rCanvas->drawTextLayout( mxTextLayout,
1345 rViewState,
1346 rRenderState );
1348 return true;
1351 bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1353 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::render()" );
1354 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex << this );
1356 rendering::RenderState aLocalState( maState );
1357 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1359 return renderEffectText( *this,
1360 aLocalState,
1361 mpCanvas->getViewState(),
1362 mpCanvas->getUNOCanvas(),
1363 maShadowColor,
1364 maShadowOffset,
1365 maReliefColor,
1366 maReliefOffset );
1369 class EffectTextArrayRenderHelper : public TextRenderer
1371 public:
1372 EffectTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas,
1373 const uno::Reference< rendering::XTextLayout >& rTextLayout,
1374 const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon,
1375 const rendering::ViewState& rViewState ) :
1376 mrCanvas( rCanvas ),
1377 mrTextLayout( rTextLayout ),
1378 mrLinePolygon( rLinePolygon ),
1379 mrViewState( rViewState )
1383 // TextRenderer interface
1384 virtual bool operator()( const rendering::RenderState& rRenderState ) const SAL_OVERRIDE
1386 mrCanvas->fillPolyPolygon( mrLinePolygon,
1387 mrViewState,
1388 rRenderState );
1390 mrCanvas->drawTextLayout( mrTextLayout,
1391 mrViewState,
1392 rRenderState );
1394 return true;
1397 private:
1398 const uno::Reference< rendering::XCanvas >& mrCanvas;
1399 const uno::Reference< rendering::XTextLayout >& mrTextLayout;
1400 const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon;
1401 const rendering::ViewState& mrViewState;
1404 bool EffectTextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1405 const Subset& rSubset ) const
1407 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::renderSubset()" );
1408 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex << this );
1410 rendering::RenderState aLocalState( maState );
1411 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1412 const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() );
1414 double nMinPos(0.0);
1415 double nMaxPos(aTextBounds.X2 - aTextBounds.X1);
1417 createSubsetLayout( xTextLayout,
1418 aLocalState,
1419 nMinPos,
1420 nMaxPos,
1421 rTransformation,
1422 rSubset );
1424 if( !xTextLayout.is() )
1425 return true; // empty layout, render nothing
1428 // create and setup local line polygon
1429 // ===================================
1431 uno::Reference< rendering::XCanvas > xCanvas( mpCanvas->getUNOCanvas() );
1432 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1434 uno::Reference< rendering::XPolyPolygon2D > xTextLines(
1435 ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1436 xCanvas->getDevice(),
1437 tools::createTextLinesPolyPolygon(
1438 0.0, nMaxPos - nMinPos,
1439 maTextLineInfo ) ) );
1442 // render everything
1443 // =================
1445 return renderEffectText(
1446 EffectTextArrayRenderHelper( xCanvas,
1447 xTextLayout,
1448 xTextLines,
1449 rViewState ),
1450 aLocalState,
1451 rViewState,
1452 xCanvas,
1453 maShadowColor,
1454 maShadowOffset,
1455 maReliefColor,
1456 maReliefOffset );
1459 ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1461 rendering::RenderState aLocalState( maState );
1462 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1464 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1465 mxTextLayout->queryTextBounds() ),
1466 ::basegfx::B2DRange( 0,0,
1467 maLinesOverallSize.getX(),
1468 maLinesOverallSize.getY() ),
1469 maReliefOffset,
1470 maShadowOffset,
1471 aLocalState,
1472 mpCanvas->getViewState() );
1475 ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1476 const Subset& rSubset ) const
1478 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::getBounds( subset )" );
1479 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex << this );
1481 rendering::RenderState aLocalState( maState );
1482 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1483 const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() );
1485 double nMinPos(0.0);
1486 double nMaxPos(aTextBounds.X2 - aTextBounds.X1);
1488 createSubsetLayout( xTextLayout,
1489 aLocalState,
1490 nMinPos,
1491 nMaxPos,
1492 rTransformation,
1493 rSubset );
1495 if( !xTextLayout.is() )
1496 return ::basegfx::B2DRange(); // empty layout, empty bounds
1499 // create and setup local line polygon
1500 // ===================================
1502 const ::basegfx::B2DPolyPolygon aPoly(
1503 tools::createTextLinesPolyPolygon(
1504 0.0, nMaxPos - nMinPos,
1505 maTextLineInfo ) );
1507 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1508 xTextLayout->queryTextBounds() ),
1509 ::basegfx::tools::getRange( aPoly ),
1510 maReliefOffset,
1511 maShadowOffset,
1512 aLocalState,
1513 mpCanvas->getViewState() );
1516 sal_Int32 EffectTextArrayAction::getActionCount() const
1518 const rendering::StringContext& rOrigContext( mxTextLayout->getText() );
1520 return rOrigContext.Length;
1526 class OutlineAction :
1527 public Action,
1528 public TextRenderer,
1529 private ::boost::noncopyable
1531 public:
1532 OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1533 const ::basegfx::B2DSize& rReliefOffset,
1534 const ::Color& rReliefColor,
1535 const ::basegfx::B2DSize& rShadowOffset,
1536 const ::Color& rShadowColor,
1537 const ::basegfx::B2DRectangle& rOutlineBounds,
1538 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1539 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1540 const uno::Sequence< double >& rOffsets,
1541 VirtualDevice& rVDev,
1542 const CanvasSharedPtr& rCanvas,
1543 const OutDevState& rState );
1544 OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1545 const ::basegfx::B2DSize& rReliefOffset,
1546 const ::Color& rReliefColor,
1547 const ::basegfx::B2DSize& rShadowOffset,
1548 const ::Color& rShadowColor,
1549 const ::basegfx::B2DRectangle& rOutlineBounds,
1550 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1551 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1552 const uno::Sequence< double >& rOffsets,
1553 VirtualDevice& rVDev,
1554 const CanvasSharedPtr& rCanvas,
1555 const OutDevState& rState,
1556 const ::basegfx::B2DHomMatrix& rTextTransform );
1558 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
1559 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1560 const Subset& rSubset ) const SAL_OVERRIDE;
1562 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
1563 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1564 const Subset& rSubset ) const SAL_OVERRIDE;
1566 virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
1568 private:
1569 // TextRenderer interface
1570 virtual bool operator()( const rendering::RenderState& rRenderState ) const SAL_OVERRIDE;
1572 // TODO(P2): This is potentially a real mass object
1573 // (every character might be a separate TextAction),
1574 // thus, make it as lightweight as possible. For
1575 // example, share common RenderState among several
1576 // TextActions, maybe using maOffsets for the
1577 // translation.
1579 uno::Reference< rendering::XPolyPolygon2D > mxTextPoly;
1581 /** This vector denotes the index of the start polygon
1582 for the respective glyph sequence.
1584 To get a polygon index range for a given character
1585 index i, take [ maPolygonGlyphMap[i],
1586 maPolygonGlyphMap[i+1] ). Note that this is wrong
1587 for BiDi
1589 const ::std::vector< sal_Int32 > maPolygonGlyphMap;
1590 const uno::Sequence< double > maOffsets;
1591 const CanvasSharedPtr mpCanvas;
1592 rendering::RenderState maState;
1593 double mnOutlineWidth;
1594 const uno::Sequence< double > maFillColor;
1595 const tools::TextLineInfo maTextLineInfo;
1596 ::basegfx::B2DSize maLinesOverallSize;
1597 const ::basegfx::B2DRectangle maOutlineBounds;
1598 uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
1599 const ::basegfx::B2DSize maReliefOffset;
1600 const ::Color maReliefColor;
1601 const ::basegfx::B2DSize maShadowOffset;
1602 const ::Color maShadowColor;
1605 double calcOutlineWidth( const OutDevState& rState,
1606 VirtualDevice& rVDev )
1608 const ::basegfx::B2DSize aFontSize( 0,
1609 rVDev.GetFont().GetHeight() / 64.0 );
1611 const double nOutlineWidth(
1612 (rState.mapModeTransform * aFontSize).getY() );
1614 return nOutlineWidth < 1.0 ? 1.0 : nOutlineWidth;
1617 OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1618 const ::basegfx::B2DSize& rReliefOffset,
1619 const ::Color& rReliefColor,
1620 const ::basegfx::B2DSize& rShadowOffset,
1621 const ::Color& rShadowColor,
1622 const ::basegfx::B2DRectangle& rOutlineBounds,
1623 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1624 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1625 const uno::Sequence< double >& rOffsets,
1626 VirtualDevice& rVDev,
1627 const CanvasSharedPtr& rCanvas,
1628 const OutDevState& rState ) :
1629 mxTextPoly( rTextPoly ),
1630 maPolygonGlyphMap( rPolygonGlyphMap ),
1631 maOffsets( rOffsets ),
1632 mpCanvas( rCanvas ),
1633 maState(),
1634 mnOutlineWidth( calcOutlineWidth(rState,rVDev) ),
1635 maFillColor(
1636 vcl::unotools::colorToDoubleSequence(
1637 ::Color( COL_WHITE ),
1638 rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1639 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1640 maLinesOverallSize(),
1641 maOutlineBounds( rOutlineBounds ),
1642 mxTextLines(),
1643 maReliefOffset( rReliefOffset ),
1644 maReliefColor( rReliefColor ),
1645 maShadowOffset( rShadowOffset ),
1646 maShadowColor( rShadowColor )
1648 initEffectLinePolyPolygon( maLinesOverallSize,
1649 mxTextLines,
1650 rCanvas,
1651 rOffsets,
1652 maTextLineInfo );
1654 init( maState,
1655 rStartPoint,
1656 rState,
1657 rCanvas );
1660 OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1661 const ::basegfx::B2DSize& rReliefOffset,
1662 const ::Color& rReliefColor,
1663 const ::basegfx::B2DSize& rShadowOffset,
1664 const ::Color& rShadowColor,
1665 const ::basegfx::B2DRectangle& rOutlineBounds,
1666 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1667 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1668 const uno::Sequence< double >& rOffsets,
1669 VirtualDevice& rVDev,
1670 const CanvasSharedPtr& rCanvas,
1671 const OutDevState& rState,
1672 const ::basegfx::B2DHomMatrix& rTextTransform ) :
1673 mxTextPoly( rTextPoly ),
1674 maPolygonGlyphMap( rPolygonGlyphMap ),
1675 maOffsets( rOffsets ),
1676 mpCanvas( rCanvas ),
1677 maState(),
1678 mnOutlineWidth( calcOutlineWidth(rState,rVDev) ),
1679 maFillColor(
1680 vcl::unotools::colorToDoubleSequence(
1681 ::Color( COL_WHITE ),
1682 rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1683 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1684 maLinesOverallSize(),
1685 maOutlineBounds( rOutlineBounds ),
1686 mxTextLines(),
1687 maReliefOffset( rReliefOffset ),
1688 maReliefColor( rReliefColor ),
1689 maShadowOffset( rShadowOffset ),
1690 maShadowColor( rShadowColor )
1692 initEffectLinePolyPolygon( maLinesOverallSize,
1693 mxTextLines,
1694 rCanvas,
1695 rOffsets,
1696 maTextLineInfo );
1698 init( maState,
1699 rStartPoint,
1700 rState,
1701 rCanvas,
1702 rTextTransform );
1705 bool OutlineAction::operator()( const rendering::RenderState& rRenderState ) const
1707 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1708 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
1710 rendering::StrokeAttributes aStrokeAttributes;
1712 aStrokeAttributes.StrokeWidth = mnOutlineWidth;
1713 aStrokeAttributes.MiterLimit = 1.0;
1714 aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
1715 aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
1716 aStrokeAttributes.JoinType = rendering::PathJoinType::MITER;
1718 rendering::RenderState aLocalState( rRenderState );
1719 aLocalState.DeviceColor = maFillColor;
1721 // TODO(P1): implement caching
1723 // background of text
1724 rCanvas->fillPolyPolygon( mxTextPoly,
1725 rViewState,
1726 aLocalState );
1728 // border line of text
1729 rCanvas->strokePolyPolygon( mxTextPoly,
1730 rViewState,
1731 rRenderState,
1732 aStrokeAttributes );
1734 // underlines/strikethrough - background
1735 rCanvas->fillPolyPolygon( mxTextLines,
1736 rViewState,
1737 aLocalState );
1738 // underlines/strikethrough - border
1739 rCanvas->strokePolyPolygon( mxTextLines,
1740 rViewState,
1741 rRenderState,
1742 aStrokeAttributes );
1744 return true;
1747 bool OutlineAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1749 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::render()" );
1750 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex << this );
1752 rendering::RenderState aLocalState( maState );
1753 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1755 return renderEffectText( *this,
1756 aLocalState,
1757 mpCanvas->getViewState(),
1758 mpCanvas->getUNOCanvas(),
1759 maShadowColor,
1760 maShadowOffset,
1761 maReliefColor,
1762 maReliefOffset );
1765 #if 0 // see #if'ed out use in OutlineAction::renderSubset below:
1766 class OutlineTextArrayRenderHelper : public TextRenderer
1768 public:
1769 OutlineTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas,
1770 const uno::Reference< rendering::XPolyPolygon2D >& rTextPolygon,
1771 const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon,
1772 const rendering::ViewState& rViewState,
1773 double nOutlineWidth ) :
1774 maFillColor(
1775 vcl::unotools::colorToDoubleSequence(
1776 ::Color( COL_WHITE ),
1777 rCanvas->getDevice()->getDeviceColorSpace() )),
1778 mnOutlineWidth( nOutlineWidth ),
1779 mrCanvas( rCanvas ),
1780 mrTextPolygon( rTextPolygon ),
1781 mrLinePolygon( rLinePolygon ),
1782 mrViewState( rViewState )
1786 // TextRenderer interface
1787 virtual bool operator()( const rendering::RenderState& rRenderState ) const
1789 rendering::StrokeAttributes aStrokeAttributes;
1791 aStrokeAttributes.StrokeWidth = mnOutlineWidth;
1792 aStrokeAttributes.MiterLimit = 1.0;
1793 aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
1794 aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
1795 aStrokeAttributes.JoinType = rendering::PathJoinType::MITER;
1797 rendering::RenderState aLocalState( rRenderState );
1798 aLocalState.DeviceColor = maFillColor;
1800 // TODO(P1): implement caching
1802 // background of text
1803 mrCanvas->fillPolyPolygon( mrTextPolygon,
1804 mrViewState,
1805 aLocalState );
1807 // border line of text
1808 mrCanvas->strokePolyPolygon( mrTextPolygon,
1809 mrViewState,
1810 rRenderState,
1811 aStrokeAttributes );
1813 // underlines/strikethrough - background
1814 mrCanvas->fillPolyPolygon( mrLinePolygon,
1815 mrViewState,
1816 aLocalState );
1817 // underlines/strikethrough - border
1818 mrCanvas->strokePolyPolygon( mrLinePolygon,
1819 mrViewState,
1820 rRenderState,
1821 aStrokeAttributes );
1823 return true;
1826 private:
1827 const uno::Sequence< double > maFillColor;
1828 double mnOutlineWidth;
1829 const uno::Reference< rendering::XCanvas >& mrCanvas;
1830 const uno::Reference< rendering::XPolyPolygon2D >& mrTextPolygon;
1831 const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon;
1832 const rendering::ViewState& mrViewState;
1834 #endif
1836 bool OutlineAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1837 const Subset& rSubset ) const
1839 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction::renderSubset()" );
1840 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction: 0x" << std::hex << this );
1842 if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd )
1843 return true; // empty range, render nothing
1845 #if 1
1846 // TODO(F3): Subsetting NYI for outline text!
1847 return render( rTransformation );
1848 #else
1849 const rendering::StringContext rOrigContext( mxTextLayout->getText() );
1851 if( rSubset.mnSubsetBegin == 0 &&
1852 rSubset.mnSubsetEnd == rOrigContext.Length )
1854 // full range, no need for subsetting
1855 return render( rTransformation );
1858 rendering::RenderState aLocalState( maState );
1859 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1862 // create and setup local Text polygon
1863 // ===================================
1865 uno::Reference< rendering::XPolyPolygon2D > xTextPolygon();
1867 // TODO(P3): Provide an API method for that!
1869 if( !xTextLayout.is() )
1870 return false;
1872 // render everything
1873 // =================
1875 return renderEffectText(
1876 OutlineTextArrayRenderHelper(
1877 xCanvas,
1878 mnOutlineWidth,
1879 xTextLayout,
1880 xTextLines,
1881 rViewState ),
1882 aLocalState,
1883 rViewState,
1884 xCanvas,
1885 maShadowColor,
1886 maShadowOffset,
1887 maReliefColor,
1888 maReliefOffset );
1889 #endif
1892 ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1894 rendering::RenderState aLocalState( maState );
1895 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1897 return calcEffectTextBounds( maOutlineBounds,
1898 ::basegfx::B2DRange( 0,0,
1899 maLinesOverallSize.getX(),
1900 maLinesOverallSize.getY() ),
1901 maReliefOffset,
1902 maShadowOffset,
1903 aLocalState,
1904 mpCanvas->getViewState() );
1907 ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1908 const Subset& /*rSubset*/ ) const
1910 SAL_WARN( "cppcanvas.emf", "OutlineAction::getBounds(): Subset not yet supported by this object" );
1912 return getBounds( rTransformation );
1915 sal_Int32 OutlineAction::getActionCount() const
1917 // TODO(F3): Subsetting NYI for outline text!
1918 return maOffsets.getLength();
1924 // Action factory methods
1928 /** Create an outline action
1930 This method extracts the polygonal outline from the
1931 text, and creates a properly setup OutlineAction from
1934 ActionSharedPtr createOutline( const ::basegfx::B2DPoint& rStartPoint,
1935 const ::basegfx::B2DSize& rReliefOffset,
1936 const ::Color& rReliefColor,
1937 const ::basegfx::B2DSize& rShadowOffset,
1938 const ::Color& rShadowColor,
1939 const OUString& rText,
1940 sal_Int32 nStartPos,
1941 sal_Int32 nLen,
1942 const long* pDXArray,
1943 VirtualDevice& rVDev,
1944 const CanvasSharedPtr& rCanvas,
1945 const OutDevState& rState,
1946 const Renderer::Parameters& rParms )
1948 // operate on raw DX array here (in logical coordinate
1949 // system), to have a higher resolution
1950 // PolyPolygon. That polygon is then converted to
1951 // device coordinate system.
1953 // #i68512# Temporarily switch off font rotation
1954 // (which is already contained in the render state
1955 // transformation matrix - otherwise, glyph polygons
1956 // will be rotated twice)
1957 const vcl::Font aOrigFont( rVDev.GetFont() );
1958 vcl::Font aUnrotatedFont( aOrigFont );
1959 aUnrotatedFont.SetOrientation(0);
1960 rVDev.SetFont( aUnrotatedFont );
1962 // TODO(F3): Don't understand parameter semantics of
1963 // GetTextOutlines()
1964 ::basegfx::B2DPolyPolygon aResultingPolyPolygon;
1965 PolyPolyVector aVCLPolyPolyVector;
1966 const bool bHaveOutlines( rVDev.GetTextOutlines( aVCLPolyPolyVector, rText,
1967 static_cast<sal_uInt16>(nStartPos),
1968 static_cast<sal_uInt16>(nStartPos),
1969 static_cast<sal_uInt16>(nLen),
1970 true, 0, pDXArray ) );
1971 rVDev.SetFont(aOrigFont);
1973 if( !bHaveOutlines )
1974 return ActionSharedPtr();
1976 ::std::vector< sal_Int32 > aPolygonGlyphMap;
1978 // first glyph starts at polygon index 0
1979 aPolygonGlyphMap.push_back( 0 );
1981 // remove offsetting from mapmode transformation
1982 // (outline polygons must stay at origin, only need to
1983 // be scaled)
1984 ::basegfx::B2DHomMatrix aMapModeTransform(
1985 rState.mapModeTransform );
1986 aMapModeTransform.set(0,2, 0.0);
1987 aMapModeTransform.set(1,2, 0.0);
1989 PolyPolyVector::const_iterator aIter( aVCLPolyPolyVector.begin() );
1990 const PolyPolyVector::const_iterator aEnd( aVCLPolyPolyVector.end() );
1991 for( ; aIter!= aEnd; ++aIter )
1993 ::basegfx::B2DPolyPolygon aPolyPolygon;
1995 aPolyPolygon = aIter->getB2DPolyPolygon();
1996 aPolyPolygon.transform( aMapModeTransform );
1998 // append result to collecting polypoly
1999 for( sal_uInt32 i=0; i<aPolyPolygon.count(); ++i )
2001 // #i47795# Ensure closed polygons (since
2002 // FreeType returns the glyph outlines
2003 // open)
2004 const ::basegfx::B2DPolygon& rPoly( aPolyPolygon.getB2DPolygon( i ) );
2005 const sal_uInt32 nCount( rPoly.count() );
2006 if( nCount<3 ||
2007 rPoly.isClosed() )
2009 // polygon either degenerate, or
2010 // already closed.
2011 aResultingPolyPolygon.append( rPoly );
2013 else
2015 ::basegfx::B2DPolygon aPoly(rPoly);
2016 aPoly.setClosed(true);
2018 aResultingPolyPolygon.append( aPoly );
2022 // TODO(F3): Depending on the semantics of
2023 // GetTextOutlines(), this here is wrong!
2025 // calc next glyph index
2026 aPolygonGlyphMap.push_back( aResultingPolyPolygon.count() );
2029 const uno::Sequence< double > aCharWidthSeq(
2030 pDXArray ?
2031 setupDXArray( pDXArray, nLen, rState ) :
2032 setupDXArray( rText,
2033 nStartPos,
2034 nLen,
2035 rVDev,
2036 rState ));
2037 const uno::Reference< rendering::XPolyPolygon2D > xTextPoly(
2038 ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
2039 rCanvas->getUNOCanvas()->getDevice(),
2040 aResultingPolyPolygon ) );
2042 if( rParms.maTextTransformation.is_initialized() )
2044 return ActionSharedPtr(
2045 new OutlineAction(
2046 rStartPoint,
2047 rReliefOffset,
2048 rReliefColor,
2049 rShadowOffset,
2050 rShadowColor,
2051 ::basegfx::tools::getRange(aResultingPolyPolygon),
2052 xTextPoly,
2053 aPolygonGlyphMap,
2054 aCharWidthSeq,
2055 rVDev,
2056 rCanvas,
2057 rState,
2058 *rParms.maTextTransformation ) );
2060 else
2062 return ActionSharedPtr(
2063 new OutlineAction(
2064 rStartPoint,
2065 rReliefOffset,
2066 rReliefColor,
2067 rShadowOffset,
2068 rShadowColor,
2069 ::basegfx::tools::getRange(aResultingPolyPolygon),
2070 xTextPoly,
2071 aPolygonGlyphMap,
2072 aCharWidthSeq,
2073 rVDev,
2074 rCanvas,
2075 rState ) );
2079 } // namespace
2084 ActionSharedPtr TextActionFactory::createTextAction( const ::Point& rStartPoint,
2085 const ::Size& rReliefOffset,
2086 const ::Color& rReliefColor,
2087 const ::Size& rShadowOffset,
2088 const ::Color& rShadowColor,
2089 const OUString& rText,
2090 sal_Int32 nStartPos,
2091 sal_Int32 nLen,
2092 const long* pDXArray,
2093 VirtualDevice& rVDev,
2094 const CanvasSharedPtr& rCanvas,
2095 const OutDevState& rState,
2096 const Renderer::Parameters& rParms,
2097 bool bSubsettable )
2099 const ::Size aBaselineOffset( tools::getBaselineOffset( rState,
2100 rVDev ) );
2101 // #143885# maintain (nearly) full precision positioning,
2102 // by circumventing integer-based OutDev-mapping
2103 const ::basegfx::B2DPoint aStartPoint(
2104 rState.mapModeTransform *
2105 ::basegfx::B2DPoint(rStartPoint.X() + aBaselineOffset.Width(),
2106 rStartPoint.Y() + aBaselineOffset.Height()) );
2108 const ::basegfx::B2DSize aReliefOffset(
2109 rState.mapModeTransform * vcl::unotools::b2DSizeFromSize( rReliefOffset ) );
2110 const ::basegfx::B2DSize aShadowOffset(
2111 rState.mapModeTransform * vcl::unotools::b2DSizeFromSize( rShadowOffset ) );
2113 if( rState.isTextOutlineModeSet )
2115 return createOutline(
2116 aStartPoint,
2117 aReliefOffset,
2118 rReliefColor,
2119 aShadowOffset,
2120 rShadowColor,
2121 rText,
2122 nStartPos,
2123 nLen,
2124 pDXArray,
2125 rVDev,
2126 rCanvas,
2127 rState,
2128 rParms );
2131 // convert DX array to device coordinate system (and
2132 // create it in the first place, if pDXArray is NULL)
2133 const uno::Sequence< double > aCharWidths(
2134 pDXArray ?
2135 setupDXArray( pDXArray, nLen, rState ) :
2136 setupDXArray( rText,
2137 nStartPos,
2138 nLen,
2139 rVDev,
2140 rState ));
2142 // determine type of text action to create
2143 // =======================================
2145 const ::Color aEmptyColor( COL_AUTO );
2147 ActionSharedPtr ret;
2149 // no DX array, and no need to subset - no need to store
2150 // DX array, then.
2151 if( !pDXArray && !bSubsettable )
2153 // effects, or not?
2154 if( !rState.textOverlineStyle &&
2155 !rState.textUnderlineStyle &&
2156 !rState.textStrikeoutStyle &&
2157 rReliefColor == aEmptyColor &&
2158 rShadowColor == aEmptyColor )
2160 // nope
2161 if( rParms.maTextTransformation.is_initialized() )
2163 ret = ActionSharedPtr( new TextAction(
2164 aStartPoint,
2165 rText,
2166 nStartPos,
2167 nLen,
2168 rCanvas,
2169 rState,
2170 *rParms.maTextTransformation ) );
2172 else
2174 ret = ActionSharedPtr( new TextAction(
2175 aStartPoint,
2176 rText,
2177 nStartPos,
2178 nLen,
2179 rCanvas,
2180 rState ) );
2183 else
2185 // at least one of the effects requested
2186 if( rParms.maTextTransformation.is_initialized() )
2187 ret = ActionSharedPtr( new EffectTextAction(
2188 aStartPoint,
2189 aReliefOffset,
2190 rReliefColor,
2191 aShadowOffset,
2192 rShadowColor,
2193 rText,
2194 nStartPos,
2195 nLen,
2196 rVDev,
2197 rCanvas,
2198 rState,
2199 *rParms.maTextTransformation ) );
2200 else
2201 ret = ActionSharedPtr( new EffectTextAction(
2202 aStartPoint,
2203 aReliefOffset,
2204 rReliefColor,
2205 aShadowOffset,
2206 rShadowColor,
2207 rText,
2208 nStartPos,
2209 nLen,
2210 rVDev,
2211 rCanvas,
2212 rState ) );
2215 else
2217 // DX array necessary - any effects?
2218 if( !rState.textOverlineStyle &&
2219 !rState.textUnderlineStyle &&
2220 !rState.textStrikeoutStyle &&
2221 rReliefColor == aEmptyColor &&
2222 rShadowColor == aEmptyColor )
2224 // nope
2225 if( rParms.maTextTransformation.is_initialized() )
2226 ret = ActionSharedPtr( new TextArrayAction(
2227 aStartPoint,
2228 rText,
2229 nStartPos,
2230 nLen,
2231 aCharWidths,
2232 rCanvas,
2233 rState,
2234 *rParms.maTextTransformation ) );
2235 else
2236 ret = ActionSharedPtr( new TextArrayAction(
2237 aStartPoint,
2238 rText,
2239 nStartPos,
2240 nLen,
2241 aCharWidths,
2242 rCanvas,
2243 rState ) );
2245 else
2247 // at least one of the effects requested
2248 if( rParms.maTextTransformation.is_initialized() )
2249 ret = ActionSharedPtr( new EffectTextArrayAction(
2250 aStartPoint,
2251 aReliefOffset,
2252 rReliefColor,
2253 aShadowOffset,
2254 rShadowColor,
2255 rText,
2256 nStartPos,
2257 nLen,
2258 aCharWidths,
2259 rVDev,
2260 rCanvas,
2261 rState,
2262 *rParms.maTextTransformation ) );
2263 else
2264 ret = ActionSharedPtr( new EffectTextArrayAction(
2265 aStartPoint,
2266 aReliefOffset,
2267 rReliefColor,
2268 aShadowOffset,
2269 rShadowColor,
2270 rText,
2271 nStartPos,
2272 nLen,
2273 aCharWidths,
2274 rVDev,
2275 rCanvas,
2276 rState ) );
2279 return ret;
2284 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */