update dev300-m58
[ooovba.git] / cppcanvas / source / mtfrenderer / textaction.cxx
blob3d6114e909f2deadee5fa2dbd33836e02f9dc4ec
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: textaction.cxx,v $
10 * $Revision: 1.22.4.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_cppcanvas.hxx"
34 #include <canvas/debug.hxx>
35 #include <tools/diagnose_ex.h>
36 #include <canvas/verbosetrace.hxx>
38 #include <rtl/logfile.hxx>
40 #include <com/sun/star/rendering/PathCapType.hpp>
41 #include <com/sun/star/rendering/PathJoinType.hpp>
42 #include <com/sun/star/rendering/XCanvas.hpp>
43 #include <com/sun/star/rendering/XCanvasFont.hpp>
45 #include <basegfx/numeric/ftools.hxx>
46 #include <basegfx/matrix/b2dhommatrix.hxx>
47 #include <basegfx/range/b2drectangle.hxx>
48 #include <basegfx/vector/b2dsize.hxx>
49 #include <basegfx/polygon/b2dpolypolygontools.hxx>
50 #include <basegfx/polygon/b2dpolygontools.hxx>
52 #include <tools/gen.hxx>
53 #include <vcl/canvastools.hxx>
54 #include <vcl/virdev.hxx>
56 #include <basegfx/tools/canvastools.hxx>
57 #include <canvas/canvastools.hxx>
59 #include <boost/scoped_array.hpp>
60 #include <boost/bind.hpp>
61 #include <boost/utility.hpp>
63 #include "textaction.hxx"
64 #include "outdevstate.hxx"
65 #include "mtftools.hxx"
68 using namespace ::com::sun::star;
70 namespace cppcanvas
72 namespace internal
74 namespace
76 void init( rendering::RenderState& o_rRenderState,
77 const ::basegfx::B2DPoint& rStartPoint,
78 const OutDevState& rState,
79 const CanvasSharedPtr& rCanvas )
81 tools::initRenderState(o_rRenderState,rState);
83 // #i36950# Offset clip back to origin (as it's also moved
84 // by rStartPoint)
85 // #i53964# Also take VCL font rotation into account,
86 // since this, opposed to the FontMatrix rotation
87 // elsewhere, _does_ get incorporated into the render
88 // state transform.
89 tools::modifyClip( o_rRenderState,
90 rState,
91 rCanvas,
92 rStartPoint,
93 NULL,
94 &rState.fontRotation );
96 ::basegfx::B2DHomMatrix aLocalTransformation;
98 aLocalTransformation.rotate( rState.fontRotation );
99 aLocalTransformation.translate( rStartPoint.getX(),
100 rStartPoint.getY() );
101 ::canvas::tools::appendToRenderState( o_rRenderState,
102 aLocalTransformation );
104 o_rRenderState.DeviceColor = rState.textColor;
107 void init( rendering::RenderState& o_rRenderState,
108 const ::basegfx::B2DPoint& rStartPoint,
109 const OutDevState& rState,
110 const CanvasSharedPtr& rCanvas,
111 const ::basegfx::B2DHomMatrix& rTextTransform )
113 init( o_rRenderState, rStartPoint, rState, rCanvas );
115 // TODO(F2): Also inversely-transform clip with
116 // rTextTransform (which is actually rather hard, as the
117 // text transform is _prepended_ to the render state)!
119 // prepend extra font transform to render state
120 // (prepend it, because it's interpreted in the unit
121 // rect coordinate space)
122 ::canvas::tools::prependToRenderState( o_rRenderState,
123 rTextTransform );
126 void init( rendering::RenderState& o_rRenderState,
127 uno::Reference< rendering::XCanvasFont >& o_rFont,
128 const ::basegfx::B2DPoint& rStartPoint,
129 const OutDevState& rState,
130 const CanvasSharedPtr& rCanvas )
132 // ensure that o_rFont is valid. It is possible that
133 // text actions are generated without previously
134 // setting a font. Then, just take a default font
135 if( !o_rFont.is() )
137 // Use completely default FontRequest
138 const rendering::FontRequest aFontRequest;
140 geometry::Matrix2D aFontMatrix;
141 ::canvas::tools::setIdentityMatrix2D( aFontMatrix );
143 o_rFont = rCanvas->getUNOCanvas()->createFont(
144 aFontRequest,
145 uno::Sequence< beans::PropertyValue >(),
146 aFontMatrix );
149 init( o_rRenderState,
150 rStartPoint,
151 rState,
152 rCanvas );
155 void init( rendering::RenderState& o_rRenderState,
156 uno::Reference< rendering::XCanvasFont >& o_rFont,
157 const ::basegfx::B2DPoint& rStartPoint,
158 const OutDevState& rState,
159 const CanvasSharedPtr& rCanvas,
160 const ::basegfx::B2DHomMatrix& rTextTransform )
162 init( o_rRenderState, o_rFont, rStartPoint, rState, rCanvas );
164 // TODO(F2): Also inversely-transform clip with
165 // rTextTransform (which is actually rather hard, as the
166 // text transform is _prepended_ to the render state)!
168 // prepend extra font transform to render state
169 // (prepend it, because it's interpreted in the unit
170 // rect coordinate space)
171 ::canvas::tools::prependToRenderState( o_rRenderState,
172 rTextTransform );
175 ::basegfx::B2DPolyPolygon textLinesFromLogicalOffsets( const uno::Sequence< double >& rOffsets,
176 const tools::TextLineInfo& rTextLineInfo )
178 return tools::createTextLinesPolyPolygon(
179 0.0,
180 // extract character cell furthest to the right
181 *(::std::max_element(
182 rOffsets.getConstArray(),
183 rOffsets.getConstArray() + rOffsets.getLength() )),
184 rTextLineInfo );
187 uno::Sequence< double > setupDXArray( const sal_Int32* pCharWidths,
188 sal_Int32 nLen,
189 const OutDevState& rState )
191 // convert character widths from logical units
192 uno::Sequence< double > aCharWidthSeq( nLen );
193 double* pOutputWidths( aCharWidthSeq.getArray() );
195 // #143885# maintain (nearly) full precision of DX
196 // array, by circumventing integer-based
197 // OutDev-mapping
198 const double nScale( rState.mapModeTransform.get(0,0) );
199 for( int i = 0; i < nLen; ++i )
201 // TODO(F2): use correct scale direction
202 *pOutputWidths++ = *pCharWidths++ * nScale;
205 return aCharWidthSeq;
208 uno::Sequence< double > setupDXArray( const ::String& rText,
209 sal_Int32 nStartPos,
210 sal_Int32 nLen,
211 VirtualDevice& rVDev,
212 const OutDevState& rState )
214 // no external DX array given, create one from given
215 // string
216 ::boost::scoped_array< sal_Int32 > pCharWidths( new sal_Int32[nLen] );
218 rVDev.GetTextArray( rText, pCharWidths.get(),
219 static_cast<USHORT>(nStartPos),
220 static_cast<USHORT>(nLen) );
222 return setupDXArray( pCharWidths.get(), nLen, rState );
225 ::basegfx::B2DPoint adaptStartPoint( const ::basegfx::B2DPoint& rStartPoint,
226 const OutDevState& rState,
227 const uno::Sequence< double >& rOffsets )
229 ::basegfx::B2DPoint aLocalPoint( rStartPoint );
231 if( rState.textAlignment )
233 // text origin is right, not left. Modify start point
234 // accordingly, because XCanvas::drawTextLayout()
235 // always aligns left!
237 const double nOffset( rOffsets[ rOffsets.getLength()-1 ] );
239 // correct start point for rotated text: rotate around
240 // former start point
241 aLocalPoint.setX( aLocalPoint.getX() + cos( rState.fontRotation )*nOffset );
242 aLocalPoint.setY( aLocalPoint.getY() + sin( rState.fontRotation )*nOffset );
245 return aLocalPoint;
248 /** Perform common setup for array text actions
250 This method creates the XTextLayout object and
251 initializes it, e.g. with the logical advancements.
253 void initArrayAction( rendering::RenderState& o_rRenderState,
254 uno::Reference< rendering::XTextLayout >& o_rTextLayout,
255 const ::basegfx::B2DPoint& rStartPoint,
256 const ::rtl::OUString& rText,
257 sal_Int32 nStartPos,
258 sal_Int32 nLen,
259 const uno::Sequence< double >& rOffsets,
260 const CanvasSharedPtr& rCanvas,
261 const OutDevState& rState,
262 const ::basegfx::B2DHomMatrix* pTextTransform )
264 ENSURE_OR_THROW( rOffsets.getLength(),
265 "::cppcanvas::internal::initArrayAction(): zero-length DX array" );
267 const ::basegfx::B2DPoint aLocalStartPoint(
268 adaptStartPoint( rStartPoint, rState, rOffsets ) );
270 uno::Reference< rendering::XCanvasFont > xFont( rState.xFont );
272 if( pTextTransform )
273 init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas, *pTextTransform );
274 else
275 init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas );
277 o_rTextLayout = xFont->createTextLayout(
278 rendering::StringContext( rText, nStartPos, nLen ),
279 rState.textDirection,
280 0 );
282 ENSURE_OR_THROW( o_rTextLayout.is(),
283 "::cppcanvas::internal::initArrayAction(): Invalid font" );
285 o_rTextLayout->applyLogicalAdvancements( rOffsets );
288 double getLineWidth( ::VirtualDevice& rVDev,
289 const OutDevState& rState,
290 const rendering::StringContext& rStringContext )
292 // TODO(F2): use correct scale direction
293 const ::basegfx::B2DSize aSize( rVDev.GetTextWidth( rStringContext.Text,
294 static_cast<USHORT>(rStringContext.StartPosition),
295 static_cast<USHORT>(rStringContext.Length) ),
296 0 );
298 return (rState.mapModeTransform * aSize).getX();
301 uno::Sequence< double >
302 calcSubsetOffsets( rendering::RenderState& io_rRenderState,
303 double& o_rMinPos,
304 double& o_rMaxPos,
305 const uno::Reference< rendering::XTextLayout >& rOrigTextLayout,
306 const ::cppcanvas::internal::Action::Subset& rSubset )
308 ENSURE_OR_THROW( rSubset.mnSubsetEnd > rSubset.mnSubsetBegin,
309 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
311 uno::Sequence< double > aOrigOffsets( rOrigTextLayout->queryLogicalAdvancements() );
312 const double* pOffsets( aOrigOffsets.getConstArray() );
314 ENSURE_OR_THROW( aOrigOffsets.getLength() >= rSubset.mnSubsetEnd,
315 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
317 // TODO(F3): It currently seems that for RTL text, the
318 // DX offsets are nevertheless increasing in logical
319 // text order (I'd expect they are decreasing,
320 // mimicking the fact that the text is output
321 // right-to-left). This breaks text effects for ALL
322 // RTL languages.
324 // determine leftmost position in given subset range -
325 // as the DX array contains the output positions
326 // starting with the second character (the first is
327 // assumed to have output position 0), correct begin
328 // iterator.
329 const double nMinPos( rSubset.mnSubsetBegin <= 0 ? 0 :
330 *(::std::min_element( pOffsets+rSubset.mnSubsetBegin-1,
331 pOffsets+rSubset.mnSubsetEnd )) );
333 // determine rightmost position in given subset range
334 // - as the DX array contains the output positions
335 // starting with the second character (the first is
336 // assumed to have output position 0), correct begin
337 // iterator.
338 const double nMaxPos(
339 *(::std::max_element( pOffsets + (rSubset.mnSubsetBegin <= 0 ?
340 0 : rSubset.mnSubsetBegin-1),
341 pOffsets + rSubset.mnSubsetEnd )) );
344 // adapt render state, to move text output to given offset
345 // -------------------------------------------------------
347 // TODO(F1): Strictly speaking, we also have to adapt
348 // the clip here, which normally should _not_ move
349 // with the output offset. Neglected for now, as it
350 // does not matter for drawing layer output
352 if( rSubset.mnSubsetBegin > 0 )
354 ::basegfx::B2DHomMatrix aTranslation;
355 if( rOrigTextLayout->getFont()->getFontRequest().FontDescription.IsVertical )
357 // vertical text -> offset in y direction
358 aTranslation.translate( 0.0, nMinPos );
360 else
362 // horizontal text -> offset in x direction
363 aTranslation.translate( nMinPos, 0.0 );
366 ::canvas::tools::appendToRenderState( io_rRenderState,
367 aTranslation );
371 // reduce DX array to given substring
372 // ----------------------------------
374 const sal_Int32 nNewElements( rSubset.mnSubsetEnd - rSubset.mnSubsetBegin );
375 uno::Sequence< double > aAdaptedOffsets( nNewElements );
376 double* pAdaptedOffsets( aAdaptedOffsets.getArray() );
378 // move to new output position (subtract nMinPos,
379 // which is the new '0' position), copy only the range
380 // as given by rSubset.
381 ::std::transform( pOffsets + rSubset.mnSubsetBegin,
382 pOffsets + rSubset.mnSubsetEnd,
383 pAdaptedOffsets,
384 ::boost::bind( ::std::minus<double>(),
385 _1,
386 nMinPos ) );
388 o_rMinPos = nMinPos;
389 o_rMaxPos = nMaxPos;
391 return aAdaptedOffsets;
394 uno::Reference< rendering::XTextLayout >
395 createSubsetLayout( const rendering::StringContext& rOrigContext,
396 const ::cppcanvas::internal::Action::Subset& rSubset,
397 const uno::Reference< rendering::XTextLayout >& rOrigTextLayout )
399 // create temporary new text layout with subset string
400 // ---------------------------------------------------
402 const sal_Int32 nNewStartPos( rOrigContext.StartPosition + ::std::min(
403 rSubset.mnSubsetBegin, rOrigContext.Length-1 ) );
404 const sal_Int32 nNewLength( ::std::max(
405 ::std::min(
406 rSubset.mnSubsetEnd - rSubset.mnSubsetBegin,
407 rOrigContext.Length ),
408 sal_Int32( 0 ) ) );
410 const rendering::StringContext aContext( rOrigContext.Text,
411 nNewStartPos,
412 nNewLength );
414 uno::Reference< rendering::XTextLayout > xTextLayout(
415 rOrigTextLayout->getFont()->createTextLayout( aContext,
416 rOrigTextLayout->getMainTextDirection(),
417 0 ),
418 uno::UNO_QUERY_THROW );
420 return xTextLayout;
423 /** Setup subset text layout
425 @param io_rTextLayout
426 Must contain original (full set) text layout on input,
427 will contain subsetted text layout (or empty
428 reference, for empty subsets) on output.
430 @param io_rRenderState
431 Must contain original render state on input, will
432 contain shifted render state concatenated with
433 rTransformation on output.
435 @param rTransformation
436 Additional transformation, to be prepended to render
437 state
439 @param rSubset
440 Subset to prepare
442 void createSubsetLayout( uno::Reference< rendering::XTextLayout >& io_rTextLayout,
443 rendering::RenderState& io_rRenderState,
444 double& o_rMinPos,
445 double& o_rMaxPos,
446 const ::basegfx::B2DHomMatrix& rTransformation,
447 const Action::Subset& rSubset )
449 ::canvas::tools::prependToRenderState(io_rRenderState, rTransformation);
451 if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd )
453 // empty range, empty layout
454 io_rTextLayout.clear();
456 return;
459 ENSURE_OR_THROW( io_rTextLayout.is(),
460 "createSubsetLayout(): Invalid input layout" );
462 const rendering::StringContext& rOrigContext( io_rTextLayout->getText() );
464 if( rSubset.mnSubsetBegin == 0 &&
465 rSubset.mnSubsetEnd == rOrigContext.Length )
467 // full range, no need for subsetting
468 return;
471 uno::Reference< rendering::XTextLayout > xTextLayout(
472 createSubsetLayout( rOrigContext, rSubset, io_rTextLayout ) );
474 if( xTextLayout.is() )
476 xTextLayout->applyLogicalAdvancements(
477 calcSubsetOffsets( io_rRenderState,
478 o_rMinPos,
479 o_rMaxPos,
480 io_rTextLayout,
481 rSubset ) );
484 io_rTextLayout = xTextLayout;
488 /** Interface for renderEffectText functor below.
490 This is interface is used from the renderEffectText()
491 method below, to call the client implementation.
493 class TextRenderer
495 public:
496 virtual ~TextRenderer() {}
498 /// Render text with given RenderState
499 virtual bool operator()( const rendering::RenderState& rRenderState ) const = 0;
502 /** Render effect text.
504 @param rRenderer
505 Functor object, will be called to render the actual
506 part of the text effect (the text itself and the means
507 to render it are unknown to this method)
509 bool renderEffectText( const TextRenderer& rRenderer,
510 const rendering::RenderState& rRenderState,
511 const rendering::ViewState& /*rViewState*/,
512 const uno::Reference< rendering::XCanvas >& xCanvas,
513 const ::Color& rShadowColor,
514 const ::basegfx::B2DSize& rShadowOffset,
515 const ::Color& rReliefColor,
516 const ::basegfx::B2DSize& rReliefOffset )
518 ::Color aEmptyColor( COL_AUTO );
519 uno::Reference<rendering::XColorSpace> xColorSpace(
520 xCanvas->getDevice()->getDeviceColorSpace() );
522 // draw shadow text, if enabled
523 if( rShadowColor != aEmptyColor )
525 rendering::RenderState aShadowState( rRenderState );
526 ::basegfx::B2DHomMatrix aTranslate;
528 aTranslate.translate( rShadowOffset.getX(),
529 rShadowOffset.getY() );
531 ::canvas::tools::appendToRenderState(aShadowState, aTranslate);
533 aShadowState.DeviceColor =
534 ::vcl::unotools::colorToDoubleSequence( rShadowColor,
535 xColorSpace );
537 rRenderer( aShadowState );
540 // draw relief text, if enabled
541 if( rReliefColor != aEmptyColor )
543 rendering::RenderState aReliefState( rRenderState );
544 ::basegfx::B2DHomMatrix aTranslate;
546 aTranslate.translate( rReliefOffset.getX(),
547 rReliefOffset.getY() );
549 ::canvas::tools::appendToRenderState(aReliefState, aTranslate);
551 aReliefState.DeviceColor =
552 ::vcl::unotools::colorToDoubleSequence( rReliefColor,
553 xColorSpace );
555 rRenderer( aReliefState );
558 // draw normal text
559 rRenderer( rRenderState );
561 return true;
565 ::basegfx::B2DRange calcEffectTextBounds( const ::basegfx::B2DRange& rTextBounds,
566 const ::basegfx::B2DRange& rLineBounds,
567 const ::basegfx::B2DSize& rReliefOffset,
568 const ::basegfx::B2DSize& rShadowOffset,
569 const rendering::RenderState& rRenderState,
570 const rendering::ViewState& rViewState )
572 ::basegfx::B2DRange aBounds( rTextBounds );
574 // add extends of text lines
575 aBounds.expand( rLineBounds );
577 // TODO(Q3): Provide this functionality at the B2DRange
578 ::basegfx::B2DRange aTotalBounds( aBounds );
579 aTotalBounds.expand(
580 ::basegfx::B2DRange( aBounds.getMinX() + rReliefOffset.getX(),
581 aBounds.getMinY() + rReliefOffset.getY(),
582 aBounds.getMaxX() + rReliefOffset.getX(),
583 aBounds.getMaxY() + rReliefOffset.getY() ) );
584 aTotalBounds.expand(
585 ::basegfx::B2DRange( aBounds.getMinX() + rShadowOffset.getX(),
586 aBounds.getMinY() + rShadowOffset.getY(),
587 aBounds.getMaxX() + rShadowOffset.getX(),
588 aBounds.getMaxY() + rShadowOffset.getY() ) );
590 return tools::calcDevicePixelBounds( aTotalBounds,
591 rViewState,
592 rRenderState );
595 void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize,
596 uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines,
597 const CanvasSharedPtr& rCanvas,
598 const uno::Sequence< double >& rOffsets,
599 const tools::TextLineInfo rLineInfo )
601 const ::basegfx::B2DPolyPolygon aPoly(
602 textLinesFromLogicalOffsets(
603 rOffsets,
604 rLineInfo ) );
606 o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange();
608 o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
609 rCanvas->getUNOCanvas()->getDevice(),
610 aPoly );
613 void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize,
614 uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines,
615 const CanvasSharedPtr& rCanvas,
616 double nLineWidth,
617 const tools::TextLineInfo rLineInfo )
619 const ::basegfx::B2DPolyPolygon aPoly(
620 tools::createTextLinesPolyPolygon( 0.0, nLineWidth,
621 rLineInfo ) );
623 o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange();
625 o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
626 rCanvas->getUNOCanvas()->getDevice(),
627 aPoly );
631 // -------------------------------------------------------------------------
633 class TextAction : public Action, private ::boost::noncopyable
635 public:
636 TextAction( const ::basegfx::B2DPoint& rStartPoint,
637 const ::rtl::OUString& rString,
638 sal_Int32 nStartPos,
639 sal_Int32 nLen,
640 const CanvasSharedPtr& rCanvas,
641 const OutDevState& rState );
643 TextAction( const ::basegfx::B2DPoint& rStartPoint,
644 const ::rtl::OUString& rString,
645 sal_Int32 nStartPos,
646 sal_Int32 nLen,
647 const CanvasSharedPtr& rCanvas,
648 const OutDevState& rState,
649 const ::basegfx::B2DHomMatrix& rTextTransform );
651 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
652 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation,
653 const Subset& rSubset ) const;
655 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
656 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
657 const Subset& rSubset ) const;
659 virtual sal_Int32 getActionCount() const;
661 private:
662 // TODO(P2): This is potentially a real mass object
663 // (every character might be a separate TextAction),
664 // thus, make it as lightweight as possible. For
665 // example, share common RenderState among several
666 // TextActions, maybe using maOffsets for the
667 // translation.
669 uno::Reference< rendering::XCanvasFont > mxFont;
670 const rendering::StringContext maStringContext;
671 const CanvasSharedPtr mpCanvas;
672 rendering::RenderState maState;
673 const sal_Int8 maTextDirection;
676 TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint,
677 const ::rtl::OUString& rString,
678 sal_Int32 nStartPos,
679 sal_Int32 nLen,
680 const CanvasSharedPtr& rCanvas,
681 const OutDevState& rState ) :
682 mxFont( rState.xFont ),
683 maStringContext( rString, nStartPos, nLen ),
684 mpCanvas( rCanvas ),
685 maState(),
686 maTextDirection( rState.textDirection )
688 init( maState, mxFont,
689 rStartPoint,
690 rState, rCanvas );
692 ENSURE_OR_THROW( mxFont.is(),
693 "::cppcanvas::internal::TextAction(): Invalid font" );
696 TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint,
697 const ::rtl::OUString& rString,
698 sal_Int32 nStartPos,
699 sal_Int32 nLen,
700 const CanvasSharedPtr& rCanvas,
701 const OutDevState& rState,
702 const ::basegfx::B2DHomMatrix& rTextTransform ) :
703 mxFont( rState.xFont ),
704 maStringContext( rString, nStartPos, nLen ),
705 mpCanvas( rCanvas ),
706 maState(),
707 maTextDirection( rState.textDirection )
709 init( maState, mxFont,
710 rStartPoint,
711 rState, rCanvas, rTextTransform );
713 ENSURE_OR_THROW( mxFont.is(),
714 "::cppcanvas::internal::TextAction(): Invalid font" );
717 bool TextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
719 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextAction::render()" );
720 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextAction: 0x%X", this );
722 rendering::RenderState aLocalState( maState );
723 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
725 mpCanvas->getUNOCanvas()->drawText( maStringContext, mxFont,
726 mpCanvas->getViewState(), aLocalState, maTextDirection );
728 return true;
731 bool TextAction::render( const ::basegfx::B2DHomMatrix& rTransformation,
732 const Subset& /*rSubset*/ ) const
734 OSL_ENSURE( false,
735 "TextAction::render(): Subset not supported by this object" );
737 // TODO(P1): Retrieve necessary font metric info for
738 // TextAction from XCanvas. Currently, the
739 // TextActionFactory does not generate this object for
740 // _subsettable_ text
741 return render( rTransformation );
744 ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
746 // create XTextLayout, to have the
747 // XTextLayout::queryTextBounds() method available
748 uno::Reference< rendering::XTextLayout > xTextLayout(
749 mxFont->createTextLayout(
750 maStringContext,
751 maTextDirection,
752 0 ) );
754 rendering::RenderState aLocalState( maState );
755 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
757 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
758 xTextLayout->queryTextBounds() ),
759 mpCanvas->getViewState(),
760 aLocalState );
763 ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
764 const Subset& /*rSubset*/ ) const
766 OSL_ENSURE( false,
767 "TextAction::getBounds(): Subset not supported by this object" );
769 // TODO(P1): Retrieve necessary font metric info for
770 // TextAction from XCanvas. Currently, the
771 // TextActionFactory does not generate this object for
772 // _subsettable_ text
773 return getBounds( rTransformation );
776 sal_Int32 TextAction::getActionCount() const
778 // TODO(P1): Retrieve necessary font metric info for
779 // TextAction from XCanvas. Currently, the
780 // TextActionFactory does not generate this object for
781 // _subsettable_ text
782 return 1;
786 // -------------------------------------------------------------------------
788 class EffectTextAction :
789 public Action,
790 public TextRenderer,
791 private ::boost::noncopyable
793 public:
794 EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
795 const ::basegfx::B2DSize& rReliefOffset,
796 const ::Color& rReliefColor,
797 const ::basegfx::B2DSize& rShadowOffset,
798 const ::Color& rShadowColor,
799 const ::rtl::OUString& rText,
800 sal_Int32 nStartPos,
801 sal_Int32 nLen,
802 VirtualDevice& rVDev,
803 const CanvasSharedPtr& rCanvas,
804 const OutDevState& rState );
806 EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
807 const ::basegfx::B2DSize& rReliefOffset,
808 const ::Color& rReliefColor,
809 const ::basegfx::B2DSize& rShadowOffset,
810 const ::Color& rShadowColor,
811 const ::rtl::OUString& rText,
812 sal_Int32 nStartPos,
813 sal_Int32 nLen,
814 VirtualDevice& rVDev,
815 const CanvasSharedPtr& rCanvas,
816 const OutDevState& rState,
817 const ::basegfx::B2DHomMatrix& rTextTransform );
819 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
820 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation,
821 const Subset& rSubset ) const;
823 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
824 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
825 const Subset& rSubset ) const;
827 virtual sal_Int32 getActionCount() const;
829 private:
830 /// Interface TextRenderer
831 virtual bool operator()( const rendering::RenderState& rRenderState ) const;
833 // TODO(P2): This is potentially a real mass object
834 // (every character might be a separate TextAction),
835 // thus, make it as lightweight as possible. For
836 // example, share common RenderState among several
837 // TextActions, maybe using maOffsets for the
838 // translation.
840 uno::Reference< rendering::XCanvasFont > mxFont;
841 const rendering::StringContext maStringContext;
842 const CanvasSharedPtr mpCanvas;
843 rendering::RenderState maState;
844 const tools::TextLineInfo maTextLineInfo;
845 ::basegfx::B2DSize maLinesOverallSize;
846 const double mnLineWidth;
847 uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
848 const ::basegfx::B2DSize maReliefOffset;
849 const ::Color maReliefColor;
850 const ::basegfx::B2DSize maShadowOffset;
851 const ::Color maShadowColor;
852 const sal_Int8 maTextDirection;
855 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
856 const ::basegfx::B2DSize& rReliefOffset,
857 const ::Color& rReliefColor,
858 const ::basegfx::B2DSize& rShadowOffset,
859 const ::Color& rShadowColor,
860 const ::rtl::OUString& rText,
861 sal_Int32 nStartPos,
862 sal_Int32 nLen,
863 VirtualDevice& rVDev,
864 const CanvasSharedPtr& rCanvas,
865 const OutDevState& rState ) :
866 mxFont( rState.xFont ),
867 maStringContext( rText, nStartPos, nLen ),
868 mpCanvas( rCanvas ),
869 maState(),
870 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
871 maLinesOverallSize(),
872 mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ),
873 mxTextLines(),
874 maReliefOffset( rReliefOffset ),
875 maReliefColor( rReliefColor ),
876 maShadowOffset( rShadowOffset ),
877 maShadowColor( rShadowColor ),
878 maTextDirection( rState.textDirection )
880 initEffectLinePolyPolygon( maLinesOverallSize,
881 mxTextLines,
882 rCanvas,
883 mnLineWidth,
884 maTextLineInfo );
886 init( maState, mxFont,
887 rStartPoint,
888 rState, rCanvas );
890 ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(),
891 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
894 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
895 const ::basegfx::B2DSize& rReliefOffset,
896 const ::Color& rReliefColor,
897 const ::basegfx::B2DSize& rShadowOffset,
898 const ::Color& rShadowColor,
899 const ::rtl::OUString& rText,
900 sal_Int32 nStartPos,
901 sal_Int32 nLen,
902 VirtualDevice& rVDev,
903 const CanvasSharedPtr& rCanvas,
904 const OutDevState& rState,
905 const ::basegfx::B2DHomMatrix& rTextTransform ) :
906 mxFont( rState.xFont ),
907 maStringContext( rText, nStartPos, nLen ),
908 mpCanvas( rCanvas ),
909 maState(),
910 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
911 maLinesOverallSize(),
912 mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ),
913 mxTextLines(),
914 maReliefOffset( rReliefOffset ),
915 maReliefColor( rReliefColor ),
916 maShadowOffset( rShadowOffset ),
917 maShadowColor( rShadowColor ),
918 maTextDirection( rState.textDirection )
920 initEffectLinePolyPolygon( maLinesOverallSize,
921 mxTextLines,
922 rCanvas,
923 mnLineWidth,
924 maTextLineInfo );
926 init( maState, mxFont,
927 rStartPoint,
928 rState, rCanvas, rTextTransform );
930 ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(),
931 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
934 bool EffectTextAction::operator()( const rendering::RenderState& rRenderState ) const
936 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
937 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
939 rCanvas->fillPolyPolygon( mxTextLines,
940 rViewState,
941 rRenderState );
943 rCanvas->drawText( maStringContext, mxFont,
944 rViewState,
945 rRenderState,
946 maTextDirection );
948 return true;
951 bool EffectTextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
953 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextAction::render()" );
954 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextAction: 0x%X", this );
956 rendering::RenderState aLocalState( maState );
957 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
959 return renderEffectText( *this,
960 aLocalState,
961 mpCanvas->getViewState(),
962 mpCanvas->getUNOCanvas(),
963 maShadowColor,
964 maShadowOffset,
965 maReliefColor,
966 maReliefOffset );
969 bool EffectTextAction::render( const ::basegfx::B2DHomMatrix& rTransformation,
970 const Subset& /*rSubset*/ ) const
972 OSL_ENSURE( false,
973 "EffectTextAction::render(): Subset not supported by this object" );
975 // TODO(P1): Retrieve necessary font metric info for
976 // TextAction from XCanvas. Currently, the
977 // TextActionFactory does not generate this object for
978 // subsettable text
979 return render( rTransformation );
982 ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
984 // create XTextLayout, to have the
985 // XTextLayout::queryTextBounds() method available
986 uno::Reference< rendering::XTextLayout > xTextLayout(
987 mxFont->createTextLayout(
988 maStringContext,
989 maTextDirection,
990 0 ) );
992 rendering::RenderState aLocalState( maState );
993 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
995 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
996 xTextLayout->queryTextBounds() ),
997 ::basegfx::B2DRange( 0,0,
998 maLinesOverallSize.getX(),
999 maLinesOverallSize.getY() ),
1000 maReliefOffset,
1001 maShadowOffset,
1002 aLocalState,
1003 mpCanvas->getViewState() );
1006 ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1007 const Subset& /*rSubset*/ ) const
1009 OSL_ENSURE( false,
1010 "EffectTextAction::getBounds(): Subset not supported by this object" );
1012 // TODO(P1): Retrieve necessary font metric info for
1013 // TextAction from XCanvas. Currently, the
1014 // TextActionFactory does not generate this object for
1015 // _subsettable_ text
1016 return getBounds( rTransformation );
1019 sal_Int32 EffectTextAction::getActionCount() const
1021 // TODO(P1): Retrieve necessary font metric info for
1022 // TextAction from XCanvas. Currently, the
1023 // TextActionFactory does not generate this object for
1024 // subsettable text
1025 return 1;
1029 // -------------------------------------------------------------------------
1031 class TextArrayAction : public Action, private ::boost::noncopyable
1033 public:
1034 TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1035 const ::rtl::OUString& rString,
1036 sal_Int32 nStartPos,
1037 sal_Int32 nLen,
1038 const uno::Sequence< double >& rOffsets,
1039 const CanvasSharedPtr& rCanvas,
1040 const OutDevState& rState );
1042 TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1043 const ::rtl::OUString& rString,
1044 sal_Int32 nStartPos,
1045 sal_Int32 nLen,
1046 const uno::Sequence< double >& rOffsets,
1047 const CanvasSharedPtr& rCanvas,
1048 const OutDevState& rState,
1049 const ::basegfx::B2DHomMatrix& rTextTransform );
1051 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1052 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation,
1053 const Subset& rSubset ) const;
1055 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1056 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1057 const Subset& rSubset ) const;
1059 virtual sal_Int32 getActionCount() const;
1061 private:
1062 // TODO(P2): This is potentially a real mass object
1063 // (every character might be a separate TextAction),
1064 // thus, make it as lightweight as possible. For
1065 // example, share common RenderState among several
1066 // TextActions, maybe using maOffsets for the
1067 // translation.
1069 uno::Reference< rendering::XTextLayout > mxTextLayout;
1070 const CanvasSharedPtr mpCanvas;
1071 rendering::RenderState maState;
1074 TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1075 const ::rtl::OUString& rString,
1076 sal_Int32 nStartPos,
1077 sal_Int32 nLen,
1078 const uno::Sequence< double >& rOffsets,
1079 const CanvasSharedPtr& rCanvas,
1080 const OutDevState& rState ) :
1081 mxTextLayout(),
1082 mpCanvas( rCanvas ),
1083 maState()
1085 initArrayAction( maState,
1086 mxTextLayout,
1087 rStartPoint,
1088 rString,
1089 nStartPos,
1090 nLen,
1091 rOffsets,
1092 rCanvas,
1093 rState, NULL );
1096 TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1097 const ::rtl::OUString& rString,
1098 sal_Int32 nStartPos,
1099 sal_Int32 nLen,
1100 const uno::Sequence< double >& rOffsets,
1101 const CanvasSharedPtr& rCanvas,
1102 const OutDevState& rState,
1103 const ::basegfx::B2DHomMatrix& rTextTransform ) :
1104 mxTextLayout(),
1105 mpCanvas( rCanvas ),
1106 maState()
1108 initArrayAction( maState,
1109 mxTextLayout,
1110 rStartPoint,
1111 rString,
1112 nStartPos,
1113 nLen,
1114 rOffsets,
1115 rCanvas,
1116 rState,
1117 &rTextTransform );
1120 bool TextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1122 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::render()" );
1123 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this );
1125 rendering::RenderState aLocalState( maState );
1126 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1128 #ifdef SPECIAL_DEBUG
1129 aLocalState.Clip.clear();
1130 aLocalState.DeviceColor =
1131 ::vcl::unotools::colorToDoubleSequence( mpCanvas->getUNOCanvas()->getDevice(),
1132 ::Color( 0x80FF0000 ) );
1134 if( maState.Clip.is() )
1135 mpCanvas->getUNOCanvas()->drawPolyPolygon( maState.Clip,
1136 mpCanvas->getViewState(),
1137 aLocalState );
1139 aLocalState.DeviceColor = maState.DeviceColor;
1140 #endif
1142 mpCanvas->getUNOCanvas()->drawTextLayout( mxTextLayout,
1143 mpCanvas->getViewState(),
1144 aLocalState );
1146 return true;
1149 bool TextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation,
1150 const Subset& rSubset ) const
1152 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::render( subset )" );
1153 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this );
1155 rendering::RenderState aLocalState( maState );
1156 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1158 double nDummy0, nDummy1;
1159 createSubsetLayout( xTextLayout,
1160 aLocalState,
1161 nDummy0,
1162 nDummy1,
1163 rTransformation,
1164 rSubset );
1166 if( !xTextLayout.is() )
1167 return true; // empty layout, render nothing
1169 mpCanvas->getUNOCanvas()->drawTextLayout( xTextLayout,
1170 mpCanvas->getViewState(),
1171 aLocalState );
1173 return true;
1176 ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1178 rendering::RenderState aLocalState( maState );
1179 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1181 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1182 mxTextLayout->queryTextBounds() ),
1183 mpCanvas->getViewState(),
1184 aLocalState );
1187 ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1188 const Subset& rSubset ) const
1190 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::getBounds( subset )" );
1191 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this );
1193 rendering::RenderState aLocalState( maState );
1194 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1196 double nDummy0, nDummy1;
1197 createSubsetLayout( xTextLayout,
1198 aLocalState,
1199 nDummy0,
1200 nDummy1,
1201 rTransformation,
1202 rSubset );
1204 if( !xTextLayout.is() )
1205 return ::basegfx::B2DRange(); // empty layout, empty bounds
1207 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1208 xTextLayout->queryTextBounds() ),
1209 mpCanvas->getViewState(),
1210 aLocalState );
1213 sal_Int32 TextArrayAction::getActionCount() const
1215 const rendering::StringContext& rOrigContext( mxTextLayout->getText() );
1217 return rOrigContext.Length;
1221 // -------------------------------------------------------------------------
1223 class EffectTextArrayAction :
1224 public Action,
1225 public TextRenderer,
1226 private ::boost::noncopyable
1228 public:
1229 EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1230 const ::basegfx::B2DSize& rReliefOffset,
1231 const ::Color& rReliefColor,
1232 const ::basegfx::B2DSize& rShadowOffset,
1233 const ::Color& rShadowColor,
1234 const ::rtl::OUString& rText,
1235 sal_Int32 nStartPos,
1236 sal_Int32 nLen,
1237 const uno::Sequence< double >& rOffsets,
1238 VirtualDevice& rVDev,
1239 const CanvasSharedPtr& rCanvas,
1240 const OutDevState& rState );
1241 EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1242 const ::basegfx::B2DSize& rReliefOffset,
1243 const ::Color& rReliefColor,
1244 const ::basegfx::B2DSize& rShadowOffset,
1245 const ::Color& rShadowColor,
1246 const ::rtl::OUString& rText,
1247 sal_Int32 nStartPos,
1248 sal_Int32 nLen,
1249 const uno::Sequence< double >& rOffsets,
1250 VirtualDevice& rVDev,
1251 const CanvasSharedPtr& rCanvas,
1252 const OutDevState& rState,
1253 const ::basegfx::B2DHomMatrix& rTextTransform );
1255 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1256 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation,
1257 const Subset& rSubset ) const;
1259 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1260 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1261 const Subset& rSubset ) const;
1263 virtual sal_Int32 getActionCount() const;
1265 private:
1266 // TextRenderer interface
1267 virtual bool operator()( const rendering::RenderState& rRenderState ) const;
1269 // TODO(P2): This is potentially a real mass object
1270 // (every character might be a separate TextAction),
1271 // thus, make it as lightweight as possible. For
1272 // example, share common RenderState among several
1273 // TextActions, maybe using maOffsets for the
1274 // translation.
1276 uno::Reference< rendering::XTextLayout > mxTextLayout;
1277 const CanvasSharedPtr mpCanvas;
1278 rendering::RenderState maState;
1279 const tools::TextLineInfo maTextLineInfo;
1280 ::basegfx::B2DSize maLinesOverallSize;
1281 uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
1282 const ::basegfx::B2DSize maReliefOffset;
1283 const ::Color maReliefColor;
1284 const ::basegfx::B2DSize maShadowOffset;
1285 const ::Color maShadowColor;
1288 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1289 const ::basegfx::B2DSize& rReliefOffset,
1290 const ::Color& rReliefColor,
1291 const ::basegfx::B2DSize& rShadowOffset,
1292 const ::Color& rShadowColor,
1293 const ::rtl::OUString& rText,
1294 sal_Int32 nStartPos,
1295 sal_Int32 nLen,
1296 const uno::Sequence< double >& rOffsets,
1297 VirtualDevice& rVDev,
1298 const CanvasSharedPtr& rCanvas,
1299 const OutDevState& rState ) :
1300 mxTextLayout(),
1301 mpCanvas( rCanvas ),
1302 maState(),
1303 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1304 maLinesOverallSize(),
1305 mxTextLines(),
1306 maReliefOffset( rReliefOffset ),
1307 maReliefColor( rReliefColor ),
1308 maShadowOffset( rShadowOffset ),
1309 maShadowColor( rShadowColor )
1311 initEffectLinePolyPolygon( maLinesOverallSize,
1312 mxTextLines,
1313 rCanvas,
1314 rOffsets,
1315 maTextLineInfo );
1317 initArrayAction( maState,
1318 mxTextLayout,
1319 rStartPoint,
1320 rText,
1321 nStartPos,
1322 nLen,
1323 rOffsets,
1324 rCanvas,
1325 rState, NULL );
1328 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1329 const ::basegfx::B2DSize& rReliefOffset,
1330 const ::Color& rReliefColor,
1331 const ::basegfx::B2DSize& rShadowOffset,
1332 const ::Color& rShadowColor,
1333 const ::rtl::OUString& rText,
1334 sal_Int32 nStartPos,
1335 sal_Int32 nLen,
1336 const uno::Sequence< double >& rOffsets,
1337 VirtualDevice& rVDev,
1338 const CanvasSharedPtr& rCanvas,
1339 const OutDevState& rState,
1340 const ::basegfx::B2DHomMatrix& rTextTransform ) :
1341 mxTextLayout(),
1342 mpCanvas( rCanvas ),
1343 maState(),
1344 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1345 maLinesOverallSize(),
1346 mxTextLines(),
1347 maReliefOffset( rReliefOffset ),
1348 maReliefColor( rReliefColor ),
1349 maShadowOffset( rShadowOffset ),
1350 maShadowColor( rShadowColor )
1352 initEffectLinePolyPolygon( maLinesOverallSize,
1353 mxTextLines,
1354 rCanvas,
1355 rOffsets,
1356 maTextLineInfo );
1358 initArrayAction( maState,
1359 mxTextLayout,
1360 rStartPoint,
1361 rText,
1362 nStartPos,
1363 nLen,
1364 rOffsets,
1365 rCanvas,
1366 rState,
1367 &rTextTransform );
1370 bool EffectTextArrayAction::operator()( const rendering::RenderState& rRenderState ) const
1372 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1373 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
1375 rCanvas->fillPolyPolygon( mxTextLines,
1376 rViewState,
1377 rRenderState );
1379 rCanvas->drawTextLayout( mxTextLayout,
1380 rViewState,
1381 rRenderState );
1383 return true;
1386 bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1388 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::render()" );
1389 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this );
1391 rendering::RenderState aLocalState( maState );
1392 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1394 return renderEffectText( *this,
1395 aLocalState,
1396 mpCanvas->getViewState(),
1397 mpCanvas->getUNOCanvas(),
1398 maShadowColor,
1399 maShadowOffset,
1400 maReliefColor,
1401 maReliefOffset );
1404 class EffectTextArrayRenderHelper : public TextRenderer
1406 public:
1407 EffectTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas,
1408 const uno::Reference< rendering::XTextLayout >& rTextLayout,
1409 const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon,
1410 const rendering::ViewState& rViewState ) :
1411 mrCanvas( rCanvas ),
1412 mrTextLayout( rTextLayout ),
1413 mrLinePolygon( rLinePolygon ),
1414 mrViewState( rViewState )
1418 // TextRenderer interface
1419 virtual bool operator()( const rendering::RenderState& rRenderState ) const
1421 mrCanvas->fillPolyPolygon( mrLinePolygon,
1422 mrViewState,
1423 rRenderState );
1425 mrCanvas->drawTextLayout( mrTextLayout,
1426 mrViewState,
1427 rRenderState );
1429 return true;
1432 private:
1433 const uno::Reference< rendering::XCanvas >& mrCanvas;
1434 const uno::Reference< rendering::XTextLayout >& mrTextLayout;
1435 const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon;
1436 const rendering::ViewState& mrViewState;
1439 bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation,
1440 const Subset& rSubset ) const
1442 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::render( subset )" );
1443 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this );
1445 rendering::RenderState aLocalState( maState );
1446 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1447 const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() );
1449 double nMinPos(0.0);
1450 double nMaxPos(aTextBounds.X2 - aTextBounds.X1);
1452 createSubsetLayout( xTextLayout,
1453 aLocalState,
1454 nMinPos,
1455 nMaxPos,
1456 rTransformation,
1457 rSubset );
1459 if( !xTextLayout.is() )
1460 return true; // empty layout, render nothing
1463 // create and setup local line polygon
1464 // ===================================
1466 uno::Reference< rendering::XCanvas > xCanvas( mpCanvas->getUNOCanvas() );
1467 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1469 uno::Reference< rendering::XPolyPolygon2D > xTextLines(
1470 ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1471 xCanvas->getDevice(),
1472 tools::createTextLinesPolyPolygon(
1473 0.0, nMaxPos - nMinPos,
1474 maTextLineInfo ) ) );
1477 // render everything
1478 // =================
1480 return renderEffectText(
1481 EffectTextArrayRenderHelper( xCanvas,
1482 xTextLayout,
1483 xTextLines,
1484 rViewState ),
1485 aLocalState,
1486 rViewState,
1487 xCanvas,
1488 maShadowColor,
1489 maShadowOffset,
1490 maReliefColor,
1491 maReliefOffset );
1494 ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1496 rendering::RenderState aLocalState( maState );
1497 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1499 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1500 mxTextLayout->queryTextBounds() ),
1501 ::basegfx::B2DRange( 0,0,
1502 maLinesOverallSize.getX(),
1503 maLinesOverallSize.getY() ),
1504 maReliefOffset,
1505 maShadowOffset,
1506 aLocalState,
1507 mpCanvas->getViewState() );
1510 ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1511 const Subset& rSubset ) const
1513 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::getBounds( subset )" );
1514 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this );
1516 rendering::RenderState aLocalState( maState );
1517 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1518 const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() );
1520 double nMinPos(0.0);
1521 double nMaxPos(aTextBounds.X2 - aTextBounds.X1);
1523 createSubsetLayout( xTextLayout,
1524 aLocalState,
1525 nMinPos,
1526 nMaxPos,
1527 rTransformation,
1528 rSubset );
1530 if( !xTextLayout.is() )
1531 return ::basegfx::B2DRange(); // empty layout, empty bounds
1534 // create and setup local line polygon
1535 // ===================================
1537 const ::basegfx::B2DPolyPolygon aPoly(
1538 tools::createTextLinesPolyPolygon(
1539 0.0, nMaxPos - nMinPos,
1540 maTextLineInfo ) );
1542 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1543 xTextLayout->queryTextBounds() ),
1544 ::basegfx::tools::getRange( aPoly ),
1545 maReliefOffset,
1546 maShadowOffset,
1547 aLocalState,
1548 mpCanvas->getViewState() );
1551 sal_Int32 EffectTextArrayAction::getActionCount() const
1553 const rendering::StringContext& rOrigContext( mxTextLayout->getText() );
1555 return rOrigContext.Length;
1559 // -------------------------------------------------------------------------
1561 class OutlineAction :
1562 public Action,
1563 public TextRenderer,
1564 private ::boost::noncopyable
1566 public:
1567 OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1568 const ::basegfx::B2DSize& rReliefOffset,
1569 const ::Color& rReliefColor,
1570 const ::basegfx::B2DSize& rShadowOffset,
1571 const ::Color& rShadowColor,
1572 const ::basegfx::B2DRectangle& rOutlineBounds,
1573 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1574 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1575 const uno::Sequence< double >& rOffsets,
1576 VirtualDevice& rVDev,
1577 const CanvasSharedPtr& rCanvas,
1578 const OutDevState& rState );
1579 OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1580 const ::basegfx::B2DSize& rReliefOffset,
1581 const ::Color& rReliefColor,
1582 const ::basegfx::B2DSize& rShadowOffset,
1583 const ::Color& rShadowColor,
1584 const ::basegfx::B2DRectangle& rOutlineBounds,
1585 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1586 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1587 const uno::Sequence< double >& rOffsets,
1588 VirtualDevice& rVDev,
1589 const CanvasSharedPtr& rCanvas,
1590 const OutDevState& rState,
1591 const ::basegfx::B2DHomMatrix& rTextTransform );
1593 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1594 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation,
1595 const Subset& rSubset ) const;
1597 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1598 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1599 const Subset& rSubset ) const;
1601 virtual sal_Int32 getActionCount() const;
1603 private:
1604 // TextRenderer interface
1605 virtual bool operator()( const rendering::RenderState& rRenderState ) const;
1607 // TODO(P2): This is potentially a real mass object
1608 // (every character might be a separate TextAction),
1609 // thus, make it as lightweight as possible. For
1610 // example, share common RenderState among several
1611 // TextActions, maybe using maOffsets for the
1612 // translation.
1614 uno::Reference< rendering::XPolyPolygon2D > mxTextPoly;
1616 /** This vector denotes the index of the start polygon
1617 for the respective glyph sequence.
1619 To get a polygon index range for a given character
1620 index i, take [ maPolygonGlyphMap[i],
1621 maPolygonGlyphMap[i+1] ). Note that this is wrong
1622 for BiDi
1624 const ::std::vector< sal_Int32 > maPolygonGlyphMap;
1625 const uno::Sequence< double > maOffsets;
1626 const CanvasSharedPtr mpCanvas;
1627 rendering::RenderState maState;
1628 double mnOutlineWidth;
1629 const uno::Sequence< double > maFillColor;
1630 const tools::TextLineInfo maTextLineInfo;
1631 ::basegfx::B2DSize maLinesOverallSize;
1632 const ::basegfx::B2DRectangle maOutlineBounds;
1633 uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
1634 const ::basegfx::B2DSize maReliefOffset;
1635 const ::Color maReliefColor;
1636 const ::basegfx::B2DSize maShadowOffset;
1637 const ::Color maShadowColor;
1640 double calcOutlineWidth( const OutDevState& rState,
1641 VirtualDevice& rVDev )
1643 const ::basegfx::B2DSize aFontSize( 0,
1644 rVDev.GetFont().GetHeight() / 64.0 );
1646 const double nOutlineWidth(
1647 (rState.mapModeTransform * aFontSize).getY() );
1649 return nOutlineWidth < 1.0 ? 1.0 : nOutlineWidth;
1652 OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1653 const ::basegfx::B2DSize& rReliefOffset,
1654 const ::Color& rReliefColor,
1655 const ::basegfx::B2DSize& rShadowOffset,
1656 const ::Color& rShadowColor,
1657 const ::basegfx::B2DRectangle& rOutlineBounds,
1658 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1659 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1660 const uno::Sequence< double >& rOffsets,
1661 VirtualDevice& rVDev,
1662 const CanvasSharedPtr& rCanvas,
1663 const OutDevState& rState ) :
1664 mxTextPoly( rTextPoly ),
1665 maPolygonGlyphMap( rPolygonGlyphMap ),
1666 maOffsets( rOffsets ),
1667 mpCanvas( rCanvas ),
1668 maState(),
1669 mnOutlineWidth( calcOutlineWidth(rState,rVDev) ),
1670 maFillColor(
1671 ::vcl::unotools::colorToDoubleSequence(
1672 ::Color( COL_WHITE ),
1673 rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1674 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1675 maLinesOverallSize(),
1676 maOutlineBounds( rOutlineBounds ),
1677 mxTextLines(),
1678 maReliefOffset( rReliefOffset ),
1679 maReliefColor( rReliefColor ),
1680 maShadowOffset( rShadowOffset ),
1681 maShadowColor( rShadowColor )
1683 initEffectLinePolyPolygon( maLinesOverallSize,
1684 mxTextLines,
1685 rCanvas,
1686 rOffsets,
1687 maTextLineInfo );
1689 init( maState,
1690 rStartPoint,
1691 rState,
1692 rCanvas );
1695 OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1696 const ::basegfx::B2DSize& rReliefOffset,
1697 const ::Color& rReliefColor,
1698 const ::basegfx::B2DSize& rShadowOffset,
1699 const ::Color& rShadowColor,
1700 const ::basegfx::B2DRectangle& rOutlineBounds,
1701 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1702 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1703 const uno::Sequence< double >& rOffsets,
1704 VirtualDevice& rVDev,
1705 const CanvasSharedPtr& rCanvas,
1706 const OutDevState& rState,
1707 const ::basegfx::B2DHomMatrix& rTextTransform ) :
1708 mxTextPoly( rTextPoly ),
1709 maPolygonGlyphMap( rPolygonGlyphMap ),
1710 maOffsets( rOffsets ),
1711 mpCanvas( rCanvas ),
1712 maState(),
1713 mnOutlineWidth( calcOutlineWidth(rState,rVDev) ),
1714 maFillColor(
1715 ::vcl::unotools::colorToDoubleSequence(
1716 ::Color( COL_WHITE ),
1717 rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1718 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1719 maLinesOverallSize(),
1720 maOutlineBounds( rOutlineBounds ),
1721 mxTextLines(),
1722 maReliefOffset( rReliefOffset ),
1723 maReliefColor( rReliefColor ),
1724 maShadowOffset( rShadowOffset ),
1725 maShadowColor( rShadowColor )
1727 initEffectLinePolyPolygon( maLinesOverallSize,
1728 mxTextLines,
1729 rCanvas,
1730 rOffsets,
1731 maTextLineInfo );
1733 init( maState,
1734 rStartPoint,
1735 rState,
1736 rCanvas,
1737 rTextTransform );
1740 bool OutlineAction::operator()( const rendering::RenderState& rRenderState ) const
1742 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1743 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
1745 rendering::StrokeAttributes aStrokeAttributes;
1747 aStrokeAttributes.StrokeWidth = mnOutlineWidth;
1748 aStrokeAttributes.MiterLimit = 1.0;
1749 aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
1750 aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
1751 aStrokeAttributes.JoinType = rendering::PathJoinType::MITER;
1753 rendering::RenderState aLocalState( rRenderState );
1754 aLocalState.DeviceColor = maFillColor;
1756 // TODO(P1): implement caching
1758 // background of text
1759 rCanvas->fillPolyPolygon( mxTextPoly,
1760 rViewState,
1761 aLocalState );
1763 // border line of text
1764 rCanvas->strokePolyPolygon( mxTextPoly,
1765 rViewState,
1766 rRenderState,
1767 aStrokeAttributes );
1769 // underlines/strikethrough - background
1770 rCanvas->fillPolyPolygon( mxTextLines,
1771 rViewState,
1772 aLocalState );
1773 // underlines/strikethrough - border
1774 rCanvas->strokePolyPolygon( mxTextLines,
1775 rViewState,
1776 rRenderState,
1777 aStrokeAttributes );
1779 return true;
1782 bool OutlineAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1784 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::render()" );
1785 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this );
1787 rendering::RenderState aLocalState( maState );
1788 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1790 return renderEffectText( *this,
1791 aLocalState,
1792 mpCanvas->getViewState(),
1793 mpCanvas->getUNOCanvas(),
1794 maShadowColor,
1795 maShadowOffset,
1796 maReliefColor,
1797 maReliefOffset );
1800 class OutlineTextArrayRenderHelper : public TextRenderer
1802 public:
1803 OutlineTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas,
1804 const uno::Reference< rendering::XPolyPolygon2D >& rTextPolygon,
1805 const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon,
1806 const rendering::ViewState& rViewState,
1807 double nOutlineWidth ) :
1808 maFillColor(
1809 ::vcl::unotools::colorToDoubleSequence(
1810 ::Color( COL_WHITE ),
1811 rCanvas->getDevice()->getDeviceColorSpace() )),
1812 mnOutlineWidth( nOutlineWidth ),
1813 mrCanvas( rCanvas ),
1814 mrTextPolygon( rTextPolygon ),
1815 mrLinePolygon( rLinePolygon ),
1816 mrViewState( rViewState )
1820 // TextRenderer interface
1821 virtual bool operator()( const rendering::RenderState& rRenderState ) const
1823 rendering::StrokeAttributes aStrokeAttributes;
1825 aStrokeAttributes.StrokeWidth = mnOutlineWidth;
1826 aStrokeAttributes.MiterLimit = 1.0;
1827 aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
1828 aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
1829 aStrokeAttributes.JoinType = rendering::PathJoinType::MITER;
1831 rendering::RenderState aLocalState( rRenderState );
1832 aLocalState.DeviceColor = maFillColor;
1834 // TODO(P1): implement caching
1836 // background of text
1837 mrCanvas->fillPolyPolygon( mrTextPolygon,
1838 mrViewState,
1839 aLocalState );
1841 // border line of text
1842 mrCanvas->strokePolyPolygon( mrTextPolygon,
1843 mrViewState,
1844 rRenderState,
1845 aStrokeAttributes );
1847 // underlines/strikethrough - background
1848 mrCanvas->fillPolyPolygon( mrLinePolygon,
1849 mrViewState,
1850 aLocalState );
1851 // underlines/strikethrough - border
1852 mrCanvas->strokePolyPolygon( mrLinePolygon,
1853 mrViewState,
1854 rRenderState,
1855 aStrokeAttributes );
1857 return true;
1860 private:
1861 const uno::Sequence< double > maFillColor;
1862 double mnOutlineWidth;
1863 const uno::Reference< rendering::XCanvas >& mrCanvas;
1864 const uno::Reference< rendering::XPolyPolygon2D >& mrTextPolygon;
1865 const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon;
1866 const rendering::ViewState& mrViewState;
1869 bool OutlineAction::render( const ::basegfx::B2DHomMatrix& rTransformation,
1870 const Subset& rSubset ) const
1872 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::OutlineAction::render( subset )" );
1873 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::OutlineAction: 0x%X", this );
1875 if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd )
1876 return true; // empty range, render nothing
1878 #if 1
1879 // TODO(F3): Subsetting NYI for outline text!
1880 return render( rTransformation );
1881 #else
1882 const rendering::StringContext rOrigContext( mxTextLayout->getText() );
1884 if( rSubset.mnSubsetBegin == 0 &&
1885 rSubset.mnSubsetEnd == rOrigContext.Length )
1887 // full range, no need for subsetting
1888 return render( rTransformation );
1891 rendering::RenderState aLocalState( maState );
1892 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1895 // create and setup local Text polygon
1896 // ===================================
1898 uno::Reference< rendering::XPolyPolygon2D > xTextPolygon();
1900 // TODO(P3): Provide an API method for that!
1902 if( !xTextLayout.is() )
1903 return false;
1905 // render everything
1906 // =================
1908 return renderEffectText(
1909 OutlineTextArrayRenderHelper(
1910 xCanvas,
1911 mnOutlineWidth,
1912 xTextLayout,
1913 xTextLines,
1914 rViewState ),
1915 aLocalState,
1916 rViewState,
1917 xCanvas,
1918 maShadowColor,
1919 maShadowOffset,
1920 maReliefColor,
1921 maReliefOffset );
1922 #endif
1925 ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1927 rendering::RenderState aLocalState( maState );
1928 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1930 return calcEffectTextBounds( maOutlineBounds,
1931 ::basegfx::B2DRange( 0,0,
1932 maLinesOverallSize.getX(),
1933 maLinesOverallSize.getY() ),
1934 maReliefOffset,
1935 maShadowOffset,
1936 aLocalState,
1937 mpCanvas->getViewState() );
1940 ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1941 const Subset& /*rSubset*/ ) const
1943 OSL_ENSURE( false,
1944 "OutlineAction::getBounds(): Subset not yet supported by this object" );
1946 return getBounds( rTransformation );
1949 sal_Int32 OutlineAction::getActionCount() const
1951 // TODO(F3): Subsetting NYI for outline text!
1952 return maOffsets.getLength();
1956 // ======================================================================
1958 // Action factory methods
1960 // ======================================================================
1962 /** Create an outline action
1964 This method extracts the polygonal outline from the
1965 text, and creates a properly setup OutlineAction from
1968 ActionSharedPtr createOutline( const ::basegfx::B2DPoint& rStartPoint,
1969 const ::basegfx::B2DSize& rReliefOffset,
1970 const ::Color& rReliefColor,
1971 const ::basegfx::B2DSize& rShadowOffset,
1972 const ::Color& rShadowColor,
1973 const String& rText,
1974 sal_Int32 nStartPos,
1975 sal_Int32 nLen,
1976 const sal_Int32* pDXArray,
1977 VirtualDevice& rVDev,
1978 const CanvasSharedPtr& rCanvas,
1979 const OutDevState& rState,
1980 const Renderer::Parameters& rParms )
1982 // operate on raw DX array here (in logical coordinate
1983 // system), to have a higher resolution
1984 // PolyPolygon. That polygon is then converted to
1985 // device coordinate system.
1987 // #i68512# Temporarily switch off font rotation
1988 // (which is already contained in the render state
1989 // transformation matrix - otherwise, glyph polygons
1990 // will be rotated twice)
1991 const ::Font aOrigFont( rVDev.GetFont() );
1992 ::Font aUnrotatedFont( aOrigFont );
1993 aUnrotatedFont.SetOrientation(0);
1994 rVDev.SetFont( aUnrotatedFont );
1996 // TODO(F3): Don't understand parameter semantics of
1997 // GetTextOutlines()
1998 ::basegfx::B2DPolyPolygon aResultingPolyPolygon;
1999 PolyPolyVector aVCLPolyPolyVector;
2000 const bool bHaveOutlines( rVDev.GetTextOutlines( aVCLPolyPolyVector, rText,
2001 static_cast<USHORT>(nStartPos),
2002 static_cast<USHORT>(nStartPos),
2003 static_cast<USHORT>(nLen),
2004 TRUE, 0, pDXArray ) );
2005 rVDev.SetFont(aOrigFont);
2007 if( !bHaveOutlines )
2008 return ActionSharedPtr();
2010 ::std::vector< sal_Int32 > aPolygonGlyphMap;
2012 // first glyph starts at polygon index 0
2013 aPolygonGlyphMap.push_back( 0 );
2015 // remove offsetting from mapmode transformation
2016 // (outline polygons must stay at origin, only need to
2017 // be scaled)
2018 ::basegfx::B2DHomMatrix aMapModeTransform(
2019 rState.mapModeTransform );
2020 aMapModeTransform.set(0,2, 0.0);
2021 aMapModeTransform.set(1,2, 0.0);
2023 PolyPolyVector::const_iterator aIter( aVCLPolyPolyVector.begin() );
2024 const PolyPolyVector::const_iterator aEnd( aVCLPolyPolyVector.end() );
2025 for( ; aIter!= aEnd; ++aIter )
2027 ::basegfx::B2DPolyPolygon aPolyPolygon;
2029 aPolyPolygon = aIter->getB2DPolyPolygon();
2030 aPolyPolygon.transform( aMapModeTransform );
2032 // append result to collecting polypoly
2033 for( sal_uInt32 i=0; i<aPolyPolygon.count(); ++i )
2035 // #i47795# Ensure closed polygons (since
2036 // FreeType returns the glyph outlines
2037 // open)
2038 const ::basegfx::B2DPolygon& rPoly( aPolyPolygon.getB2DPolygon( i ) );
2039 const sal_uInt32 nCount( rPoly.count() );
2040 if( nCount<3 ||
2041 rPoly.isClosed() )
2043 // polygon either degenerate, or
2044 // already closed.
2045 aResultingPolyPolygon.append( rPoly );
2047 else
2049 ::basegfx::B2DPolygon aPoly(rPoly);
2050 aPoly.setClosed(true);
2052 aResultingPolyPolygon.append( aPoly );
2056 // TODO(F3): Depending on the semantics of
2057 // GetTextOutlines(), this here is wrong!
2059 // calc next glyph index
2060 aPolygonGlyphMap.push_back( aResultingPolyPolygon.count() );
2063 const uno::Sequence< double > aCharWidthSeq(
2064 pDXArray ?
2065 setupDXArray( pDXArray, nLen, rState ) :
2066 setupDXArray( rText,
2067 nStartPos,
2068 nLen,
2069 rVDev,
2070 rState ));
2071 const uno::Reference< rendering::XPolyPolygon2D > xTextPoly(
2072 ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
2073 rCanvas->getUNOCanvas()->getDevice(),
2074 aResultingPolyPolygon ) );
2076 if( rParms.maTextTransformation.isValid() )
2078 return ActionSharedPtr(
2079 new OutlineAction(
2080 rStartPoint,
2081 rReliefOffset,
2082 rReliefColor,
2083 rShadowOffset,
2084 rShadowColor,
2085 ::basegfx::tools::getRange(aResultingPolyPolygon),
2086 xTextPoly,
2087 aPolygonGlyphMap,
2088 aCharWidthSeq,
2089 rVDev,
2090 rCanvas,
2091 rState,
2092 rParms.maTextTransformation.getValue() ) );
2094 else
2096 return ActionSharedPtr(
2097 new OutlineAction(
2098 rStartPoint,
2099 rReliefOffset,
2100 rReliefColor,
2101 rShadowOffset,
2102 rShadowColor,
2103 ::basegfx::tools::getRange(aResultingPolyPolygon),
2104 xTextPoly,
2105 aPolygonGlyphMap,
2106 aCharWidthSeq,
2107 rVDev,
2108 rCanvas,
2109 rState ) );
2113 } // namespace
2116 // ---------------------------------------------------------------------------------
2118 ActionSharedPtr TextActionFactory::createTextAction( const ::Point& rStartPoint,
2119 const ::Size& rReliefOffset,
2120 const ::Color& rReliefColor,
2121 const ::Size& rShadowOffset,
2122 const ::Color& rShadowColor,
2123 const String& rText,
2124 sal_Int32 nStartPos,
2125 sal_Int32 nLen,
2126 const sal_Int32* pDXArray,
2127 VirtualDevice& rVDev,
2128 const CanvasSharedPtr& rCanvas,
2129 const OutDevState& rState,
2130 const Renderer::Parameters& rParms,
2131 bool bSubsettable )
2133 const ::Size aBaselineOffset( tools::getBaselineOffset( rState,
2134 rVDev ) );
2135 // #143885# maintain (nearly) full precision positioning,
2136 // by circumventing integer-based OutDev-mapping
2137 const ::basegfx::B2DPoint aStartPoint(
2138 rState.mapModeTransform *
2139 ::basegfx::B2DPoint(rStartPoint.X() + aBaselineOffset.Width(),
2140 rStartPoint.Y() + aBaselineOffset.Height()) );
2142 const ::basegfx::B2DSize aReliefOffset(
2143 rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rReliefOffset ) );
2144 const ::basegfx::B2DSize aShadowOffset(
2145 rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rShadowOffset ) );
2147 if( rState.isTextOutlineModeSet )
2149 return createOutline(
2150 aStartPoint,
2151 aReliefOffset,
2152 rReliefColor,
2153 aShadowOffset,
2154 rShadowColor,
2155 rText,
2156 nStartPos,
2157 nLen,
2158 pDXArray,
2159 rVDev,
2160 rCanvas,
2161 rState,
2162 rParms );
2165 // convert DX array to device coordinate system (and
2166 // create it in the first place, if pDXArray is NULL)
2167 const uno::Sequence< double > aCharWidths(
2168 pDXArray ?
2169 setupDXArray( pDXArray, nLen, rState ) :
2170 setupDXArray( rText,
2171 nStartPos,
2172 nLen,
2173 rVDev,
2174 rState ));
2176 // determine type of text action to create
2177 // =======================================
2179 const ::Color aEmptyColor( COL_AUTO );
2181 // no DX array, and no need to subset - no need to store
2182 // DX array, then.
2183 if( !pDXArray && !bSubsettable )
2185 // effects, or not?
2186 if( !rState.textOverlineStyle &&
2187 !rState.textUnderlineStyle &&
2188 !rState.textStrikeoutStyle &&
2189 rReliefColor == aEmptyColor &&
2190 rShadowColor == aEmptyColor )
2192 // nope
2193 if( rParms.maTextTransformation.isValid() )
2195 return ActionSharedPtr( new TextAction(
2196 aStartPoint,
2197 rText,
2198 nStartPos,
2199 nLen,
2200 rCanvas,
2201 rState,
2202 rParms.maTextTransformation.getValue() ) );
2204 else
2206 return ActionSharedPtr( new TextAction(
2207 aStartPoint,
2208 rText,
2209 nStartPos,
2210 nLen,
2211 rCanvas,
2212 rState ) );
2215 else
2217 // at least one of the effects requested
2218 if( rParms.maTextTransformation.isValid() )
2219 return ActionSharedPtr( new EffectTextAction(
2220 aStartPoint,
2221 aReliefOffset,
2222 rReliefColor,
2223 aShadowOffset,
2224 rShadowColor,
2225 rText,
2226 nStartPos,
2227 nLen,
2228 rVDev,
2229 rCanvas,
2230 rState,
2231 rParms.maTextTransformation.getValue() ) );
2232 else
2233 return ActionSharedPtr( new EffectTextAction(
2234 aStartPoint,
2235 aReliefOffset,
2236 rReliefColor,
2237 aShadowOffset,
2238 rShadowColor,
2239 rText,
2240 nStartPos,
2241 nLen,
2242 rVDev,
2243 rCanvas,
2244 rState ) );
2247 else
2249 // DX array necessary - any effects?
2250 if( !rState.textOverlineStyle &&
2251 !rState.textUnderlineStyle &&
2252 !rState.textStrikeoutStyle &&
2253 rReliefColor == aEmptyColor &&
2254 rShadowColor == aEmptyColor )
2256 // nope
2257 if( rParms.maTextTransformation.isValid() )
2258 return ActionSharedPtr( new TextArrayAction(
2259 aStartPoint,
2260 rText,
2261 nStartPos,
2262 nLen,
2263 aCharWidths,
2264 rCanvas,
2265 rState,
2266 rParms.maTextTransformation.getValue() ) );
2267 else
2268 return ActionSharedPtr( new TextArrayAction(
2269 aStartPoint,
2270 rText,
2271 nStartPos,
2272 nLen,
2273 aCharWidths,
2274 rCanvas,
2275 rState ) );
2277 else
2279 // at least one of the effects requested
2280 if( rParms.maTextTransformation.isValid() )
2281 return ActionSharedPtr( new EffectTextArrayAction(
2282 aStartPoint,
2283 aReliefOffset,
2284 rReliefColor,
2285 aShadowOffset,
2286 rShadowColor,
2287 rText,
2288 nStartPos,
2289 nLen,
2290 aCharWidths,
2291 rVDev,
2292 rCanvas,
2293 rState,
2294 rParms.maTextTransformation.getValue() ) );
2295 else
2296 return ActionSharedPtr( new EffectTextArrayAction(
2297 aStartPoint,
2298 aReliefOffset,
2299 rReliefColor,
2300 aShadowOffset,
2301 rShadowColor,
2302 rText,
2303 nStartPos,
2304 nLen,
2305 aCharWidths,
2306 rVDev,
2307 rCanvas,
2308 rState ) );
2311 #if defined __GNUC__
2312 #if __GNUC__ == 4 && __GNUC_MINOR__ >= 1
2313 // Unreachable; to avoid bogus warning:
2314 return ActionSharedPtr();
2315 #endif
2316 #endif