Bump for 3.6-28
[LibreOffice.git] / cppcanvas / source / mtfrenderer / textaction.cxx
blob13b283760522fd8220a60269c2df3274a0d49315
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <canvas/debug.hxx>
31 #include <tools/diagnose_ex.h>
32 #include <canvas/verbosetrace.hxx>
34 #include <rtl/logfile.hxx>
36 #include <com/sun/star/rendering/PathCapType.hpp>
37 #include <com/sun/star/rendering/PathJoinType.hpp>
38 #include <com/sun/star/rendering/XCanvas.hpp>
39 #include <com/sun/star/rendering/XCanvasFont.hpp>
41 #include <basegfx/numeric/ftools.hxx>
42 #include <basegfx/matrix/b2dhommatrix.hxx>
43 #include <basegfx/range/b2drectangle.hxx>
44 #include <basegfx/vector/b2dsize.hxx>
45 #include <basegfx/polygon/b2dpolypolygontools.hxx>
46 #include <basegfx/polygon/b2dpolygontools.hxx>
47 #include <basegfx/matrix/b2dhommatrixtools.hxx>
49 #include <tools/gen.hxx>
50 #include <vcl/canvastools.hxx>
51 #include <vcl/virdev.hxx>
53 #include <basegfx/tools/canvastools.hxx>
54 #include <canvas/canvastools.hxx>
56 #include <boost/scoped_array.hpp>
57 #include <boost/bind.hpp>
58 #include <boost/utility.hpp>
60 #include "textaction.hxx"
61 #include "outdevstate.hxx"
62 #include "mtftools.hxx"
65 using namespace ::com::sun::star;
67 namespace cppcanvas
69 namespace internal
71 namespace
73 void init( rendering::RenderState& o_rRenderState,
74 const ::basegfx::B2DPoint& rStartPoint,
75 const OutDevState& rState,
76 const CanvasSharedPtr& rCanvas )
78 tools::initRenderState(o_rRenderState,rState);
80 // #i36950# Offset clip back to origin (as it's also moved
81 // by rStartPoint)
82 // #i53964# Also take VCL font rotation into account,
83 // since this, opposed to the FontMatrix rotation
84 // elsewhere, _does_ get incorporated into the render
85 // state transform.
86 tools::modifyClip( o_rRenderState,
87 rState,
88 rCanvas,
89 rStartPoint,
90 NULL,
91 &rState.fontRotation );
93 basegfx::B2DHomMatrix aLocalTransformation(basegfx::tools::createRotateB2DHomMatrix(rState.fontRotation));
94 aLocalTransformation.translate( rStartPoint.getX(),
95 rStartPoint.getY() );
96 ::canvas::tools::appendToRenderState( o_rRenderState,
97 aLocalTransformation );
99 o_rRenderState.DeviceColor = rState.textColor;
102 void init( rendering::RenderState& o_rRenderState,
103 const ::basegfx::B2DPoint& rStartPoint,
104 const OutDevState& rState,
105 const CanvasSharedPtr& rCanvas,
106 const ::basegfx::B2DHomMatrix& rTextTransform )
108 init( o_rRenderState, rStartPoint, rState, rCanvas );
110 // TODO(F2): Also inversely-transform clip with
111 // rTextTransform (which is actually rather hard, as the
112 // text transform is _prepended_ to the render state)!
114 // prepend extra font transform to render state
115 // (prepend it, because it's interpreted in the unit
116 // rect coordinate space)
117 ::canvas::tools::prependToRenderState( o_rRenderState,
118 rTextTransform );
121 void init( rendering::RenderState& o_rRenderState,
122 uno::Reference< rendering::XCanvasFont >& o_rFont,
123 const ::basegfx::B2DPoint& rStartPoint,
124 const OutDevState& rState,
125 const CanvasSharedPtr& rCanvas )
127 // ensure that o_rFont is valid. It is possible that
128 // text actions are generated without previously
129 // setting a font. Then, just take a default font
130 if( !o_rFont.is() )
132 // Use completely default FontRequest
133 const rendering::FontRequest aFontRequest;
135 geometry::Matrix2D aFontMatrix;
136 ::canvas::tools::setIdentityMatrix2D( aFontMatrix );
138 o_rFont = rCanvas->getUNOCanvas()->createFont(
139 aFontRequest,
140 uno::Sequence< beans::PropertyValue >(),
141 aFontMatrix );
144 init( o_rRenderState,
145 rStartPoint,
146 rState,
147 rCanvas );
150 void init( rendering::RenderState& o_rRenderState,
151 uno::Reference< rendering::XCanvasFont >& o_rFont,
152 const ::basegfx::B2DPoint& rStartPoint,
153 const OutDevState& rState,
154 const CanvasSharedPtr& rCanvas,
155 const ::basegfx::B2DHomMatrix& rTextTransform )
157 init( o_rRenderState, o_rFont, rStartPoint, rState, rCanvas );
159 // TODO(F2): Also inversely-transform clip with
160 // rTextTransform (which is actually rather hard, as the
161 // text transform is _prepended_ to the render state)!
163 // prepend extra font transform to render state
164 // (prepend it, because it's interpreted in the unit
165 // rect coordinate space)
166 ::canvas::tools::prependToRenderState( o_rRenderState,
167 rTextTransform );
170 ::basegfx::B2DPolyPolygon textLinesFromLogicalOffsets( const uno::Sequence< double >& rOffsets,
171 const tools::TextLineInfo& rTextLineInfo )
173 return tools::createTextLinesPolyPolygon(
174 0.0,
175 // extract character cell furthest to the right
176 *(::std::max_element(
177 rOffsets.getConstArray(),
178 rOffsets.getConstArray() + rOffsets.getLength() )),
179 rTextLineInfo );
182 uno::Sequence< double > setupDXArray( const sal_Int32* pCharWidths,
183 sal_Int32 nLen,
184 const OutDevState& rState )
186 // convert character widths from logical units
187 uno::Sequence< double > aCharWidthSeq( nLen );
188 double* pOutputWidths( aCharWidthSeq.getArray() );
190 // #143885# maintain (nearly) full precision of DX
191 // array, by circumventing integer-based
192 // OutDev-mapping
193 const double nScale( rState.mapModeTransform.get(0,0) );
194 for( int i = 0; i < nLen; ++i )
196 // TODO(F2): use correct scale direction
197 *pOutputWidths++ = *pCharWidths++ * nScale;
200 return aCharWidthSeq;
203 uno::Sequence< double > setupDXArray( const ::String& rText,
204 sal_Int32 nStartPos,
205 sal_Int32 nLen,
206 VirtualDevice& rVDev,
207 const OutDevState& rState )
209 // no external DX array given, create one from given
210 // string
211 ::boost::scoped_array< sal_Int32 > pCharWidths( new sal_Int32[nLen] );
213 rVDev.GetTextArray( rText, pCharWidths.get(),
214 static_cast<sal_uInt16>(nStartPos),
215 static_cast<sal_uInt16>(nLen) );
217 return setupDXArray( pCharWidths.get(), nLen, rState );
220 ::basegfx::B2DPoint adaptStartPoint( const ::basegfx::B2DPoint& rStartPoint,
221 const OutDevState& rState,
222 const uno::Sequence< double >& rOffsets )
224 ::basegfx::B2DPoint aLocalPoint( rStartPoint );
226 if( rState.textAlignment )
228 // text origin is right, not left. Modify start point
229 // accordingly, because XCanvas::drawTextLayout()
230 // always aligns left!
232 const double nOffset( rOffsets[ rOffsets.getLength()-1 ] );
234 // correct start point for rotated text: rotate around
235 // former start point
236 aLocalPoint.setX( aLocalPoint.getX() + cos( rState.fontRotation )*nOffset );
237 aLocalPoint.setY( aLocalPoint.getY() + sin( rState.fontRotation )*nOffset );
240 return aLocalPoint;
243 /** Perform common setup for array text actions
245 This method creates the XTextLayout object and
246 initializes it, e.g. with the logical advancements.
248 void initArrayAction( rendering::RenderState& o_rRenderState,
249 uno::Reference< rendering::XTextLayout >& o_rTextLayout,
250 const ::basegfx::B2DPoint& rStartPoint,
251 const ::rtl::OUString& rText,
252 sal_Int32 nStartPos,
253 sal_Int32 nLen,
254 const uno::Sequence< double >& rOffsets,
255 const CanvasSharedPtr& rCanvas,
256 const OutDevState& rState,
257 const ::basegfx::B2DHomMatrix* pTextTransform )
259 ENSURE_OR_THROW( rOffsets.getLength(),
260 "::cppcanvas::internal::initArrayAction(): zero-length DX array" );
262 const ::basegfx::B2DPoint aLocalStartPoint(
263 adaptStartPoint( rStartPoint, rState, rOffsets ) );
265 uno::Reference< rendering::XCanvasFont > xFont( rState.xFont );
267 if( pTextTransform )
268 init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas, *pTextTransform );
269 else
270 init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas );
272 o_rTextLayout = xFont->createTextLayout(
273 rendering::StringContext( rText, nStartPos, nLen ),
274 rState.textDirection,
275 0 );
277 ENSURE_OR_THROW( o_rTextLayout.is(),
278 "::cppcanvas::internal::initArrayAction(): Invalid font" );
280 o_rTextLayout->applyLogicalAdvancements( rOffsets );
283 double getLineWidth( ::VirtualDevice& rVDev,
284 const OutDevState& rState,
285 const rendering::StringContext& rStringContext )
287 // TODO(F2): use correct scale direction
288 const ::basegfx::B2DSize aSize( rVDev.GetTextWidth( rStringContext.Text,
289 static_cast<sal_uInt16>(rStringContext.StartPosition),
290 static_cast<sal_uInt16>(rStringContext.Length) ),
291 0 );
293 return (rState.mapModeTransform * aSize).getX();
296 uno::Sequence< double >
297 calcSubsetOffsets( rendering::RenderState& io_rRenderState,
298 double& o_rMinPos,
299 double& o_rMaxPos,
300 const uno::Reference< rendering::XTextLayout >& rOrigTextLayout,
301 const ::cppcanvas::internal::Action::Subset& rSubset )
303 ENSURE_OR_THROW( rSubset.mnSubsetEnd > rSubset.mnSubsetBegin,
304 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
306 uno::Sequence< double > aOrigOffsets( rOrigTextLayout->queryLogicalAdvancements() );
307 const double* pOffsets( aOrigOffsets.getConstArray() );
309 ENSURE_OR_THROW( aOrigOffsets.getLength() >= rSubset.mnSubsetEnd,
310 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
312 // TODO(F3): It currently seems that for RTL text, the
313 // DX offsets are nevertheless increasing in logical
314 // text order (I'd expect they are decreasing,
315 // mimicking the fact that the text is output
316 // right-to-left). This breaks text effects for ALL
317 // RTL languages.
319 // determine leftmost position in given subset range -
320 // as the DX array contains the output positions
321 // starting with the second character (the first is
322 // assumed to have output position 0), correct begin
323 // iterator.
324 const double nMinPos( rSubset.mnSubsetBegin <= 0 ? 0 :
325 *(::std::min_element( pOffsets+rSubset.mnSubsetBegin-1,
326 pOffsets+rSubset.mnSubsetEnd )) );
328 // determine rightmost position in given subset range
329 // - as the DX array contains the output positions
330 // starting with the second character (the first is
331 // assumed to have output position 0), correct begin
332 // iterator.
333 const double nMaxPos(
334 *(::std::max_element( pOffsets + (rSubset.mnSubsetBegin <= 0 ?
335 0 : rSubset.mnSubsetBegin-1),
336 pOffsets + rSubset.mnSubsetEnd )) );
339 // adapt render state, to move text output to given offset
340 // -------------------------------------------------------
342 // TODO(F1): Strictly speaking, we also have to adapt
343 // the clip here, which normally should _not_ move
344 // with the output offset. Neglected for now, as it
345 // does not matter for drawing layer output
347 if( rSubset.mnSubsetBegin > 0 )
349 ::basegfx::B2DHomMatrix aTranslation;
350 if( rOrigTextLayout->getFont()->getFontRequest().FontDescription.IsVertical )
352 // vertical text -> offset in y direction
353 aTranslation.translate( 0.0, nMinPos );
355 else
357 // horizontal text -> offset in x direction
358 aTranslation.translate( nMinPos, 0.0 );
361 ::canvas::tools::appendToRenderState( io_rRenderState,
362 aTranslation );
366 // reduce DX array to given substring
367 // ----------------------------------
369 const sal_Int32 nNewElements( rSubset.mnSubsetEnd - rSubset.mnSubsetBegin );
370 uno::Sequence< double > aAdaptedOffsets( nNewElements );
371 double* pAdaptedOffsets( aAdaptedOffsets.getArray() );
373 // move to new output position (subtract nMinPos,
374 // which is the new '0' position), copy only the range
375 // as given by rSubset.
376 ::std::transform( pOffsets + rSubset.mnSubsetBegin,
377 pOffsets + rSubset.mnSubsetEnd,
378 pAdaptedOffsets,
379 ::boost::bind( ::std::minus<double>(),
381 nMinPos ) );
383 o_rMinPos = nMinPos;
384 o_rMaxPos = nMaxPos;
386 return aAdaptedOffsets;
389 uno::Reference< rendering::XTextLayout >
390 createSubsetLayout( const rendering::StringContext& rOrigContext,
391 const ::cppcanvas::internal::Action::Subset& rSubset,
392 const uno::Reference< rendering::XTextLayout >& rOrigTextLayout )
394 // create temporary new text layout with subset string
395 // ---------------------------------------------------
397 const sal_Int32 nNewStartPos( rOrigContext.StartPosition + ::std::min(
398 rSubset.mnSubsetBegin, rOrigContext.Length-1 ) );
399 const sal_Int32 nNewLength( ::std::max(
400 ::std::min(
401 rSubset.mnSubsetEnd - rSubset.mnSubsetBegin,
402 rOrigContext.Length ),
403 sal_Int32( 0 ) ) );
405 const rendering::StringContext aContext( rOrigContext.Text,
406 nNewStartPos,
407 nNewLength );
409 uno::Reference< rendering::XTextLayout > xTextLayout(
410 rOrigTextLayout->getFont()->createTextLayout( aContext,
411 rOrigTextLayout->getMainTextDirection(),
412 0 ),
413 uno::UNO_QUERY_THROW );
415 return xTextLayout;
418 /** Setup subset text layout
420 @param io_rTextLayout
421 Must contain original (full set) text layout on input,
422 will contain subsetted text layout (or empty
423 reference, for empty subsets) on output.
425 @param io_rRenderState
426 Must contain original render state on input, will
427 contain shifted render state concatenated with
428 rTransformation on output.
430 @param rTransformation
431 Additional transformation, to be prepended to render
432 state
434 @param rSubset
435 Subset to prepare
437 void createSubsetLayout( uno::Reference< rendering::XTextLayout >& io_rTextLayout,
438 rendering::RenderState& io_rRenderState,
439 double& o_rMinPos,
440 double& o_rMaxPos,
441 const ::basegfx::B2DHomMatrix& rTransformation,
442 const Action::Subset& rSubset )
444 ::canvas::tools::prependToRenderState(io_rRenderState, rTransformation);
446 if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd )
448 // empty range, empty layout
449 io_rTextLayout.clear();
451 return;
454 ENSURE_OR_THROW( io_rTextLayout.is(),
455 "createSubsetLayout(): Invalid input layout" );
457 const rendering::StringContext& rOrigContext( io_rTextLayout->getText() );
459 if( rSubset.mnSubsetBegin == 0 &&
460 rSubset.mnSubsetEnd == rOrigContext.Length )
462 // full range, no need for subsetting
463 return;
466 uno::Reference< rendering::XTextLayout > xTextLayout(
467 createSubsetLayout( rOrigContext, rSubset, io_rTextLayout ) );
469 if( xTextLayout.is() )
471 xTextLayout->applyLogicalAdvancements(
472 calcSubsetOffsets( io_rRenderState,
473 o_rMinPos,
474 o_rMaxPos,
475 io_rTextLayout,
476 rSubset ) );
479 io_rTextLayout = xTextLayout;
483 /** Interface for renderEffectText functor below.
485 This is interface is used from the renderEffectText()
486 method below, to call the client implementation.
488 class TextRenderer
490 public:
491 virtual ~TextRenderer() {}
493 /// Render text with given RenderState
494 virtual bool operator()( const rendering::RenderState& rRenderState ) const = 0;
497 /** Render effect text.
499 @param rRenderer
500 Functor object, will be called to render the actual
501 part of the text effect (the text itself and the means
502 to render it are unknown to this method)
504 bool renderEffectText( const TextRenderer& rRenderer,
505 const rendering::RenderState& rRenderState,
506 const rendering::ViewState& /*rViewState*/,
507 const uno::Reference< rendering::XCanvas >& xCanvas,
508 const ::Color& rShadowColor,
509 const ::basegfx::B2DSize& rShadowOffset,
510 const ::Color& rReliefColor,
511 const ::basegfx::B2DSize& rReliefOffset )
513 ::Color aEmptyColor( COL_AUTO );
514 uno::Reference<rendering::XColorSpace> xColorSpace(
515 xCanvas->getDevice()->getDeviceColorSpace() );
517 // draw shadow text, if enabled
518 if( rShadowColor != aEmptyColor )
520 rendering::RenderState aShadowState( rRenderState );
521 ::basegfx::B2DHomMatrix aTranslate;
523 aTranslate.translate( rShadowOffset.getX(),
524 rShadowOffset.getY() );
526 ::canvas::tools::appendToRenderState(aShadowState, aTranslate);
528 aShadowState.DeviceColor =
529 ::vcl::unotools::colorToDoubleSequence( rShadowColor,
530 xColorSpace );
532 rRenderer( aShadowState );
535 // draw relief text, if enabled
536 if( rReliefColor != aEmptyColor )
538 rendering::RenderState aReliefState( rRenderState );
539 ::basegfx::B2DHomMatrix aTranslate;
541 aTranslate.translate( rReliefOffset.getX(),
542 rReliefOffset.getY() );
544 ::canvas::tools::appendToRenderState(aReliefState, aTranslate);
546 aReliefState.DeviceColor =
547 ::vcl::unotools::colorToDoubleSequence( rReliefColor,
548 xColorSpace );
550 rRenderer( aReliefState );
553 // draw normal text
554 rRenderer( rRenderState );
556 return true;
560 ::basegfx::B2DRange calcEffectTextBounds( const ::basegfx::B2DRange& rTextBounds,
561 const ::basegfx::B2DRange& rLineBounds,
562 const ::basegfx::B2DSize& rReliefOffset,
563 const ::basegfx::B2DSize& rShadowOffset,
564 const rendering::RenderState& rRenderState,
565 const rendering::ViewState& rViewState )
567 ::basegfx::B2DRange aBounds( rTextBounds );
569 // add extends of text lines
570 aBounds.expand( rLineBounds );
572 // TODO(Q3): Provide this functionality at the B2DRange
573 ::basegfx::B2DRange aTotalBounds( aBounds );
574 aTotalBounds.expand(
575 ::basegfx::B2DRange( aBounds.getMinX() + rReliefOffset.getX(),
576 aBounds.getMinY() + rReliefOffset.getY(),
577 aBounds.getMaxX() + rReliefOffset.getX(),
578 aBounds.getMaxY() + rReliefOffset.getY() ) );
579 aTotalBounds.expand(
580 ::basegfx::B2DRange( aBounds.getMinX() + rShadowOffset.getX(),
581 aBounds.getMinY() + rShadowOffset.getY(),
582 aBounds.getMaxX() + rShadowOffset.getX(),
583 aBounds.getMaxY() + rShadowOffset.getY() ) );
585 return tools::calcDevicePixelBounds( aTotalBounds,
586 rViewState,
587 rRenderState );
590 void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize,
591 uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines,
592 const CanvasSharedPtr& rCanvas,
593 const uno::Sequence< double >& rOffsets,
594 const tools::TextLineInfo rLineInfo )
596 const ::basegfx::B2DPolyPolygon aPoly(
597 textLinesFromLogicalOffsets(
598 rOffsets,
599 rLineInfo ) );
601 o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange();
603 o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
604 rCanvas->getUNOCanvas()->getDevice(),
605 aPoly );
608 void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize,
609 uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines,
610 const CanvasSharedPtr& rCanvas,
611 double nLineWidth,
612 const tools::TextLineInfo rLineInfo )
614 const ::basegfx::B2DPolyPolygon aPoly(
615 tools::createTextLinesPolyPolygon( 0.0, nLineWidth,
616 rLineInfo ) );
618 o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange();
620 o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
621 rCanvas->getUNOCanvas()->getDevice(),
622 aPoly );
626 // -------------------------------------------------------------------------
628 class TextAction : public Action, private ::boost::noncopyable
630 public:
631 TextAction( const ::basegfx::B2DPoint& rStartPoint,
632 const ::rtl::OUString& rString,
633 sal_Int32 nStartPos,
634 sal_Int32 nLen,
635 const CanvasSharedPtr& rCanvas,
636 const OutDevState& rState );
638 TextAction( const ::basegfx::B2DPoint& rStartPoint,
639 const ::rtl::OUString& rString,
640 sal_Int32 nStartPos,
641 sal_Int32 nLen,
642 const CanvasSharedPtr& rCanvas,
643 const OutDevState& rState,
644 const ::basegfx::B2DHomMatrix& rTextTransform );
646 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
647 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
648 const Subset& rSubset ) const;
650 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
651 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
652 const Subset& rSubset ) const;
654 virtual sal_Int32 getActionCount() const;
656 private:
657 // TODO(P2): This is potentially a real mass object
658 // (every character might be a separate TextAction),
659 // thus, make it as lightweight as possible. For
660 // example, share common RenderState among several
661 // TextActions, maybe using maOffsets for the
662 // translation.
664 uno::Reference< rendering::XCanvasFont > mxFont;
665 const rendering::StringContext maStringContext;
666 const CanvasSharedPtr mpCanvas;
667 rendering::RenderState maState;
668 const sal_Int8 maTextDirection;
671 TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint,
672 const ::rtl::OUString& rString,
673 sal_Int32 nStartPos,
674 sal_Int32 nLen,
675 const CanvasSharedPtr& rCanvas,
676 const OutDevState& rState ) :
677 mxFont( rState.xFont ),
678 maStringContext( rString, nStartPos, nLen ),
679 mpCanvas( rCanvas ),
680 maState(),
681 maTextDirection( rState.textDirection )
683 init( maState, mxFont,
684 rStartPoint,
685 rState, rCanvas );
687 ENSURE_OR_THROW( mxFont.is(),
688 "::cppcanvas::internal::TextAction(): Invalid font" );
691 TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint,
692 const ::rtl::OUString& rString,
693 sal_Int32 nStartPos,
694 sal_Int32 nLen,
695 const CanvasSharedPtr& rCanvas,
696 const OutDevState& rState,
697 const ::basegfx::B2DHomMatrix& rTextTransform ) :
698 mxFont( rState.xFont ),
699 maStringContext( rString, nStartPos, nLen ),
700 mpCanvas( rCanvas ),
701 maState(),
702 maTextDirection( rState.textDirection )
704 init( maState, mxFont,
705 rStartPoint,
706 rState, rCanvas, rTextTransform );
708 ENSURE_OR_THROW( mxFont.is(),
709 "::cppcanvas::internal::TextAction(): Invalid font" );
712 bool TextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
714 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextAction::render()" );
715 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextAction: 0x%X", this );
717 rendering::RenderState aLocalState( maState );
718 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
720 mpCanvas->getUNOCanvas()->drawText( maStringContext, mxFont,
721 mpCanvas->getViewState(), aLocalState, maTextDirection );
723 return true;
726 bool TextAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
727 const Subset& /*rSubset*/ ) const
729 OSL_FAIL( "TextAction::renderSubset(): Subset not supported by this object" );
731 // TODO(P1): Retrieve necessary font metric info for
732 // TextAction from XCanvas. Currently, the
733 // TextActionFactory does not generate this object for
734 // _subsettable_ text
735 return render( rTransformation );
738 ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
740 // create XTextLayout, to have the
741 // XTextLayout::queryTextBounds() method available
742 uno::Reference< rendering::XTextLayout > xTextLayout(
743 mxFont->createTextLayout(
744 maStringContext,
745 maTextDirection,
746 0 ) );
748 rendering::RenderState aLocalState( maState );
749 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
751 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
752 xTextLayout->queryTextBounds() ),
753 mpCanvas->getViewState(),
754 aLocalState );
757 ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
758 const Subset& /*rSubset*/ ) const
760 OSL_FAIL( "TextAction::getBounds(): Subset not supported by this object" );
762 // TODO(P1): Retrieve necessary font metric info for
763 // TextAction from XCanvas. Currently, the
764 // TextActionFactory does not generate this object for
765 // _subsettable_ text
766 return getBounds( rTransformation );
769 sal_Int32 TextAction::getActionCount() const
771 // TODO(P1): Retrieve necessary font metric info for
772 // TextAction from XCanvas. Currently, the
773 // TextActionFactory does not generate this object for
774 // _subsettable_ text
775 return 1;
779 // -------------------------------------------------------------------------
781 class EffectTextAction :
782 public Action,
783 public TextRenderer,
784 private ::boost::noncopyable
786 public:
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 ::rtl::OUString& rText,
793 sal_Int32 nStartPos,
794 sal_Int32 nLen,
795 VirtualDevice& rVDev,
796 const CanvasSharedPtr& rCanvas,
797 const OutDevState& rState );
799 EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
800 const ::basegfx::B2DSize& rReliefOffset,
801 const ::Color& rReliefColor,
802 const ::basegfx::B2DSize& rShadowOffset,
803 const ::Color& rShadowColor,
804 const ::rtl::OUString& rText,
805 sal_Int32 nStartPos,
806 sal_Int32 nLen,
807 VirtualDevice& rVDev,
808 const CanvasSharedPtr& rCanvas,
809 const OutDevState& rState,
810 const ::basegfx::B2DHomMatrix& rTextTransform );
812 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
813 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
814 const Subset& rSubset ) const;
816 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
817 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
818 const Subset& rSubset ) const;
820 virtual sal_Int32 getActionCount() const;
822 private:
823 /// Interface TextRenderer
824 virtual bool operator()( const rendering::RenderState& rRenderState ) const;
826 // TODO(P2): This is potentially a real mass object
827 // (every character might be a separate TextAction),
828 // thus, make it as lightweight as possible. For
829 // example, share common RenderState among several
830 // TextActions, maybe using maOffsets for the
831 // translation.
833 uno::Reference< rendering::XCanvasFont > mxFont;
834 const rendering::StringContext maStringContext;
835 const CanvasSharedPtr mpCanvas;
836 rendering::RenderState maState;
837 const tools::TextLineInfo maTextLineInfo;
838 ::basegfx::B2DSize maLinesOverallSize;
839 const double mnLineWidth;
840 uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
841 const ::basegfx::B2DSize maReliefOffset;
842 const ::Color maReliefColor;
843 const ::basegfx::B2DSize maShadowOffset;
844 const ::Color maShadowColor;
845 const sal_Int8 maTextDirection;
848 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
849 const ::basegfx::B2DSize& rReliefOffset,
850 const ::Color& rReliefColor,
851 const ::basegfx::B2DSize& rShadowOffset,
852 const ::Color& rShadowColor,
853 const ::rtl::OUString& rText,
854 sal_Int32 nStartPos,
855 sal_Int32 nLen,
856 VirtualDevice& rVDev,
857 const CanvasSharedPtr& rCanvas,
858 const OutDevState& rState ) :
859 mxFont( rState.xFont ),
860 maStringContext( rText, nStartPos, nLen ),
861 mpCanvas( rCanvas ),
862 maState(),
863 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
864 maLinesOverallSize(),
865 mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ),
866 mxTextLines(),
867 maReliefOffset( rReliefOffset ),
868 maReliefColor( rReliefColor ),
869 maShadowOffset( rShadowOffset ),
870 maShadowColor( rShadowColor ),
871 maTextDirection( rState.textDirection )
873 initEffectLinePolyPolygon( maLinesOverallSize,
874 mxTextLines,
875 rCanvas,
876 mnLineWidth,
877 maTextLineInfo );
879 init( maState, mxFont,
880 rStartPoint,
881 rState, rCanvas );
883 ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(),
884 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
887 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
888 const ::basegfx::B2DSize& rReliefOffset,
889 const ::Color& rReliefColor,
890 const ::basegfx::B2DSize& rShadowOffset,
891 const ::Color& rShadowColor,
892 const ::rtl::OUString& rText,
893 sal_Int32 nStartPos,
894 sal_Int32 nLen,
895 VirtualDevice& rVDev,
896 const CanvasSharedPtr& rCanvas,
897 const OutDevState& rState,
898 const ::basegfx::B2DHomMatrix& rTextTransform ) :
899 mxFont( rState.xFont ),
900 maStringContext( rText, nStartPos, nLen ),
901 mpCanvas( rCanvas ),
902 maState(),
903 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
904 maLinesOverallSize(),
905 mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ),
906 mxTextLines(),
907 maReliefOffset( rReliefOffset ),
908 maReliefColor( rReliefColor ),
909 maShadowOffset( rShadowOffset ),
910 maShadowColor( rShadowColor ),
911 maTextDirection( rState.textDirection )
913 initEffectLinePolyPolygon( maLinesOverallSize,
914 mxTextLines,
915 rCanvas,
916 mnLineWidth,
917 maTextLineInfo );
919 init( maState, mxFont,
920 rStartPoint,
921 rState, rCanvas, rTextTransform );
923 ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(),
924 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
927 bool EffectTextAction::operator()( const rendering::RenderState& rRenderState ) const
929 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
930 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
932 rCanvas->fillPolyPolygon( mxTextLines,
933 rViewState,
934 rRenderState );
936 rCanvas->drawText( maStringContext, mxFont,
937 rViewState,
938 rRenderState,
939 maTextDirection );
941 return true;
944 bool EffectTextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
946 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextAction::render()" );
947 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextAction: 0x%X", this );
949 rendering::RenderState aLocalState( maState );
950 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
952 return renderEffectText( *this,
953 aLocalState,
954 mpCanvas->getViewState(),
955 mpCanvas->getUNOCanvas(),
956 maShadowColor,
957 maShadowOffset,
958 maReliefColor,
959 maReliefOffset );
962 bool EffectTextAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
963 const Subset& /*rSubset*/ ) const
965 OSL_FAIL( "EffectTextAction::renderSubset(): Subset not supported by this object" );
967 // TODO(P1): Retrieve necessary font metric info for
968 // TextAction from XCanvas. Currently, the
969 // TextActionFactory does not generate this object for
970 // subsettable text
971 return render( rTransformation );
974 ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
976 // create XTextLayout, to have the
977 // XTextLayout::queryTextBounds() method available
978 uno::Reference< rendering::XTextLayout > xTextLayout(
979 mxFont->createTextLayout(
980 maStringContext,
981 maTextDirection,
982 0 ) );
984 rendering::RenderState aLocalState( maState );
985 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
987 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
988 xTextLayout->queryTextBounds() ),
989 ::basegfx::B2DRange( 0,0,
990 maLinesOverallSize.getX(),
991 maLinesOverallSize.getY() ),
992 maReliefOffset,
993 maShadowOffset,
994 aLocalState,
995 mpCanvas->getViewState() );
998 ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
999 const Subset& /*rSubset*/ ) const
1001 OSL_FAIL( "EffectTextAction::getBounds(): Subset not supported by this object" );
1003 // TODO(P1): Retrieve necessary font metric info for
1004 // TextAction from XCanvas. Currently, the
1005 // TextActionFactory does not generate this object for
1006 // _subsettable_ text
1007 return getBounds( rTransformation );
1010 sal_Int32 EffectTextAction::getActionCount() const
1012 // TODO(P1): Retrieve necessary font metric info for
1013 // TextAction from XCanvas. Currently, the
1014 // TextActionFactory does not generate this object for
1015 // subsettable text
1016 return 1;
1020 // -------------------------------------------------------------------------
1022 class TextArrayAction : public Action, private ::boost::noncopyable
1024 public:
1025 TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1026 const ::rtl::OUString& rString,
1027 sal_Int32 nStartPos,
1028 sal_Int32 nLen,
1029 const uno::Sequence< double >& rOffsets,
1030 const CanvasSharedPtr& rCanvas,
1031 const OutDevState& rState );
1033 TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1034 const ::rtl::OUString& rString,
1035 sal_Int32 nStartPos,
1036 sal_Int32 nLen,
1037 const uno::Sequence< double >& rOffsets,
1038 const CanvasSharedPtr& rCanvas,
1039 const OutDevState& rState,
1040 const ::basegfx::B2DHomMatrix& rTextTransform );
1042 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1043 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1044 const Subset& rSubset ) const;
1046 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1047 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1048 const Subset& rSubset ) const;
1050 virtual sal_Int32 getActionCount() const;
1052 private:
1053 // TODO(P2): This is potentially a real mass object
1054 // (every character might be a separate TextAction),
1055 // thus, make it as lightweight as possible. For
1056 // example, share common RenderState among several
1057 // TextActions, maybe using maOffsets for the
1058 // translation.
1060 uno::Reference< rendering::XTextLayout > mxTextLayout;
1061 const CanvasSharedPtr mpCanvas;
1062 rendering::RenderState maState;
1065 TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1066 const ::rtl::OUString& rString,
1067 sal_Int32 nStartPos,
1068 sal_Int32 nLen,
1069 const uno::Sequence< double >& rOffsets,
1070 const CanvasSharedPtr& rCanvas,
1071 const OutDevState& rState ) :
1072 mxTextLayout(),
1073 mpCanvas( rCanvas ),
1074 maState()
1076 initArrayAction( maState,
1077 mxTextLayout,
1078 rStartPoint,
1079 rString,
1080 nStartPos,
1081 nLen,
1082 rOffsets,
1083 rCanvas,
1084 rState, NULL );
1087 TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1088 const ::rtl::OUString& rString,
1089 sal_Int32 nStartPos,
1090 sal_Int32 nLen,
1091 const uno::Sequence< double >& rOffsets,
1092 const CanvasSharedPtr& rCanvas,
1093 const OutDevState& rState,
1094 const ::basegfx::B2DHomMatrix& rTextTransform ) :
1095 mxTextLayout(),
1096 mpCanvas( rCanvas ),
1097 maState()
1099 initArrayAction( maState,
1100 mxTextLayout,
1101 rStartPoint,
1102 rString,
1103 nStartPos,
1104 nLen,
1105 rOffsets,
1106 rCanvas,
1107 rState,
1108 &rTextTransform );
1111 bool TextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1113 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::render()" );
1114 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this );
1116 rendering::RenderState aLocalState( maState );
1117 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1119 mpCanvas->getUNOCanvas()->drawTextLayout( mxTextLayout,
1120 mpCanvas->getViewState(),
1121 aLocalState );
1123 return true;
1126 bool TextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1127 const Subset& rSubset ) const
1129 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::renderSubset()" );
1130 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this );
1132 rendering::RenderState aLocalState( maState );
1133 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1135 double nDummy0, nDummy1;
1136 createSubsetLayout( xTextLayout,
1137 aLocalState,
1138 nDummy0,
1139 nDummy1,
1140 rTransformation,
1141 rSubset );
1143 if( !xTextLayout.is() )
1144 return true; // empty layout, render nothing
1146 mpCanvas->getUNOCanvas()->drawTextLayout( xTextLayout,
1147 mpCanvas->getViewState(),
1148 aLocalState );
1150 return true;
1153 ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1155 rendering::RenderState aLocalState( maState );
1156 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1158 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1159 mxTextLayout->queryTextBounds() ),
1160 mpCanvas->getViewState(),
1161 aLocalState );
1164 ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1165 const Subset& rSubset ) const
1167 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::TextArrayAction::getBounds( subset )" );
1168 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::TextArrayAction: 0x%X", this );
1170 rendering::RenderState aLocalState( maState );
1171 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1173 double nDummy0, nDummy1;
1174 createSubsetLayout( xTextLayout,
1175 aLocalState,
1176 nDummy0,
1177 nDummy1,
1178 rTransformation,
1179 rSubset );
1181 if( !xTextLayout.is() )
1182 return ::basegfx::B2DRange(); // empty layout, empty bounds
1184 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1185 xTextLayout->queryTextBounds() ),
1186 mpCanvas->getViewState(),
1187 aLocalState );
1190 sal_Int32 TextArrayAction::getActionCount() const
1192 const rendering::StringContext& rOrigContext( mxTextLayout->getText() );
1194 return rOrigContext.Length;
1198 // -------------------------------------------------------------------------
1200 class EffectTextArrayAction :
1201 public Action,
1202 public TextRenderer,
1203 private ::boost::noncopyable
1205 public:
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 ::rtl::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 EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1219 const ::basegfx::B2DSize& rReliefOffset,
1220 const ::Color& rReliefColor,
1221 const ::basegfx::B2DSize& rShadowOffset,
1222 const ::Color& rShadowColor,
1223 const ::rtl::OUString& rText,
1224 sal_Int32 nStartPos,
1225 sal_Int32 nLen,
1226 const uno::Sequence< double >& rOffsets,
1227 VirtualDevice& rVDev,
1228 const CanvasSharedPtr& rCanvas,
1229 const OutDevState& rState,
1230 const ::basegfx::B2DHomMatrix& rTextTransform );
1232 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1233 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1234 const Subset& rSubset ) const;
1236 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1237 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1238 const Subset& rSubset ) const;
1240 virtual sal_Int32 getActionCount() const;
1242 private:
1243 // TextRenderer interface
1244 virtual bool operator()( const rendering::RenderState& rRenderState ) const;
1246 // TODO(P2): This is potentially a real mass object
1247 // (every character might be a separate TextAction),
1248 // thus, make it as lightweight as possible. For
1249 // example, share common RenderState among several
1250 // TextActions, maybe using maOffsets for the
1251 // translation.
1253 uno::Reference< rendering::XTextLayout > mxTextLayout;
1254 const CanvasSharedPtr mpCanvas;
1255 rendering::RenderState maState;
1256 const tools::TextLineInfo maTextLineInfo;
1257 ::basegfx::B2DSize maLinesOverallSize;
1258 uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
1259 const ::basegfx::B2DSize maReliefOffset;
1260 const ::Color maReliefColor;
1261 const ::basegfx::B2DSize maShadowOffset;
1262 const ::Color maShadowColor;
1265 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1266 const ::basegfx::B2DSize& rReliefOffset,
1267 const ::Color& rReliefColor,
1268 const ::basegfx::B2DSize& rShadowOffset,
1269 const ::Color& rShadowColor,
1270 const ::rtl::OUString& rText,
1271 sal_Int32 nStartPos,
1272 sal_Int32 nLen,
1273 const uno::Sequence< double >& rOffsets,
1274 VirtualDevice& rVDev,
1275 const CanvasSharedPtr& rCanvas,
1276 const OutDevState& rState ) :
1277 mxTextLayout(),
1278 mpCanvas( rCanvas ),
1279 maState(),
1280 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1281 maLinesOverallSize(),
1282 mxTextLines(),
1283 maReliefOffset( rReliefOffset ),
1284 maReliefColor( rReliefColor ),
1285 maShadowOffset( rShadowOffset ),
1286 maShadowColor( rShadowColor )
1288 initEffectLinePolyPolygon( maLinesOverallSize,
1289 mxTextLines,
1290 rCanvas,
1291 rOffsets,
1292 maTextLineInfo );
1294 initArrayAction( maState,
1295 mxTextLayout,
1296 rStartPoint,
1297 rText,
1298 nStartPos,
1299 nLen,
1300 rOffsets,
1301 rCanvas,
1302 rState, NULL );
1305 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1306 const ::basegfx::B2DSize& rReliefOffset,
1307 const ::Color& rReliefColor,
1308 const ::basegfx::B2DSize& rShadowOffset,
1309 const ::Color& rShadowColor,
1310 const ::rtl::OUString& rText,
1311 sal_Int32 nStartPos,
1312 sal_Int32 nLen,
1313 const uno::Sequence< double >& rOffsets,
1314 VirtualDevice& rVDev,
1315 const CanvasSharedPtr& rCanvas,
1316 const OutDevState& rState,
1317 const ::basegfx::B2DHomMatrix& rTextTransform ) :
1318 mxTextLayout(),
1319 mpCanvas( rCanvas ),
1320 maState(),
1321 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1322 maLinesOverallSize(),
1323 mxTextLines(),
1324 maReliefOffset( rReliefOffset ),
1325 maReliefColor( rReliefColor ),
1326 maShadowOffset( rShadowOffset ),
1327 maShadowColor( rShadowColor )
1329 initEffectLinePolyPolygon( maLinesOverallSize,
1330 mxTextLines,
1331 rCanvas,
1332 rOffsets,
1333 maTextLineInfo );
1335 initArrayAction( maState,
1336 mxTextLayout,
1337 rStartPoint,
1338 rText,
1339 nStartPos,
1340 nLen,
1341 rOffsets,
1342 rCanvas,
1343 rState,
1344 &rTextTransform );
1347 bool EffectTextArrayAction::operator()( const rendering::RenderState& rRenderState ) const
1349 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1350 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
1352 rCanvas->fillPolyPolygon( mxTextLines,
1353 rViewState,
1354 rRenderState );
1356 rCanvas->drawTextLayout( mxTextLayout,
1357 rViewState,
1358 rRenderState );
1360 return true;
1363 bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1365 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::render()" );
1366 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this );
1368 rendering::RenderState aLocalState( maState );
1369 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1371 return renderEffectText( *this,
1372 aLocalState,
1373 mpCanvas->getViewState(),
1374 mpCanvas->getUNOCanvas(),
1375 maShadowColor,
1376 maShadowOffset,
1377 maReliefColor,
1378 maReliefOffset );
1381 class EffectTextArrayRenderHelper : public TextRenderer
1383 public:
1384 EffectTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas,
1385 const uno::Reference< rendering::XTextLayout >& rTextLayout,
1386 const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon,
1387 const rendering::ViewState& rViewState ) :
1388 mrCanvas( rCanvas ),
1389 mrTextLayout( rTextLayout ),
1390 mrLinePolygon( rLinePolygon ),
1391 mrViewState( rViewState )
1395 // TextRenderer interface
1396 virtual bool operator()( const rendering::RenderState& rRenderState ) const
1398 mrCanvas->fillPolyPolygon( mrLinePolygon,
1399 mrViewState,
1400 rRenderState );
1402 mrCanvas->drawTextLayout( mrTextLayout,
1403 mrViewState,
1404 rRenderState );
1406 return true;
1409 private:
1410 const uno::Reference< rendering::XCanvas >& mrCanvas;
1411 const uno::Reference< rendering::XTextLayout >& mrTextLayout;
1412 const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon;
1413 const rendering::ViewState& mrViewState;
1416 bool EffectTextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1417 const Subset& rSubset ) const
1419 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::renderSubset()" );
1420 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this );
1422 rendering::RenderState aLocalState( maState );
1423 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1424 const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() );
1426 double nMinPos(0.0);
1427 double nMaxPos(aTextBounds.X2 - aTextBounds.X1);
1429 createSubsetLayout( xTextLayout,
1430 aLocalState,
1431 nMinPos,
1432 nMaxPos,
1433 rTransformation,
1434 rSubset );
1436 if( !xTextLayout.is() )
1437 return true; // empty layout, render nothing
1440 // create and setup local line polygon
1441 // ===================================
1443 uno::Reference< rendering::XCanvas > xCanvas( mpCanvas->getUNOCanvas() );
1444 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1446 uno::Reference< rendering::XPolyPolygon2D > xTextLines(
1447 ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1448 xCanvas->getDevice(),
1449 tools::createTextLinesPolyPolygon(
1450 0.0, nMaxPos - nMinPos,
1451 maTextLineInfo ) ) );
1454 // render everything
1455 // =================
1457 return renderEffectText(
1458 EffectTextArrayRenderHelper( xCanvas,
1459 xTextLayout,
1460 xTextLines,
1461 rViewState ),
1462 aLocalState,
1463 rViewState,
1464 xCanvas,
1465 maShadowColor,
1466 maShadowOffset,
1467 maReliefColor,
1468 maReliefOffset );
1471 ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1473 rendering::RenderState aLocalState( maState );
1474 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1476 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1477 mxTextLayout->queryTextBounds() ),
1478 ::basegfx::B2DRange( 0,0,
1479 maLinesOverallSize.getX(),
1480 maLinesOverallSize.getY() ),
1481 maReliefOffset,
1482 maShadowOffset,
1483 aLocalState,
1484 mpCanvas->getViewState() );
1487 ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1488 const Subset& rSubset ) const
1490 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::getBounds( subset )" );
1491 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this );
1493 rendering::RenderState aLocalState( maState );
1494 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1495 const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() );
1497 double nMinPos(0.0);
1498 double nMaxPos(aTextBounds.X2 - aTextBounds.X1);
1500 createSubsetLayout( xTextLayout,
1501 aLocalState,
1502 nMinPos,
1503 nMaxPos,
1504 rTransformation,
1505 rSubset );
1507 if( !xTextLayout.is() )
1508 return ::basegfx::B2DRange(); // empty layout, empty bounds
1511 // create and setup local line polygon
1512 // ===================================
1514 const ::basegfx::B2DPolyPolygon aPoly(
1515 tools::createTextLinesPolyPolygon(
1516 0.0, nMaxPos - nMinPos,
1517 maTextLineInfo ) );
1519 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1520 xTextLayout->queryTextBounds() ),
1521 ::basegfx::tools::getRange( aPoly ),
1522 maReliefOffset,
1523 maShadowOffset,
1524 aLocalState,
1525 mpCanvas->getViewState() );
1528 sal_Int32 EffectTextArrayAction::getActionCount() const
1530 const rendering::StringContext& rOrigContext( mxTextLayout->getText() );
1532 return rOrigContext.Length;
1536 // -------------------------------------------------------------------------
1538 class OutlineAction :
1539 public Action,
1540 public TextRenderer,
1541 private ::boost::noncopyable
1543 public:
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 OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1557 const ::basegfx::B2DSize& rReliefOffset,
1558 const ::Color& rReliefColor,
1559 const ::basegfx::B2DSize& rShadowOffset,
1560 const ::Color& rShadowColor,
1561 const ::basegfx::B2DRectangle& rOutlineBounds,
1562 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1563 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1564 const uno::Sequence< double >& rOffsets,
1565 VirtualDevice& rVDev,
1566 const CanvasSharedPtr& rCanvas,
1567 const OutDevState& rState,
1568 const ::basegfx::B2DHomMatrix& rTextTransform );
1570 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1571 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1572 const Subset& rSubset ) const;
1574 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1575 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1576 const Subset& rSubset ) const;
1578 virtual sal_Int32 getActionCount() const;
1580 private:
1581 // TextRenderer interface
1582 virtual bool operator()( const rendering::RenderState& rRenderState ) const;
1584 // TODO(P2): This is potentially a real mass object
1585 // (every character might be a separate TextAction),
1586 // thus, make it as lightweight as possible. For
1587 // example, share common RenderState among several
1588 // TextActions, maybe using maOffsets for the
1589 // translation.
1591 uno::Reference< rendering::XPolyPolygon2D > mxTextPoly;
1593 /** This vector denotes the index of the start polygon
1594 for the respective glyph sequence.
1596 To get a polygon index range for a given character
1597 index i, take [ maPolygonGlyphMap[i],
1598 maPolygonGlyphMap[i+1] ). Note that this is wrong
1599 for BiDi
1601 const ::std::vector< sal_Int32 > maPolygonGlyphMap;
1602 const uno::Sequence< double > maOffsets;
1603 const CanvasSharedPtr mpCanvas;
1604 rendering::RenderState maState;
1605 double mnOutlineWidth;
1606 const uno::Sequence< double > maFillColor;
1607 const tools::TextLineInfo maTextLineInfo;
1608 ::basegfx::B2DSize maLinesOverallSize;
1609 const ::basegfx::B2DRectangle maOutlineBounds;
1610 uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
1611 const ::basegfx::B2DSize maReliefOffset;
1612 const ::Color maReliefColor;
1613 const ::basegfx::B2DSize maShadowOffset;
1614 const ::Color maShadowColor;
1617 double calcOutlineWidth( const OutDevState& rState,
1618 VirtualDevice& rVDev )
1620 const ::basegfx::B2DSize aFontSize( 0,
1621 rVDev.GetFont().GetHeight() / 64.0 );
1623 const double nOutlineWidth(
1624 (rState.mapModeTransform * aFontSize).getY() );
1626 return nOutlineWidth < 1.0 ? 1.0 : nOutlineWidth;
1629 OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1630 const ::basegfx::B2DSize& rReliefOffset,
1631 const ::Color& rReliefColor,
1632 const ::basegfx::B2DSize& rShadowOffset,
1633 const ::Color& rShadowColor,
1634 const ::basegfx::B2DRectangle& rOutlineBounds,
1635 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1636 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1637 const uno::Sequence< double >& rOffsets,
1638 VirtualDevice& rVDev,
1639 const CanvasSharedPtr& rCanvas,
1640 const OutDevState& rState ) :
1641 mxTextPoly( rTextPoly ),
1642 maPolygonGlyphMap( rPolygonGlyphMap ),
1643 maOffsets( rOffsets ),
1644 mpCanvas( rCanvas ),
1645 maState(),
1646 mnOutlineWidth( calcOutlineWidth(rState,rVDev) ),
1647 maFillColor(
1648 ::vcl::unotools::colorToDoubleSequence(
1649 ::Color( COL_WHITE ),
1650 rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1651 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1652 maLinesOverallSize(),
1653 maOutlineBounds( rOutlineBounds ),
1654 mxTextLines(),
1655 maReliefOffset( rReliefOffset ),
1656 maReliefColor( rReliefColor ),
1657 maShadowOffset( rShadowOffset ),
1658 maShadowColor( rShadowColor )
1660 initEffectLinePolyPolygon( maLinesOverallSize,
1661 mxTextLines,
1662 rCanvas,
1663 rOffsets,
1664 maTextLineInfo );
1666 init( maState,
1667 rStartPoint,
1668 rState,
1669 rCanvas );
1672 OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1673 const ::basegfx::B2DSize& rReliefOffset,
1674 const ::Color& rReliefColor,
1675 const ::basegfx::B2DSize& rShadowOffset,
1676 const ::Color& rShadowColor,
1677 const ::basegfx::B2DRectangle& rOutlineBounds,
1678 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1679 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1680 const uno::Sequence< double >& rOffsets,
1681 VirtualDevice& rVDev,
1682 const CanvasSharedPtr& rCanvas,
1683 const OutDevState& rState,
1684 const ::basegfx::B2DHomMatrix& rTextTransform ) :
1685 mxTextPoly( rTextPoly ),
1686 maPolygonGlyphMap( rPolygonGlyphMap ),
1687 maOffsets( rOffsets ),
1688 mpCanvas( rCanvas ),
1689 maState(),
1690 mnOutlineWidth( calcOutlineWidth(rState,rVDev) ),
1691 maFillColor(
1692 ::vcl::unotools::colorToDoubleSequence(
1693 ::Color( COL_WHITE ),
1694 rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1695 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1696 maLinesOverallSize(),
1697 maOutlineBounds( rOutlineBounds ),
1698 mxTextLines(),
1699 maReliefOffset( rReliefOffset ),
1700 maReliefColor( rReliefColor ),
1701 maShadowOffset( rShadowOffset ),
1702 maShadowColor( rShadowColor )
1704 initEffectLinePolyPolygon( maLinesOverallSize,
1705 mxTextLines,
1706 rCanvas,
1707 rOffsets,
1708 maTextLineInfo );
1710 init( maState,
1711 rStartPoint,
1712 rState,
1713 rCanvas,
1714 rTextTransform );
1717 bool OutlineAction::operator()( const rendering::RenderState& rRenderState ) const
1719 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1720 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
1722 rendering::StrokeAttributes aStrokeAttributes;
1724 aStrokeAttributes.StrokeWidth = mnOutlineWidth;
1725 aStrokeAttributes.MiterLimit = 1.0;
1726 aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
1727 aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
1728 aStrokeAttributes.JoinType = rendering::PathJoinType::MITER;
1730 rendering::RenderState aLocalState( rRenderState );
1731 aLocalState.DeviceColor = maFillColor;
1733 // TODO(P1): implement caching
1735 // background of text
1736 rCanvas->fillPolyPolygon( mxTextPoly,
1737 rViewState,
1738 aLocalState );
1740 // border line of text
1741 rCanvas->strokePolyPolygon( mxTextPoly,
1742 rViewState,
1743 rRenderState,
1744 aStrokeAttributes );
1746 // underlines/strikethrough - background
1747 rCanvas->fillPolyPolygon( mxTextLines,
1748 rViewState,
1749 aLocalState );
1750 // underlines/strikethrough - border
1751 rCanvas->strokePolyPolygon( mxTextLines,
1752 rViewState,
1753 rRenderState,
1754 aStrokeAttributes );
1756 return true;
1759 bool OutlineAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1761 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::EffectTextArrayAction::render()" );
1762 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::EffectTextArrayAction: 0x%X", this );
1764 rendering::RenderState aLocalState( maState );
1765 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1767 return renderEffectText( *this,
1768 aLocalState,
1769 mpCanvas->getViewState(),
1770 mpCanvas->getUNOCanvas(),
1771 maShadowColor,
1772 maShadowOffset,
1773 maReliefColor,
1774 maReliefOffset );
1777 class OutlineTextArrayRenderHelper : public TextRenderer
1779 public:
1780 OutlineTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas,
1781 const uno::Reference< rendering::XPolyPolygon2D >& rTextPolygon,
1782 const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon,
1783 const rendering::ViewState& rViewState,
1784 double nOutlineWidth ) :
1785 maFillColor(
1786 ::vcl::unotools::colorToDoubleSequence(
1787 ::Color( COL_WHITE ),
1788 rCanvas->getDevice()->getDeviceColorSpace() )),
1789 mnOutlineWidth( nOutlineWidth ),
1790 mrCanvas( rCanvas ),
1791 mrTextPolygon( rTextPolygon ),
1792 mrLinePolygon( rLinePolygon ),
1793 mrViewState( rViewState )
1797 // TextRenderer interface
1798 virtual bool operator()( const rendering::RenderState& rRenderState ) const
1800 rendering::StrokeAttributes aStrokeAttributes;
1802 aStrokeAttributes.StrokeWidth = mnOutlineWidth;
1803 aStrokeAttributes.MiterLimit = 1.0;
1804 aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
1805 aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
1806 aStrokeAttributes.JoinType = rendering::PathJoinType::MITER;
1808 rendering::RenderState aLocalState( rRenderState );
1809 aLocalState.DeviceColor = maFillColor;
1811 // TODO(P1): implement caching
1813 // background of text
1814 mrCanvas->fillPolyPolygon( mrTextPolygon,
1815 mrViewState,
1816 aLocalState );
1818 // border line of text
1819 mrCanvas->strokePolyPolygon( mrTextPolygon,
1820 mrViewState,
1821 rRenderState,
1822 aStrokeAttributes );
1824 // underlines/strikethrough - background
1825 mrCanvas->fillPolyPolygon( mrLinePolygon,
1826 mrViewState,
1827 aLocalState );
1828 // underlines/strikethrough - border
1829 mrCanvas->strokePolyPolygon( mrLinePolygon,
1830 mrViewState,
1831 rRenderState,
1832 aStrokeAttributes );
1834 return true;
1837 private:
1838 const uno::Sequence< double > maFillColor;
1839 double mnOutlineWidth;
1840 const uno::Reference< rendering::XCanvas >& mrCanvas;
1841 const uno::Reference< rendering::XPolyPolygon2D >& mrTextPolygon;
1842 const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon;
1843 const rendering::ViewState& mrViewState;
1846 bool OutlineAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1847 const Subset& rSubset ) const
1849 RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::OutlineAction::renderSubset()" );
1850 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::cppcanvas::internal::OutlineAction: 0x%X", this );
1852 if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd )
1853 return true; // empty range, render nothing
1855 #if 1
1856 // TODO(F3): Subsetting NYI for outline text!
1857 return render( rTransformation );
1858 #else
1859 const rendering::StringContext rOrigContext( mxTextLayout->getText() );
1861 if( rSubset.mnSubsetBegin == 0 &&
1862 rSubset.mnSubsetEnd == rOrigContext.Length )
1864 // full range, no need for subsetting
1865 return render( rTransformation );
1868 rendering::RenderState aLocalState( maState );
1869 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1872 // create and setup local Text polygon
1873 // ===================================
1875 uno::Reference< rendering::XPolyPolygon2D > xTextPolygon();
1877 // TODO(P3): Provide an API method for that!
1879 if( !xTextLayout.is() )
1880 return false;
1882 // render everything
1883 // =================
1885 return renderEffectText(
1886 OutlineTextArrayRenderHelper(
1887 xCanvas,
1888 mnOutlineWidth,
1889 xTextLayout,
1890 xTextLines,
1891 rViewState ),
1892 aLocalState,
1893 rViewState,
1894 xCanvas,
1895 maShadowColor,
1896 maShadowOffset,
1897 maReliefColor,
1898 maReliefOffset );
1899 #endif
1902 ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1904 rendering::RenderState aLocalState( maState );
1905 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1907 return calcEffectTextBounds( maOutlineBounds,
1908 ::basegfx::B2DRange( 0,0,
1909 maLinesOverallSize.getX(),
1910 maLinesOverallSize.getY() ),
1911 maReliefOffset,
1912 maShadowOffset,
1913 aLocalState,
1914 mpCanvas->getViewState() );
1917 ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1918 const Subset& /*rSubset*/ ) const
1920 OSL_FAIL( "OutlineAction::getBounds(): Subset not yet supported by this object" );
1922 return getBounds( rTransformation );
1925 sal_Int32 OutlineAction::getActionCount() const
1927 // TODO(F3): Subsetting NYI for outline text!
1928 return maOffsets.getLength();
1932 // ======================================================================
1934 // Action factory methods
1936 // ======================================================================
1938 /** Create an outline action
1940 This method extracts the polygonal outline from the
1941 text, and creates a properly setup OutlineAction from
1944 ActionSharedPtr createOutline( const ::basegfx::B2DPoint& rStartPoint,
1945 const ::basegfx::B2DSize& rReliefOffset,
1946 const ::Color& rReliefColor,
1947 const ::basegfx::B2DSize& rShadowOffset,
1948 const ::Color& rShadowColor,
1949 const String& rText,
1950 sal_Int32 nStartPos,
1951 sal_Int32 nLen,
1952 const sal_Int32* pDXArray,
1953 VirtualDevice& rVDev,
1954 const CanvasSharedPtr& rCanvas,
1955 const OutDevState& rState,
1956 const Renderer::Parameters& rParms )
1958 // operate on raw DX array here (in logical coordinate
1959 // system), to have a higher resolution
1960 // PolyPolygon. That polygon is then converted to
1961 // device coordinate system.
1963 // #i68512# Temporarily switch off font rotation
1964 // (which is already contained in the render state
1965 // transformation matrix - otherwise, glyph polygons
1966 // will be rotated twice)
1967 const ::Font aOrigFont( rVDev.GetFont() );
1968 ::Font aUnrotatedFont( aOrigFont );
1969 aUnrotatedFont.SetOrientation(0);
1970 rVDev.SetFont( aUnrotatedFont );
1972 // TODO(F3): Don't understand parameter semantics of
1973 // GetTextOutlines()
1974 ::basegfx::B2DPolyPolygon aResultingPolyPolygon;
1975 PolyPolyVector aVCLPolyPolyVector;
1976 const bool bHaveOutlines( rVDev.GetTextOutlines( aVCLPolyPolyVector, rText,
1977 static_cast<sal_uInt16>(nStartPos),
1978 static_cast<sal_uInt16>(nStartPos),
1979 static_cast<sal_uInt16>(nLen),
1980 sal_True, 0, pDXArray ) );
1981 rVDev.SetFont(aOrigFont);
1983 if( !bHaveOutlines )
1984 return ActionSharedPtr();
1986 ::std::vector< sal_Int32 > aPolygonGlyphMap;
1988 // first glyph starts at polygon index 0
1989 aPolygonGlyphMap.push_back( 0 );
1991 // remove offsetting from mapmode transformation
1992 // (outline polygons must stay at origin, only need to
1993 // be scaled)
1994 ::basegfx::B2DHomMatrix aMapModeTransform(
1995 rState.mapModeTransform );
1996 aMapModeTransform.set(0,2, 0.0);
1997 aMapModeTransform.set(1,2, 0.0);
1999 PolyPolyVector::const_iterator aIter( aVCLPolyPolyVector.begin() );
2000 const PolyPolyVector::const_iterator aEnd( aVCLPolyPolyVector.end() );
2001 for( ; aIter!= aEnd; ++aIter )
2003 ::basegfx::B2DPolyPolygon aPolyPolygon;
2005 aPolyPolygon = aIter->getB2DPolyPolygon();
2006 aPolyPolygon.transform( aMapModeTransform );
2008 // append result to collecting polypoly
2009 for( sal_uInt32 i=0; i<aPolyPolygon.count(); ++i )
2011 // #i47795# Ensure closed polygons (since
2012 // FreeType returns the glyph outlines
2013 // open)
2014 const ::basegfx::B2DPolygon& rPoly( aPolyPolygon.getB2DPolygon( i ) );
2015 const sal_uInt32 nCount( rPoly.count() );
2016 if( nCount<3 ||
2017 rPoly.isClosed() )
2019 // polygon either degenerate, or
2020 // already closed.
2021 aResultingPolyPolygon.append( rPoly );
2023 else
2025 ::basegfx::B2DPolygon aPoly(rPoly);
2026 aPoly.setClosed(true);
2028 aResultingPolyPolygon.append( aPoly );
2032 // TODO(F3): Depending on the semantics of
2033 // GetTextOutlines(), this here is wrong!
2035 // calc next glyph index
2036 aPolygonGlyphMap.push_back( aResultingPolyPolygon.count() );
2039 const uno::Sequence< double > aCharWidthSeq(
2040 pDXArray ?
2041 setupDXArray( pDXArray, nLen, rState ) :
2042 setupDXArray( rText,
2043 nStartPos,
2044 nLen,
2045 rVDev,
2046 rState ));
2047 const uno::Reference< rendering::XPolyPolygon2D > xTextPoly(
2048 ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
2049 rCanvas->getUNOCanvas()->getDevice(),
2050 aResultingPolyPolygon ) );
2052 if( rParms.maTextTransformation.is_initialized() )
2054 return ActionSharedPtr(
2055 new OutlineAction(
2056 rStartPoint,
2057 rReliefOffset,
2058 rReliefColor,
2059 rShadowOffset,
2060 rShadowColor,
2061 ::basegfx::tools::getRange(aResultingPolyPolygon),
2062 xTextPoly,
2063 aPolygonGlyphMap,
2064 aCharWidthSeq,
2065 rVDev,
2066 rCanvas,
2067 rState,
2068 *rParms.maTextTransformation ) );
2070 else
2072 return ActionSharedPtr(
2073 new OutlineAction(
2074 rStartPoint,
2075 rReliefOffset,
2076 rReliefColor,
2077 rShadowOffset,
2078 rShadowColor,
2079 ::basegfx::tools::getRange(aResultingPolyPolygon),
2080 xTextPoly,
2081 aPolygonGlyphMap,
2082 aCharWidthSeq,
2083 rVDev,
2084 rCanvas,
2085 rState ) );
2089 } // namespace
2092 // ---------------------------------------------------------------------------------
2094 ActionSharedPtr TextActionFactory::createTextAction( const ::Point& rStartPoint,
2095 const ::Size& rReliefOffset,
2096 const ::Color& rReliefColor,
2097 const ::Size& rShadowOffset,
2098 const ::Color& rShadowColor,
2099 const String& rText,
2100 sal_Int32 nStartPos,
2101 sal_Int32 nLen,
2102 const sal_Int32* pDXArray,
2103 VirtualDevice& rVDev,
2104 const CanvasSharedPtr& rCanvas,
2105 const OutDevState& rState,
2106 const Renderer::Parameters& rParms,
2107 bool bSubsettable )
2109 const ::Size aBaselineOffset( tools::getBaselineOffset( rState,
2110 rVDev ) );
2111 // #143885# maintain (nearly) full precision positioning,
2112 // by circumventing integer-based OutDev-mapping
2113 const ::basegfx::B2DPoint aStartPoint(
2114 rState.mapModeTransform *
2115 ::basegfx::B2DPoint(rStartPoint.X() + aBaselineOffset.Width(),
2116 rStartPoint.Y() + aBaselineOffset.Height()) );
2118 const ::basegfx::B2DSize aReliefOffset(
2119 rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rReliefOffset ) );
2120 const ::basegfx::B2DSize aShadowOffset(
2121 rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rShadowOffset ) );
2123 if( rState.isTextOutlineModeSet )
2125 return createOutline(
2126 aStartPoint,
2127 aReliefOffset,
2128 rReliefColor,
2129 aShadowOffset,
2130 rShadowColor,
2131 rText,
2132 nStartPos,
2133 nLen,
2134 pDXArray,
2135 rVDev,
2136 rCanvas,
2137 rState,
2138 rParms );
2141 // convert DX array to device coordinate system (and
2142 // create it in the first place, if pDXArray is NULL)
2143 const uno::Sequence< double > aCharWidths(
2144 pDXArray ?
2145 setupDXArray( pDXArray, nLen, rState ) :
2146 setupDXArray( rText,
2147 nStartPos,
2148 nLen,
2149 rVDev,
2150 rState ));
2152 // determine type of text action to create
2153 // =======================================
2155 const ::Color aEmptyColor( COL_AUTO );
2157 // no DX array, and no need to subset - no need to store
2158 // DX array, then.
2159 if( !pDXArray && !bSubsettable )
2161 // effects, or not?
2162 if( !rState.textOverlineStyle &&
2163 !rState.textUnderlineStyle &&
2164 !rState.textStrikeoutStyle &&
2165 rReliefColor == aEmptyColor &&
2166 rShadowColor == aEmptyColor )
2168 // nope
2169 if( rParms.maTextTransformation.is_initialized() )
2171 return ActionSharedPtr( new TextAction(
2172 aStartPoint,
2173 rText,
2174 nStartPos,
2175 nLen,
2176 rCanvas,
2177 rState,
2178 *rParms.maTextTransformation ) );
2180 else
2182 return ActionSharedPtr( new TextAction(
2183 aStartPoint,
2184 rText,
2185 nStartPos,
2186 nLen,
2187 rCanvas,
2188 rState ) );
2191 else
2193 // at least one of the effects requested
2194 if( rParms.maTextTransformation.is_initialized() )
2195 return ActionSharedPtr( new EffectTextAction(
2196 aStartPoint,
2197 aReliefOffset,
2198 rReliefColor,
2199 aShadowOffset,
2200 rShadowColor,
2201 rText,
2202 nStartPos,
2203 nLen,
2204 rVDev,
2205 rCanvas,
2206 rState,
2207 *rParms.maTextTransformation ) );
2208 else
2209 return ActionSharedPtr( new EffectTextAction(
2210 aStartPoint,
2211 aReliefOffset,
2212 rReliefColor,
2213 aShadowOffset,
2214 rShadowColor,
2215 rText,
2216 nStartPos,
2217 nLen,
2218 rVDev,
2219 rCanvas,
2220 rState ) );
2223 else
2225 // DX array necessary - any effects?
2226 if( !rState.textOverlineStyle &&
2227 !rState.textUnderlineStyle &&
2228 !rState.textStrikeoutStyle &&
2229 rReliefColor == aEmptyColor &&
2230 rShadowColor == aEmptyColor )
2232 // nope
2233 if( rParms.maTextTransformation.is_initialized() )
2234 return ActionSharedPtr( new TextArrayAction(
2235 aStartPoint,
2236 rText,
2237 nStartPos,
2238 nLen,
2239 aCharWidths,
2240 rCanvas,
2241 rState,
2242 *rParms.maTextTransformation ) );
2243 else
2244 return ActionSharedPtr( new TextArrayAction(
2245 aStartPoint,
2246 rText,
2247 nStartPos,
2248 nLen,
2249 aCharWidths,
2250 rCanvas,
2251 rState ) );
2253 else
2255 // at least one of the effects requested
2256 if( rParms.maTextTransformation.is_initialized() )
2257 return ActionSharedPtr( new EffectTextArrayAction(
2258 aStartPoint,
2259 aReliefOffset,
2260 rReliefColor,
2261 aShadowOffset,
2262 rShadowColor,
2263 rText,
2264 nStartPos,
2265 nLen,
2266 aCharWidths,
2267 rVDev,
2268 rCanvas,
2269 rState,
2270 *rParms.maTextTransformation ) );
2271 else
2272 return ActionSharedPtr( new EffectTextArrayAction(
2273 aStartPoint,
2274 aReliefOffset,
2275 rReliefColor,
2276 aShadowOffset,
2277 rShadowColor,
2278 rText,
2279 nStartPos,
2280 nLen,
2281 aCharWidths,
2282 rVDev,
2283 rCanvas,
2284 rState ) );
2287 #if defined(__GNUC__)
2288 return ActionSharedPtr();
2289 #endif
2294 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */