update credits
[LibreOffice.git] / cppcanvas / source / mtfrenderer / textaction.cxx
blob61b9182e91246ce61d0b9c7b948fbf463501843c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <canvas/debug.hxx>
22 #include <tools/diagnose_ex.h>
23 #include <canvas/verbosetrace.hxx>
25 #include <com/sun/star/rendering/PathCapType.hpp>
26 #include <com/sun/star/rendering/PathJoinType.hpp>
27 #include <com/sun/star/rendering/XCanvas.hpp>
28 #include <com/sun/star/rendering/XCanvasFont.hpp>
30 #include <basegfx/numeric/ftools.hxx>
31 #include <basegfx/matrix/b2dhommatrix.hxx>
32 #include <basegfx/range/b2drectangle.hxx>
33 #include <basegfx/vector/b2dsize.hxx>
34 #include <basegfx/polygon/b2dpolypolygontools.hxx>
35 #include <basegfx/polygon/b2dpolygontools.hxx>
36 #include <basegfx/matrix/b2dhommatrixtools.hxx>
38 #include <tools/gen.hxx>
39 #include <vcl/canvastools.hxx>
40 #include <vcl/virdev.hxx>
42 #include <basegfx/tools/canvastools.hxx>
43 #include <canvas/canvastools.hxx>
45 #include <boost/scoped_array.hpp>
46 #include <boost/bind.hpp>
47 #include <boost/utility.hpp>
49 #include "textaction.hxx"
50 #include "outdevstate.hxx"
51 #include "mtftools.hxx"
54 using namespace ::com::sun::star;
56 namespace cppcanvas
58 namespace internal
60 namespace
62 void init( rendering::RenderState& o_rRenderState,
63 const ::basegfx::B2DPoint& rStartPoint,
64 const OutDevState& rState,
65 const CanvasSharedPtr& rCanvas )
67 tools::initRenderState(o_rRenderState,rState);
69 // #i36950# Offset clip back to origin (as it's also moved
70 // by rStartPoint)
71 // #i53964# Also take VCL font rotation into account,
72 // since this, opposed to the FontMatrix rotation
73 // elsewhere, _does_ get incorporated into the render
74 // state transform.
75 tools::modifyClip( o_rRenderState,
76 rState,
77 rCanvas,
78 rStartPoint,
79 NULL,
80 &rState.fontRotation );
82 basegfx::B2DHomMatrix aLocalTransformation(basegfx::tools::createRotateB2DHomMatrix(rState.fontRotation));
83 aLocalTransformation.translate( rStartPoint.getX(),
84 rStartPoint.getY() );
85 ::canvas::tools::appendToRenderState( o_rRenderState,
86 aLocalTransformation );
88 o_rRenderState.DeviceColor = rState.textColor;
91 void init( rendering::RenderState& o_rRenderState,
92 const ::basegfx::B2DPoint& rStartPoint,
93 const OutDevState& rState,
94 const CanvasSharedPtr& rCanvas,
95 const ::basegfx::B2DHomMatrix& rTextTransform )
97 init( o_rRenderState, rStartPoint, rState, rCanvas );
99 // TODO(F2): Also inversely-transform clip with
100 // rTextTransform (which is actually rather hard, as the
101 // text transform is _prepended_ to the render state)!
103 // prepend extra font transform to render state
104 // (prepend it, because it's interpreted in the unit
105 // rect coordinate space)
106 ::canvas::tools::prependToRenderState( o_rRenderState,
107 rTextTransform );
110 void init( rendering::RenderState& o_rRenderState,
111 uno::Reference< rendering::XCanvasFont >& o_rFont,
112 const ::basegfx::B2DPoint& rStartPoint,
113 const OutDevState& rState,
114 const CanvasSharedPtr& rCanvas )
116 // ensure that o_rFont is valid. It is possible that
117 // text actions are generated without previously
118 // setting a font. Then, just take a default font
119 if( !o_rFont.is() )
121 // Use completely default FontRequest
122 const rendering::FontRequest aFontRequest;
124 geometry::Matrix2D aFontMatrix;
125 ::canvas::tools::setIdentityMatrix2D( aFontMatrix );
127 o_rFont = rCanvas->getUNOCanvas()->createFont(
128 aFontRequest,
129 uno::Sequence< beans::PropertyValue >(),
130 aFontMatrix );
133 init( o_rRenderState,
134 rStartPoint,
135 rState,
136 rCanvas );
139 void init( rendering::RenderState& o_rRenderState,
140 uno::Reference< rendering::XCanvasFont >& o_rFont,
141 const ::basegfx::B2DPoint& rStartPoint,
142 const OutDevState& rState,
143 const CanvasSharedPtr& rCanvas,
144 const ::basegfx::B2DHomMatrix& rTextTransform )
146 init( o_rRenderState, o_rFont, rStartPoint, rState, rCanvas );
148 // TODO(F2): Also inversely-transform clip with
149 // rTextTransform (which is actually rather hard, as the
150 // text transform is _prepended_ to the render state)!
152 // prepend extra font transform to render state
153 // (prepend it, because it's interpreted in the unit
154 // rect coordinate space)
155 ::canvas::tools::prependToRenderState( o_rRenderState,
156 rTextTransform );
159 ::basegfx::B2DPolyPolygon textLinesFromLogicalOffsets( const uno::Sequence< double >& rOffsets,
160 const tools::TextLineInfo& rTextLineInfo )
162 return tools::createTextLinesPolyPolygon(
163 0.0,
164 // extract character cell furthest to the right
165 *(::std::max_element(
166 rOffsets.getConstArray(),
167 rOffsets.getConstArray() + rOffsets.getLength() )),
168 rTextLineInfo );
171 uno::Sequence< double > setupDXArray( const sal_Int32* pCharWidths,
172 sal_Int32 nLen,
173 const OutDevState& rState )
175 // convert character widths from logical units
176 uno::Sequence< double > aCharWidthSeq( nLen );
177 double* pOutputWidths( aCharWidthSeq.getArray() );
179 // #143885# maintain (nearly) full precision of DX
180 // array, by circumventing integer-based
181 // OutDev-mapping
182 const double nScale( rState.mapModeTransform.get(0,0) );
183 for( int i = 0; i < nLen; ++i )
185 // TODO(F2): use correct scale direction
186 *pOutputWidths++ = *pCharWidths++ * nScale;
189 return aCharWidthSeq;
192 uno::Sequence< double > setupDXArray( const ::String& rText,
193 sal_Int32 nStartPos,
194 sal_Int32 nLen,
195 VirtualDevice& rVDev,
196 const OutDevState& rState )
198 // no external DX array given, create one from given
199 // string
200 ::boost::scoped_array< sal_Int32 > pCharWidths( new sal_Int32[nLen] );
202 rVDev.GetTextArray( rText, pCharWidths.get(),
203 static_cast<sal_uInt16>(nStartPos),
204 static_cast<sal_uInt16>(nLen) );
206 return setupDXArray( pCharWidths.get(), nLen, rState );
209 ::basegfx::B2DPoint adaptStartPoint( const ::basegfx::B2DPoint& rStartPoint,
210 const OutDevState& rState,
211 const uno::Sequence< double >& rOffsets )
213 ::basegfx::B2DPoint aLocalPoint( rStartPoint );
215 if( rState.textAlignment )
217 // text origin is right, not left. Modify start point
218 // accordingly, because XCanvas::drawTextLayout()
219 // always aligns left!
221 const double nOffset( rOffsets[ rOffsets.getLength()-1 ] );
223 // correct start point for rotated text: rotate around
224 // former start point
225 aLocalPoint.setX( aLocalPoint.getX() + cos( rState.fontRotation )*nOffset );
226 aLocalPoint.setY( aLocalPoint.getY() + sin( rState.fontRotation )*nOffset );
229 return aLocalPoint;
232 /** Perform common setup for array text actions
234 This method creates the XTextLayout object and
235 initializes it, e.g. with the logical advancements.
237 void initArrayAction( rendering::RenderState& o_rRenderState,
238 uno::Reference< rendering::XTextLayout >& o_rTextLayout,
239 const ::basegfx::B2DPoint& rStartPoint,
240 const OUString& rText,
241 sal_Int32 nStartPos,
242 sal_Int32 nLen,
243 const uno::Sequence< double >& rOffsets,
244 const CanvasSharedPtr& rCanvas,
245 const OutDevState& rState,
246 const ::basegfx::B2DHomMatrix* pTextTransform )
248 ENSURE_OR_THROW( rOffsets.getLength(),
249 "::cppcanvas::internal::initArrayAction(): zero-length DX array" );
251 const ::basegfx::B2DPoint aLocalStartPoint(
252 adaptStartPoint( rStartPoint, rState, rOffsets ) );
254 uno::Reference< rendering::XCanvasFont > xFont( rState.xFont );
256 if( pTextTransform )
257 init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas, *pTextTransform );
258 else
259 init( o_rRenderState, xFont, aLocalStartPoint, rState, rCanvas );
261 o_rTextLayout = xFont->createTextLayout(
262 rendering::StringContext( rText, nStartPos, nLen ),
263 rState.textDirection,
264 0 );
266 ENSURE_OR_THROW( o_rTextLayout.is(),
267 "::cppcanvas::internal::initArrayAction(): Invalid font" );
269 o_rTextLayout->applyLogicalAdvancements( rOffsets );
272 double getLineWidth( ::VirtualDevice& rVDev,
273 const OutDevState& rState,
274 const rendering::StringContext& rStringContext )
276 // TODO(F2): use correct scale direction
277 const ::basegfx::B2DSize aSize( rVDev.GetTextWidth( rStringContext.Text,
278 static_cast<sal_uInt16>(rStringContext.StartPosition),
279 static_cast<sal_uInt16>(rStringContext.Length) ),
280 0 );
282 return (rState.mapModeTransform * aSize).getX();
285 uno::Sequence< double >
286 calcSubsetOffsets( rendering::RenderState& io_rRenderState,
287 double& o_rMinPos,
288 double& o_rMaxPos,
289 const uno::Reference< rendering::XTextLayout >& rOrigTextLayout,
290 const ::cppcanvas::internal::Action::Subset& rSubset )
292 ENSURE_OR_THROW( rSubset.mnSubsetEnd > rSubset.mnSubsetBegin,
293 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
295 uno::Sequence< double > aOrigOffsets( rOrigTextLayout->queryLogicalAdvancements() );
296 const double* pOffsets( aOrigOffsets.getConstArray() );
298 ENSURE_OR_THROW( aOrigOffsets.getLength() >= rSubset.mnSubsetEnd,
299 "::cppcanvas::internal::calcSubsetOffsets(): invalid subset range range" );
301 // TODO(F3): It currently seems that for RTL text, the
302 // DX offsets are nevertheless increasing in logical
303 // text order (I'd expect they are decreasing,
304 // mimicking the fact that the text is output
305 // right-to-left). This breaks text effects for ALL
306 // RTL languages.
308 // determine leftmost position in given subset range -
309 // as the DX array contains the output positions
310 // starting with the second character (the first is
311 // assumed to have output position 0), correct begin
312 // iterator.
313 const double nMinPos( rSubset.mnSubsetBegin <= 0 ? 0 :
314 *(::std::min_element( pOffsets+rSubset.mnSubsetBegin-1,
315 pOffsets+rSubset.mnSubsetEnd )) );
317 // determine rightmost position in given subset range
318 // - as the DX array contains the output positions
319 // starting with the second character (the first is
320 // assumed to have output position 0), correct begin
321 // iterator.
322 const double nMaxPos(
323 *(::std::max_element( pOffsets + (rSubset.mnSubsetBegin <= 0 ?
324 0 : rSubset.mnSubsetBegin-1),
325 pOffsets + rSubset.mnSubsetEnd )) );
328 // adapt render state, to move text output to given offset
329 // -------------------------------------------------------
331 // TODO(F1): Strictly speaking, we also have to adapt
332 // the clip here, which normally should _not_ move
333 // with the output offset. Neglected for now, as it
334 // does not matter for drawing layer output
336 if( rSubset.mnSubsetBegin > 0 )
338 ::basegfx::B2DHomMatrix aTranslation;
339 if( rOrigTextLayout->getFont()->getFontRequest().FontDescription.IsVertical )
341 // vertical text -> offset in y direction
342 aTranslation.translate( 0.0, nMinPos );
344 else
346 // horizontal text -> offset in x direction
347 aTranslation.translate( nMinPos, 0.0 );
350 ::canvas::tools::appendToRenderState( io_rRenderState,
351 aTranslation );
355 // reduce DX array to given substring
356 // ----------------------------------
358 const sal_Int32 nNewElements( rSubset.mnSubsetEnd - rSubset.mnSubsetBegin );
359 uno::Sequence< double > aAdaptedOffsets( nNewElements );
360 double* pAdaptedOffsets( aAdaptedOffsets.getArray() );
362 // move to new output position (subtract nMinPos,
363 // which is the new '0' position), copy only the range
364 // as given by rSubset.
365 ::std::transform( pOffsets + rSubset.mnSubsetBegin,
366 pOffsets + rSubset.mnSubsetEnd,
367 pAdaptedOffsets,
368 ::boost::bind( ::std::minus<double>(),
370 nMinPos ) );
372 o_rMinPos = nMinPos;
373 o_rMaxPos = nMaxPos;
375 return aAdaptedOffsets;
378 uno::Reference< rendering::XTextLayout >
379 createSubsetLayout( const rendering::StringContext& rOrigContext,
380 const ::cppcanvas::internal::Action::Subset& rSubset,
381 const uno::Reference< rendering::XTextLayout >& rOrigTextLayout )
383 // create temporary new text layout with subset string
384 // ---------------------------------------------------
386 const sal_Int32 nNewStartPos( rOrigContext.StartPosition + ::std::min(
387 rSubset.mnSubsetBegin, rOrigContext.Length-1 ) );
388 const sal_Int32 nNewLength( ::std::max(
389 ::std::min(
390 rSubset.mnSubsetEnd - rSubset.mnSubsetBegin,
391 rOrigContext.Length ),
392 sal_Int32( 0 ) ) );
394 const rendering::StringContext aContext( rOrigContext.Text,
395 nNewStartPos,
396 nNewLength );
398 uno::Reference< rendering::XTextLayout > xTextLayout(
399 rOrigTextLayout->getFont()->createTextLayout( aContext,
400 rOrigTextLayout->getMainTextDirection(),
401 0 ),
402 uno::UNO_QUERY_THROW );
404 return xTextLayout;
407 /** Setup subset text layout
409 @param io_rTextLayout
410 Must contain original (full set) text layout on input,
411 will contain subsetted text layout (or empty
412 reference, for empty subsets) on output.
414 @param io_rRenderState
415 Must contain original render state on input, will
416 contain shifted render state concatenated with
417 rTransformation on output.
419 @param rTransformation
420 Additional transformation, to be prepended to render
421 state
423 @param rSubset
424 Subset to prepare
426 void createSubsetLayout( uno::Reference< rendering::XTextLayout >& io_rTextLayout,
427 rendering::RenderState& io_rRenderState,
428 double& o_rMinPos,
429 double& o_rMaxPos,
430 const ::basegfx::B2DHomMatrix& rTransformation,
431 const Action::Subset& rSubset )
433 ::canvas::tools::prependToRenderState(io_rRenderState, rTransformation);
435 if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd )
437 // empty range, empty layout
438 io_rTextLayout.clear();
440 return;
443 ENSURE_OR_THROW( io_rTextLayout.is(),
444 "createSubsetLayout(): Invalid input layout" );
446 const rendering::StringContext& rOrigContext( io_rTextLayout->getText() );
448 if( rSubset.mnSubsetBegin == 0 &&
449 rSubset.mnSubsetEnd == rOrigContext.Length )
451 // full range, no need for subsetting
452 return;
455 uno::Reference< rendering::XTextLayout > xTextLayout(
456 createSubsetLayout( rOrigContext, rSubset, io_rTextLayout ) );
458 if( xTextLayout.is() )
460 xTextLayout->applyLogicalAdvancements(
461 calcSubsetOffsets( io_rRenderState,
462 o_rMinPos,
463 o_rMaxPos,
464 io_rTextLayout,
465 rSubset ) );
468 io_rTextLayout = xTextLayout;
472 /** Interface for renderEffectText functor below.
474 This is interface is used from the renderEffectText()
475 method below, to call the client implementation.
477 class TextRenderer
479 public:
480 virtual ~TextRenderer() {}
482 /// Render text with given RenderState
483 virtual bool operator()( const rendering::RenderState& rRenderState ) const = 0;
486 /** Render effect text.
488 @param rRenderer
489 Functor object, will be called to render the actual
490 part of the text effect (the text itself and the means
491 to render it are unknown to this method)
493 bool renderEffectText( const TextRenderer& rRenderer,
494 const rendering::RenderState& rRenderState,
495 const rendering::ViewState& /*rViewState*/,
496 const uno::Reference< rendering::XCanvas >& xCanvas,
497 const ::Color& rShadowColor,
498 const ::basegfx::B2DSize& rShadowOffset,
499 const ::Color& rReliefColor,
500 const ::basegfx::B2DSize& rReliefOffset )
502 ::Color aEmptyColor( COL_AUTO );
503 uno::Reference<rendering::XColorSpace> xColorSpace(
504 xCanvas->getDevice()->getDeviceColorSpace() );
506 // draw shadow text, if enabled
507 if( rShadowColor != aEmptyColor )
509 rendering::RenderState aShadowState( rRenderState );
510 ::basegfx::B2DHomMatrix aTranslate;
512 aTranslate.translate( rShadowOffset.getX(),
513 rShadowOffset.getY() );
515 ::canvas::tools::appendToRenderState(aShadowState, aTranslate);
517 aShadowState.DeviceColor =
518 ::vcl::unotools::colorToDoubleSequence( rShadowColor,
519 xColorSpace );
521 rRenderer( aShadowState );
524 // draw relief text, if enabled
525 if( rReliefColor != aEmptyColor )
527 rendering::RenderState aReliefState( rRenderState );
528 ::basegfx::B2DHomMatrix aTranslate;
530 aTranslate.translate( rReliefOffset.getX(),
531 rReliefOffset.getY() );
533 ::canvas::tools::appendToRenderState(aReliefState, aTranslate);
535 aReliefState.DeviceColor =
536 ::vcl::unotools::colorToDoubleSequence( rReliefColor,
537 xColorSpace );
539 rRenderer( aReliefState );
542 // draw normal text
543 rRenderer( rRenderState );
545 return true;
549 ::basegfx::B2DRange calcEffectTextBounds( const ::basegfx::B2DRange& rTextBounds,
550 const ::basegfx::B2DRange& rLineBounds,
551 const ::basegfx::B2DSize& rReliefOffset,
552 const ::basegfx::B2DSize& rShadowOffset,
553 const rendering::RenderState& rRenderState,
554 const rendering::ViewState& rViewState )
556 ::basegfx::B2DRange aBounds( rTextBounds );
558 // add extends of text lines
559 aBounds.expand( rLineBounds );
561 // TODO(Q3): Provide this functionality at the B2DRange
562 ::basegfx::B2DRange aTotalBounds( aBounds );
563 aTotalBounds.expand(
564 ::basegfx::B2DRange( aBounds.getMinX() + rReliefOffset.getX(),
565 aBounds.getMinY() + rReliefOffset.getY(),
566 aBounds.getMaxX() + rReliefOffset.getX(),
567 aBounds.getMaxY() + rReliefOffset.getY() ) );
568 aTotalBounds.expand(
569 ::basegfx::B2DRange( aBounds.getMinX() + rShadowOffset.getX(),
570 aBounds.getMinY() + rShadowOffset.getY(),
571 aBounds.getMaxX() + rShadowOffset.getX(),
572 aBounds.getMaxY() + rShadowOffset.getY() ) );
574 return tools::calcDevicePixelBounds( aTotalBounds,
575 rViewState,
576 rRenderState );
579 void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize,
580 uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines,
581 const CanvasSharedPtr& rCanvas,
582 const uno::Sequence< double >& rOffsets,
583 const tools::TextLineInfo rLineInfo )
585 const ::basegfx::B2DPolyPolygon aPoly(
586 textLinesFromLogicalOffsets(
587 rOffsets,
588 rLineInfo ) );
590 o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange();
592 o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
593 rCanvas->getUNOCanvas()->getDevice(),
594 aPoly );
597 void initEffectLinePolyPolygon( ::basegfx::B2DSize& o_rOverallSize,
598 uno::Reference< rendering::XPolyPolygon2D >& o_rTextLines,
599 const CanvasSharedPtr& rCanvas,
600 double nLineWidth,
601 const tools::TextLineInfo rLineInfo )
603 const ::basegfx::B2DPolyPolygon aPoly(
604 tools::createTextLinesPolyPolygon( 0.0, nLineWidth,
605 rLineInfo ) );
607 o_rOverallSize = ::basegfx::tools::getRange( aPoly ).getRange();
609 o_rTextLines = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
610 rCanvas->getUNOCanvas()->getDevice(),
611 aPoly );
615 // -------------------------------------------------------------------------
617 class TextAction : public Action, private ::boost::noncopyable
619 public:
620 TextAction( const ::basegfx::B2DPoint& rStartPoint,
621 const OUString& rString,
622 sal_Int32 nStartPos,
623 sal_Int32 nLen,
624 const CanvasSharedPtr& rCanvas,
625 const OutDevState& rState );
627 TextAction( const ::basegfx::B2DPoint& rStartPoint,
628 const OUString& rString,
629 sal_Int32 nStartPos,
630 sal_Int32 nLen,
631 const CanvasSharedPtr& rCanvas,
632 const OutDevState& rState,
633 const ::basegfx::B2DHomMatrix& rTextTransform );
635 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
636 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
637 const Subset& rSubset ) const;
639 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
640 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
641 const Subset& rSubset ) const;
643 virtual sal_Int32 getActionCount() const;
645 private:
646 // TODO(P2): This is potentially a real mass object
647 // (every character might be a separate TextAction),
648 // thus, make it as lightweight as possible. For
649 // example, share common RenderState among several
650 // TextActions, maybe using maOffsets for the
651 // translation.
653 uno::Reference< rendering::XCanvasFont > mxFont;
654 const rendering::StringContext maStringContext;
655 const CanvasSharedPtr mpCanvas;
656 rendering::RenderState maState;
657 const sal_Int8 maTextDirection;
660 TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint,
661 const OUString& rString,
662 sal_Int32 nStartPos,
663 sal_Int32 nLen,
664 const CanvasSharedPtr& rCanvas,
665 const OutDevState& rState ) :
666 mxFont( rState.xFont ),
667 maStringContext( rString, nStartPos, nLen ),
668 mpCanvas( rCanvas ),
669 maState(),
670 maTextDirection( rState.textDirection )
672 init( maState, mxFont,
673 rStartPoint,
674 rState, rCanvas );
676 ENSURE_OR_THROW( mxFont.is(),
677 "::cppcanvas::internal::TextAction(): Invalid font" );
680 TextAction::TextAction( const ::basegfx::B2DPoint& rStartPoint,
681 const OUString& rString,
682 sal_Int32 nStartPos,
683 sal_Int32 nLen,
684 const CanvasSharedPtr& rCanvas,
685 const OutDevState& rState,
686 const ::basegfx::B2DHomMatrix& rTextTransform ) :
687 mxFont( rState.xFont ),
688 maStringContext( rString, nStartPos, nLen ),
689 mpCanvas( rCanvas ),
690 maState(),
691 maTextDirection( rState.textDirection )
693 init( maState, mxFont,
694 rStartPoint,
695 rState, rCanvas, rTextTransform );
697 ENSURE_OR_THROW( mxFont.is(),
698 "::cppcanvas::internal::TextAction(): Invalid font" );
701 bool TextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
703 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextAction::render()" );
704 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextAction: 0x" << std::hex << this );
706 rendering::RenderState aLocalState( maState );
707 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
709 mpCanvas->getUNOCanvas()->drawText( maStringContext, mxFont,
710 mpCanvas->getViewState(), aLocalState, maTextDirection );
712 return true;
715 bool TextAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
716 const Subset& /*rSubset*/ ) const
718 SAL_WARN( "cppcanvas.emf", "TextAction::renderSubset(): Subset not supported by this object" );
720 // TODO(P1): Retrieve necessary font metric info for
721 // TextAction from XCanvas. Currently, the
722 // TextActionFactory does not generate this object for
723 // _subsettable_ text
724 return render( rTransformation );
727 ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
729 // create XTextLayout, to have the
730 // XTextLayout::queryTextBounds() method available
731 uno::Reference< rendering::XTextLayout > xTextLayout(
732 mxFont->createTextLayout(
733 maStringContext,
734 maTextDirection,
735 0 ) );
737 rendering::RenderState aLocalState( maState );
738 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
740 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
741 xTextLayout->queryTextBounds() ),
742 mpCanvas->getViewState(),
743 aLocalState );
746 ::basegfx::B2DRange TextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
747 const Subset& /*rSubset*/ ) const
749 SAL_WARN( "cppcanvas.emf", "TextAction::getBounds(): Subset not supported by this object" );
751 // TODO(P1): Retrieve necessary font metric info for
752 // TextAction from XCanvas. Currently, the
753 // TextActionFactory does not generate this object for
754 // _subsettable_ text
755 return getBounds( rTransformation );
758 sal_Int32 TextAction::getActionCount() const
760 // TODO(P1): Retrieve necessary font metric info for
761 // TextAction from XCanvas. Currently, the
762 // TextActionFactory does not generate this object for
763 // _subsettable_ text
764 return 1;
768 // -------------------------------------------------------------------------
770 class EffectTextAction :
771 public Action,
772 public TextRenderer,
773 private ::boost::noncopyable
775 public:
776 EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
777 const ::basegfx::B2DSize& rReliefOffset,
778 const ::Color& rReliefColor,
779 const ::basegfx::B2DSize& rShadowOffset,
780 const ::Color& rShadowColor,
781 const OUString& rText,
782 sal_Int32 nStartPos,
783 sal_Int32 nLen,
784 VirtualDevice& rVDev,
785 const CanvasSharedPtr& rCanvas,
786 const OutDevState& rState );
788 EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
789 const ::basegfx::B2DSize& rReliefOffset,
790 const ::Color& rReliefColor,
791 const ::basegfx::B2DSize& rShadowOffset,
792 const ::Color& rShadowColor,
793 const OUString& rText,
794 sal_Int32 nStartPos,
795 sal_Int32 nLen,
796 VirtualDevice& rVDev,
797 const CanvasSharedPtr& rCanvas,
798 const OutDevState& rState,
799 const ::basegfx::B2DHomMatrix& rTextTransform );
801 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
802 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
803 const Subset& rSubset ) const;
805 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
806 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
807 const Subset& rSubset ) const;
809 virtual sal_Int32 getActionCount() const;
811 private:
812 /// Interface TextRenderer
813 virtual bool operator()( const rendering::RenderState& rRenderState ) const;
815 // TODO(P2): This is potentially a real mass object
816 // (every character might be a separate TextAction),
817 // thus, make it as lightweight as possible. For
818 // example, share common RenderState among several
819 // TextActions, maybe using maOffsets for the
820 // translation.
822 uno::Reference< rendering::XCanvasFont > mxFont;
823 const rendering::StringContext maStringContext;
824 const CanvasSharedPtr mpCanvas;
825 rendering::RenderState maState;
826 const tools::TextLineInfo maTextLineInfo;
827 ::basegfx::B2DSize maLinesOverallSize;
828 const double mnLineWidth;
829 uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
830 const ::basegfx::B2DSize maReliefOffset;
831 const ::Color maReliefColor;
832 const ::basegfx::B2DSize maShadowOffset;
833 const ::Color maShadowColor;
834 const sal_Int8 maTextDirection;
837 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
838 const ::basegfx::B2DSize& rReliefOffset,
839 const ::Color& rReliefColor,
840 const ::basegfx::B2DSize& rShadowOffset,
841 const ::Color& rShadowColor,
842 const OUString& rText,
843 sal_Int32 nStartPos,
844 sal_Int32 nLen,
845 VirtualDevice& rVDev,
846 const CanvasSharedPtr& rCanvas,
847 const OutDevState& rState ) :
848 mxFont( rState.xFont ),
849 maStringContext( rText, nStartPos, nLen ),
850 mpCanvas( rCanvas ),
851 maState(),
852 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
853 maLinesOverallSize(),
854 mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ),
855 mxTextLines(),
856 maReliefOffset( rReliefOffset ),
857 maReliefColor( rReliefColor ),
858 maShadowOffset( rShadowOffset ),
859 maShadowColor( rShadowColor ),
860 maTextDirection( rState.textDirection )
862 initEffectLinePolyPolygon( maLinesOverallSize,
863 mxTextLines,
864 rCanvas,
865 mnLineWidth,
866 maTextLineInfo );
868 init( maState, mxFont,
869 rStartPoint,
870 rState, rCanvas );
872 ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(),
873 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
876 EffectTextAction::EffectTextAction( const ::basegfx::B2DPoint& rStartPoint,
877 const ::basegfx::B2DSize& rReliefOffset,
878 const ::Color& rReliefColor,
879 const ::basegfx::B2DSize& rShadowOffset,
880 const ::Color& rShadowColor,
881 const OUString& rText,
882 sal_Int32 nStartPos,
883 sal_Int32 nLen,
884 VirtualDevice& rVDev,
885 const CanvasSharedPtr& rCanvas,
886 const OutDevState& rState,
887 const ::basegfx::B2DHomMatrix& rTextTransform ) :
888 mxFont( rState.xFont ),
889 maStringContext( rText, nStartPos, nLen ),
890 mpCanvas( rCanvas ),
891 maState(),
892 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
893 maLinesOverallSize(),
894 mnLineWidth( getLineWidth( rVDev, rState, maStringContext ) ),
895 mxTextLines(),
896 maReliefOffset( rReliefOffset ),
897 maReliefColor( rReliefColor ),
898 maShadowOffset( rShadowOffset ),
899 maShadowColor( rShadowColor ),
900 maTextDirection( rState.textDirection )
902 initEffectLinePolyPolygon( maLinesOverallSize,
903 mxTextLines,
904 rCanvas,
905 mnLineWidth,
906 maTextLineInfo );
908 init( maState, mxFont,
909 rStartPoint,
910 rState, rCanvas, rTextTransform );
912 ENSURE_OR_THROW( mxFont.is() && mxTextLines.is(),
913 "::cppcanvas::internal::EffectTextAction(): Invalid font or lines" );
916 bool EffectTextAction::operator()( const rendering::RenderState& rRenderState ) const
918 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
919 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
921 rCanvas->fillPolyPolygon( mxTextLines,
922 rViewState,
923 rRenderState );
925 rCanvas->drawText( maStringContext, mxFont,
926 rViewState,
927 rRenderState,
928 maTextDirection );
930 return true;
933 bool EffectTextAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
935 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextAction::render()" );
936 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextAction: 0x" << std::hex << this );
938 rendering::RenderState aLocalState( maState );
939 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
941 return renderEffectText( *this,
942 aLocalState,
943 mpCanvas->getViewState(),
944 mpCanvas->getUNOCanvas(),
945 maShadowColor,
946 maShadowOffset,
947 maReliefColor,
948 maReliefOffset );
951 bool EffectTextAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
952 const Subset& /*rSubset*/ ) const
954 SAL_WARN( "cppcanvas.emf", "EffectTextAction::renderSubset(): Subset not supported by this object" );
956 // TODO(P1): Retrieve necessary font metric info for
957 // TextAction from XCanvas. Currently, the
958 // TextActionFactory does not generate this object for
959 // subsettable text
960 return render( rTransformation );
963 ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
965 // create XTextLayout, to have the
966 // XTextLayout::queryTextBounds() method available
967 uno::Reference< rendering::XTextLayout > xTextLayout(
968 mxFont->createTextLayout(
969 maStringContext,
970 maTextDirection,
971 0 ) );
973 rendering::RenderState aLocalState( maState );
974 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
976 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
977 xTextLayout->queryTextBounds() ),
978 ::basegfx::B2DRange( 0,0,
979 maLinesOverallSize.getX(),
980 maLinesOverallSize.getY() ),
981 maReliefOffset,
982 maShadowOffset,
983 aLocalState,
984 mpCanvas->getViewState() );
987 ::basegfx::B2DRange EffectTextAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
988 const Subset& /*rSubset*/ ) const
990 SAL_WARN( "cppcanvas.emf", "EffectTextAction::getBounds(): Subset not supported by this object" );
992 // TODO(P1): Retrieve necessary font metric info for
993 // TextAction from XCanvas. Currently, the
994 // TextActionFactory does not generate this object for
995 // _subsettable_ text
996 return getBounds( rTransformation );
999 sal_Int32 EffectTextAction::getActionCount() const
1001 // TODO(P1): Retrieve necessary font metric info for
1002 // TextAction from XCanvas. Currently, the
1003 // TextActionFactory does not generate this object for
1004 // subsettable text
1005 return 1;
1009 // -------------------------------------------------------------------------
1011 class TextArrayAction : public Action, private ::boost::noncopyable
1013 public:
1014 TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1015 const OUString& rString,
1016 sal_Int32 nStartPos,
1017 sal_Int32 nLen,
1018 const uno::Sequence< double >& rOffsets,
1019 const CanvasSharedPtr& rCanvas,
1020 const OutDevState& rState );
1022 TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1023 const OUString& rString,
1024 sal_Int32 nStartPos,
1025 sal_Int32 nLen,
1026 const uno::Sequence< double >& rOffsets,
1027 const CanvasSharedPtr& rCanvas,
1028 const OutDevState& rState,
1029 const ::basegfx::B2DHomMatrix& rTextTransform );
1031 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1032 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1033 const Subset& rSubset ) const;
1035 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1036 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1037 const Subset& rSubset ) const;
1039 virtual sal_Int32 getActionCount() const;
1041 private:
1042 // TODO(P2): This is potentially a real mass object
1043 // (every character might be a separate TextAction),
1044 // thus, make it as lightweight as possible. For
1045 // example, share common RenderState among several
1046 // TextActions, maybe using maOffsets for the
1047 // translation.
1049 uno::Reference< rendering::XTextLayout > mxTextLayout;
1050 const CanvasSharedPtr mpCanvas;
1051 rendering::RenderState maState;
1054 TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1055 const OUString& rString,
1056 sal_Int32 nStartPos,
1057 sal_Int32 nLen,
1058 const uno::Sequence< double >& rOffsets,
1059 const CanvasSharedPtr& rCanvas,
1060 const OutDevState& rState ) :
1061 mxTextLayout(),
1062 mpCanvas( rCanvas ),
1063 maState()
1065 initArrayAction( maState,
1066 mxTextLayout,
1067 rStartPoint,
1068 rString,
1069 nStartPos,
1070 nLen,
1071 rOffsets,
1072 rCanvas,
1073 rState, NULL );
1076 TextArrayAction::TextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1077 const OUString& rString,
1078 sal_Int32 nStartPos,
1079 sal_Int32 nLen,
1080 const uno::Sequence< double >& rOffsets,
1081 const CanvasSharedPtr& rCanvas,
1082 const OutDevState& rState,
1083 const ::basegfx::B2DHomMatrix& rTextTransform ) :
1084 mxTextLayout(),
1085 mpCanvas( rCanvas ),
1086 maState()
1088 initArrayAction( maState,
1089 mxTextLayout,
1090 rStartPoint,
1091 rString,
1092 nStartPos,
1093 nLen,
1094 rOffsets,
1095 rCanvas,
1096 rState,
1097 &rTextTransform );
1100 bool TextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1102 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::render()" );
1103 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex << this );
1105 rendering::RenderState aLocalState( maState );
1106 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1108 mpCanvas->getUNOCanvas()->drawTextLayout( mxTextLayout,
1109 mpCanvas->getViewState(),
1110 aLocalState );
1112 return true;
1115 bool TextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1116 const Subset& rSubset ) const
1118 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::renderSubset()" );
1119 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex << this );
1121 rendering::RenderState aLocalState( maState );
1122 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1124 double nDummy0, nDummy1;
1125 createSubsetLayout( xTextLayout,
1126 aLocalState,
1127 nDummy0,
1128 nDummy1,
1129 rTransformation,
1130 rSubset );
1132 if( !xTextLayout.is() )
1133 return true; // empty layout, render nothing
1135 mpCanvas->getUNOCanvas()->drawTextLayout( xTextLayout,
1136 mpCanvas->getViewState(),
1137 aLocalState );
1139 return true;
1142 ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1144 rendering::RenderState aLocalState( maState );
1145 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1147 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1148 mxTextLayout->queryTextBounds() ),
1149 mpCanvas->getViewState(),
1150 aLocalState );
1153 ::basegfx::B2DRange TextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1154 const Subset& rSubset ) const
1156 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction::getBounds( subset )" );
1157 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::TextArrayAction: 0x" << std::hex << this );
1159 rendering::RenderState aLocalState( maState );
1160 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1162 double nDummy0, nDummy1;
1163 createSubsetLayout( xTextLayout,
1164 aLocalState,
1165 nDummy0,
1166 nDummy1,
1167 rTransformation,
1168 rSubset );
1170 if( !xTextLayout.is() )
1171 return ::basegfx::B2DRange(); // empty layout, empty bounds
1173 return tools::calcDevicePixelBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1174 xTextLayout->queryTextBounds() ),
1175 mpCanvas->getViewState(),
1176 aLocalState );
1179 sal_Int32 TextArrayAction::getActionCount() const
1181 const rendering::StringContext& rOrigContext( mxTextLayout->getText() );
1183 return rOrigContext.Length;
1187 // -------------------------------------------------------------------------
1189 class EffectTextArrayAction :
1190 public Action,
1191 public TextRenderer,
1192 private ::boost::noncopyable
1194 public:
1195 EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1196 const ::basegfx::B2DSize& rReliefOffset,
1197 const ::Color& rReliefColor,
1198 const ::basegfx::B2DSize& rShadowOffset,
1199 const ::Color& rShadowColor,
1200 const OUString& rText,
1201 sal_Int32 nStartPos,
1202 sal_Int32 nLen,
1203 const uno::Sequence< double >& rOffsets,
1204 VirtualDevice& rVDev,
1205 const CanvasSharedPtr& rCanvas,
1206 const OutDevState& rState );
1207 EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1208 const ::basegfx::B2DSize& rReliefOffset,
1209 const ::Color& rReliefColor,
1210 const ::basegfx::B2DSize& rShadowOffset,
1211 const ::Color& rShadowColor,
1212 const OUString& rText,
1213 sal_Int32 nStartPos,
1214 sal_Int32 nLen,
1215 const uno::Sequence< double >& rOffsets,
1216 VirtualDevice& rVDev,
1217 const CanvasSharedPtr& rCanvas,
1218 const OutDevState& rState,
1219 const ::basegfx::B2DHomMatrix& rTextTransform );
1221 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1222 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1223 const Subset& rSubset ) const;
1225 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1226 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1227 const Subset& rSubset ) const;
1229 virtual sal_Int32 getActionCount() const;
1231 private:
1232 // TextRenderer interface
1233 virtual bool operator()( const rendering::RenderState& rRenderState ) const;
1235 // TODO(P2): This is potentially a real mass object
1236 // (every character might be a separate TextAction),
1237 // thus, make it as lightweight as possible. For
1238 // example, share common RenderState among several
1239 // TextActions, maybe using maOffsets for the
1240 // translation.
1242 uno::Reference< rendering::XTextLayout > mxTextLayout;
1243 const CanvasSharedPtr mpCanvas;
1244 rendering::RenderState maState;
1245 const tools::TextLineInfo maTextLineInfo;
1246 ::basegfx::B2DSize maLinesOverallSize;
1247 uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
1248 const ::basegfx::B2DSize maReliefOffset;
1249 const ::Color maReliefColor;
1250 const ::basegfx::B2DSize maShadowOffset;
1251 const ::Color maShadowColor;
1254 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1255 const ::basegfx::B2DSize& rReliefOffset,
1256 const ::Color& rReliefColor,
1257 const ::basegfx::B2DSize& rShadowOffset,
1258 const ::Color& rShadowColor,
1259 const OUString& rText,
1260 sal_Int32 nStartPos,
1261 sal_Int32 nLen,
1262 const uno::Sequence< double >& rOffsets,
1263 VirtualDevice& rVDev,
1264 const CanvasSharedPtr& rCanvas,
1265 const OutDevState& rState ) :
1266 mxTextLayout(),
1267 mpCanvas( rCanvas ),
1268 maState(),
1269 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1270 maLinesOverallSize(),
1271 mxTextLines(),
1272 maReliefOffset( rReliefOffset ),
1273 maReliefColor( rReliefColor ),
1274 maShadowOffset( rShadowOffset ),
1275 maShadowColor( rShadowColor )
1277 initEffectLinePolyPolygon( maLinesOverallSize,
1278 mxTextLines,
1279 rCanvas,
1280 rOffsets,
1281 maTextLineInfo );
1283 initArrayAction( maState,
1284 mxTextLayout,
1285 rStartPoint,
1286 rText,
1287 nStartPos,
1288 nLen,
1289 rOffsets,
1290 rCanvas,
1291 rState, NULL );
1294 EffectTextArrayAction::EffectTextArrayAction( const ::basegfx::B2DPoint& rStartPoint,
1295 const ::basegfx::B2DSize& rReliefOffset,
1296 const ::Color& rReliefColor,
1297 const ::basegfx::B2DSize& rShadowOffset,
1298 const ::Color& rShadowColor,
1299 const OUString& rText,
1300 sal_Int32 nStartPos,
1301 sal_Int32 nLen,
1302 const uno::Sequence< double >& rOffsets,
1303 VirtualDevice& rVDev,
1304 const CanvasSharedPtr& rCanvas,
1305 const OutDevState& rState,
1306 const ::basegfx::B2DHomMatrix& rTextTransform ) :
1307 mxTextLayout(),
1308 mpCanvas( rCanvas ),
1309 maState(),
1310 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1311 maLinesOverallSize(),
1312 mxTextLines(),
1313 maReliefOffset( rReliefOffset ),
1314 maReliefColor( rReliefColor ),
1315 maShadowOffset( rShadowOffset ),
1316 maShadowColor( rShadowColor )
1318 initEffectLinePolyPolygon( maLinesOverallSize,
1319 mxTextLines,
1320 rCanvas,
1321 rOffsets,
1322 maTextLineInfo );
1324 initArrayAction( maState,
1325 mxTextLayout,
1326 rStartPoint,
1327 rText,
1328 nStartPos,
1329 nLen,
1330 rOffsets,
1331 rCanvas,
1332 rState,
1333 &rTextTransform );
1336 bool EffectTextArrayAction::operator()( const rendering::RenderState& rRenderState ) const
1338 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1339 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
1341 rCanvas->fillPolyPolygon( mxTextLines,
1342 rViewState,
1343 rRenderState );
1345 rCanvas->drawTextLayout( mxTextLayout,
1346 rViewState,
1347 rRenderState );
1349 return true;
1352 bool EffectTextArrayAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1354 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::render()" );
1355 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex << this );
1357 rendering::RenderState aLocalState( maState );
1358 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1360 return renderEffectText( *this,
1361 aLocalState,
1362 mpCanvas->getViewState(),
1363 mpCanvas->getUNOCanvas(),
1364 maShadowColor,
1365 maShadowOffset,
1366 maReliefColor,
1367 maReliefOffset );
1370 class EffectTextArrayRenderHelper : public TextRenderer
1372 public:
1373 EffectTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas,
1374 const uno::Reference< rendering::XTextLayout >& rTextLayout,
1375 const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon,
1376 const rendering::ViewState& rViewState ) :
1377 mrCanvas( rCanvas ),
1378 mrTextLayout( rTextLayout ),
1379 mrLinePolygon( rLinePolygon ),
1380 mrViewState( rViewState )
1384 // TextRenderer interface
1385 virtual bool operator()( const rendering::RenderState& rRenderState ) const
1387 mrCanvas->fillPolyPolygon( mrLinePolygon,
1388 mrViewState,
1389 rRenderState );
1391 mrCanvas->drawTextLayout( mrTextLayout,
1392 mrViewState,
1393 rRenderState );
1395 return true;
1398 private:
1399 const uno::Reference< rendering::XCanvas >& mrCanvas;
1400 const uno::Reference< rendering::XTextLayout >& mrTextLayout;
1401 const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon;
1402 const rendering::ViewState& mrViewState;
1405 bool EffectTextArrayAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1406 const Subset& rSubset ) const
1408 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::renderSubset()" );
1409 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex << this );
1411 rendering::RenderState aLocalState( maState );
1412 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1413 const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() );
1415 double nMinPos(0.0);
1416 double nMaxPos(aTextBounds.X2 - aTextBounds.X1);
1418 createSubsetLayout( xTextLayout,
1419 aLocalState,
1420 nMinPos,
1421 nMaxPos,
1422 rTransformation,
1423 rSubset );
1425 if( !xTextLayout.is() )
1426 return true; // empty layout, render nothing
1429 // create and setup local line polygon
1430 // ===================================
1432 uno::Reference< rendering::XCanvas > xCanvas( mpCanvas->getUNOCanvas() );
1433 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1435 uno::Reference< rendering::XPolyPolygon2D > xTextLines(
1436 ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1437 xCanvas->getDevice(),
1438 tools::createTextLinesPolyPolygon(
1439 0.0, nMaxPos - nMinPos,
1440 maTextLineInfo ) ) );
1443 // render everything
1444 // =================
1446 return renderEffectText(
1447 EffectTextArrayRenderHelper( xCanvas,
1448 xTextLayout,
1449 xTextLines,
1450 rViewState ),
1451 aLocalState,
1452 rViewState,
1453 xCanvas,
1454 maShadowColor,
1455 maShadowOffset,
1456 maReliefColor,
1457 maReliefOffset );
1460 ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1462 rendering::RenderState aLocalState( maState );
1463 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1465 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1466 mxTextLayout->queryTextBounds() ),
1467 ::basegfx::B2DRange( 0,0,
1468 maLinesOverallSize.getX(),
1469 maLinesOverallSize.getY() ),
1470 maReliefOffset,
1471 maShadowOffset,
1472 aLocalState,
1473 mpCanvas->getViewState() );
1476 ::basegfx::B2DRange EffectTextArrayAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1477 const Subset& rSubset ) const
1479 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::getBounds( subset )" );
1480 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex << this );
1482 rendering::RenderState aLocalState( maState );
1483 uno::Reference< rendering::XTextLayout > xTextLayout( mxTextLayout );
1484 const geometry::RealRectangle2D aTextBounds( mxTextLayout->queryTextBounds() );
1486 double nMinPos(0.0);
1487 double nMaxPos(aTextBounds.X2 - aTextBounds.X1);
1489 createSubsetLayout( xTextLayout,
1490 aLocalState,
1491 nMinPos,
1492 nMaxPos,
1493 rTransformation,
1494 rSubset );
1496 if( !xTextLayout.is() )
1497 return ::basegfx::B2DRange(); // empty layout, empty bounds
1500 // create and setup local line polygon
1501 // ===================================
1503 const ::basegfx::B2DPolyPolygon aPoly(
1504 tools::createTextLinesPolyPolygon(
1505 0.0, nMaxPos - nMinPos,
1506 maTextLineInfo ) );
1508 return calcEffectTextBounds( ::basegfx::unotools::b2DRectangleFromRealRectangle2D(
1509 xTextLayout->queryTextBounds() ),
1510 ::basegfx::tools::getRange( aPoly ),
1511 maReliefOffset,
1512 maShadowOffset,
1513 aLocalState,
1514 mpCanvas->getViewState() );
1517 sal_Int32 EffectTextArrayAction::getActionCount() const
1519 const rendering::StringContext& rOrigContext( mxTextLayout->getText() );
1521 return rOrigContext.Length;
1525 // -------------------------------------------------------------------------
1527 class OutlineAction :
1528 public Action,
1529 public TextRenderer,
1530 private ::boost::noncopyable
1532 public:
1533 OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1534 const ::basegfx::B2DSize& rReliefOffset,
1535 const ::Color& rReliefColor,
1536 const ::basegfx::B2DSize& rShadowOffset,
1537 const ::Color& rShadowColor,
1538 const ::basegfx::B2DRectangle& rOutlineBounds,
1539 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1540 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1541 const uno::Sequence< double >& rOffsets,
1542 VirtualDevice& rVDev,
1543 const CanvasSharedPtr& rCanvas,
1544 const OutDevState& rState );
1545 OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1546 const ::basegfx::B2DSize& rReliefOffset,
1547 const ::Color& rReliefColor,
1548 const ::basegfx::B2DSize& rShadowOffset,
1549 const ::Color& rShadowColor,
1550 const ::basegfx::B2DRectangle& rOutlineBounds,
1551 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1552 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1553 const uno::Sequence< double >& rOffsets,
1554 VirtualDevice& rVDev,
1555 const CanvasSharedPtr& rCanvas,
1556 const OutDevState& rState,
1557 const ::basegfx::B2DHomMatrix& rTextTransform );
1559 virtual bool render( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1560 virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1561 const Subset& rSubset ) const;
1563 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const;
1564 virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1565 const Subset& rSubset ) const;
1567 virtual sal_Int32 getActionCount() const;
1569 private:
1570 // TextRenderer interface
1571 virtual bool operator()( const rendering::RenderState& rRenderState ) const;
1573 // TODO(P2): This is potentially a real mass object
1574 // (every character might be a separate TextAction),
1575 // thus, make it as lightweight as possible. For
1576 // example, share common RenderState among several
1577 // TextActions, maybe using maOffsets for the
1578 // translation.
1580 uno::Reference< rendering::XPolyPolygon2D > mxTextPoly;
1582 /** This vector denotes the index of the start polygon
1583 for the respective glyph sequence.
1585 To get a polygon index range for a given character
1586 index i, take [ maPolygonGlyphMap[i],
1587 maPolygonGlyphMap[i+1] ). Note that this is wrong
1588 for BiDi
1590 const ::std::vector< sal_Int32 > maPolygonGlyphMap;
1591 const uno::Sequence< double > maOffsets;
1592 const CanvasSharedPtr mpCanvas;
1593 rendering::RenderState maState;
1594 double mnOutlineWidth;
1595 const uno::Sequence< double > maFillColor;
1596 const tools::TextLineInfo maTextLineInfo;
1597 ::basegfx::B2DSize maLinesOverallSize;
1598 const ::basegfx::B2DRectangle maOutlineBounds;
1599 uno::Reference< rendering::XPolyPolygon2D > mxTextLines;
1600 const ::basegfx::B2DSize maReliefOffset;
1601 const ::Color maReliefColor;
1602 const ::basegfx::B2DSize maShadowOffset;
1603 const ::Color maShadowColor;
1606 double calcOutlineWidth( const OutDevState& rState,
1607 VirtualDevice& rVDev )
1609 const ::basegfx::B2DSize aFontSize( 0,
1610 rVDev.GetFont().GetHeight() / 64.0 );
1612 const double nOutlineWidth(
1613 (rState.mapModeTransform * aFontSize).getY() );
1615 return nOutlineWidth < 1.0 ? 1.0 : nOutlineWidth;
1618 OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1619 const ::basegfx::B2DSize& rReliefOffset,
1620 const ::Color& rReliefColor,
1621 const ::basegfx::B2DSize& rShadowOffset,
1622 const ::Color& rShadowColor,
1623 const ::basegfx::B2DRectangle& rOutlineBounds,
1624 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1625 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1626 const uno::Sequence< double >& rOffsets,
1627 VirtualDevice& rVDev,
1628 const CanvasSharedPtr& rCanvas,
1629 const OutDevState& rState ) :
1630 mxTextPoly( rTextPoly ),
1631 maPolygonGlyphMap( rPolygonGlyphMap ),
1632 maOffsets( rOffsets ),
1633 mpCanvas( rCanvas ),
1634 maState(),
1635 mnOutlineWidth( calcOutlineWidth(rState,rVDev) ),
1636 maFillColor(
1637 ::vcl::unotools::colorToDoubleSequence(
1638 ::Color( COL_WHITE ),
1639 rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1640 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1641 maLinesOverallSize(),
1642 maOutlineBounds( rOutlineBounds ),
1643 mxTextLines(),
1644 maReliefOffset( rReliefOffset ),
1645 maReliefColor( rReliefColor ),
1646 maShadowOffset( rShadowOffset ),
1647 maShadowColor( rShadowColor )
1649 initEffectLinePolyPolygon( maLinesOverallSize,
1650 mxTextLines,
1651 rCanvas,
1652 rOffsets,
1653 maTextLineInfo );
1655 init( maState,
1656 rStartPoint,
1657 rState,
1658 rCanvas );
1661 OutlineAction::OutlineAction( const ::basegfx::B2DPoint& rStartPoint,
1662 const ::basegfx::B2DSize& rReliefOffset,
1663 const ::Color& rReliefColor,
1664 const ::basegfx::B2DSize& rShadowOffset,
1665 const ::Color& rShadowColor,
1666 const ::basegfx::B2DRectangle& rOutlineBounds,
1667 const uno::Reference< rendering::XPolyPolygon2D >& rTextPoly,
1668 const ::std::vector< sal_Int32 >& rPolygonGlyphMap,
1669 const uno::Sequence< double >& rOffsets,
1670 VirtualDevice& rVDev,
1671 const CanvasSharedPtr& rCanvas,
1672 const OutDevState& rState,
1673 const ::basegfx::B2DHomMatrix& rTextTransform ) :
1674 mxTextPoly( rTextPoly ),
1675 maPolygonGlyphMap( rPolygonGlyphMap ),
1676 maOffsets( rOffsets ),
1677 mpCanvas( rCanvas ),
1678 maState(),
1679 mnOutlineWidth( calcOutlineWidth(rState,rVDev) ),
1680 maFillColor(
1681 ::vcl::unotools::colorToDoubleSequence(
1682 ::Color( COL_WHITE ),
1683 rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() )),
1684 maTextLineInfo( tools::createTextLineInfo( rVDev, rState ) ),
1685 maLinesOverallSize(),
1686 maOutlineBounds( rOutlineBounds ),
1687 mxTextLines(),
1688 maReliefOffset( rReliefOffset ),
1689 maReliefColor( rReliefColor ),
1690 maShadowOffset( rShadowOffset ),
1691 maShadowColor( rShadowColor )
1693 initEffectLinePolyPolygon( maLinesOverallSize,
1694 mxTextLines,
1695 rCanvas,
1696 rOffsets,
1697 maTextLineInfo );
1699 init( maState,
1700 rStartPoint,
1701 rState,
1702 rCanvas,
1703 rTextTransform );
1706 bool OutlineAction::operator()( const rendering::RenderState& rRenderState ) const
1708 const rendering::ViewState& rViewState( mpCanvas->getViewState() );
1709 const uno::Reference< rendering::XCanvas >& rCanvas( mpCanvas->getUNOCanvas() );
1711 rendering::StrokeAttributes aStrokeAttributes;
1713 aStrokeAttributes.StrokeWidth = mnOutlineWidth;
1714 aStrokeAttributes.MiterLimit = 1.0;
1715 aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
1716 aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
1717 aStrokeAttributes.JoinType = rendering::PathJoinType::MITER;
1719 rendering::RenderState aLocalState( rRenderState );
1720 aLocalState.DeviceColor = maFillColor;
1722 // TODO(P1): implement caching
1724 // background of text
1725 rCanvas->fillPolyPolygon( mxTextPoly,
1726 rViewState,
1727 aLocalState );
1729 // border line of text
1730 rCanvas->strokePolyPolygon( mxTextPoly,
1731 rViewState,
1732 rRenderState,
1733 aStrokeAttributes );
1735 // underlines/strikethrough - background
1736 rCanvas->fillPolyPolygon( mxTextLines,
1737 rViewState,
1738 aLocalState );
1739 // underlines/strikethrough - border
1740 rCanvas->strokePolyPolygon( mxTextLines,
1741 rViewState,
1742 rRenderState,
1743 aStrokeAttributes );
1745 return true;
1748 bool OutlineAction::render( const ::basegfx::B2DHomMatrix& rTransformation ) const
1750 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction::render()" );
1751 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::EffectTextArrayAction: 0x" << std::hex << this );
1753 rendering::RenderState aLocalState( maState );
1754 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1756 return renderEffectText( *this,
1757 aLocalState,
1758 mpCanvas->getViewState(),
1759 mpCanvas->getUNOCanvas(),
1760 maShadowColor,
1761 maShadowOffset,
1762 maReliefColor,
1763 maReliefOffset );
1766 class OutlineTextArrayRenderHelper : public TextRenderer
1768 public:
1769 OutlineTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas,
1770 const uno::Reference< rendering::XPolyPolygon2D >& rTextPolygon,
1771 const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon,
1772 const rendering::ViewState& rViewState,
1773 double nOutlineWidth ) :
1774 maFillColor(
1775 ::vcl::unotools::colorToDoubleSequence(
1776 ::Color( COL_WHITE ),
1777 rCanvas->getDevice()->getDeviceColorSpace() )),
1778 mnOutlineWidth( nOutlineWidth ),
1779 mrCanvas( rCanvas ),
1780 mrTextPolygon( rTextPolygon ),
1781 mrLinePolygon( rLinePolygon ),
1782 mrViewState( rViewState )
1786 // TextRenderer interface
1787 virtual bool operator()( const rendering::RenderState& rRenderState ) const
1789 rendering::StrokeAttributes aStrokeAttributes;
1791 aStrokeAttributes.StrokeWidth = mnOutlineWidth;
1792 aStrokeAttributes.MiterLimit = 1.0;
1793 aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
1794 aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
1795 aStrokeAttributes.JoinType = rendering::PathJoinType::MITER;
1797 rendering::RenderState aLocalState( rRenderState );
1798 aLocalState.DeviceColor = maFillColor;
1800 // TODO(P1): implement caching
1802 // background of text
1803 mrCanvas->fillPolyPolygon( mrTextPolygon,
1804 mrViewState,
1805 aLocalState );
1807 // border line of text
1808 mrCanvas->strokePolyPolygon( mrTextPolygon,
1809 mrViewState,
1810 rRenderState,
1811 aStrokeAttributes );
1813 // underlines/strikethrough - background
1814 mrCanvas->fillPolyPolygon( mrLinePolygon,
1815 mrViewState,
1816 aLocalState );
1817 // underlines/strikethrough - border
1818 mrCanvas->strokePolyPolygon( mrLinePolygon,
1819 mrViewState,
1820 rRenderState,
1821 aStrokeAttributes );
1823 return true;
1826 private:
1827 const uno::Sequence< double > maFillColor;
1828 double mnOutlineWidth;
1829 const uno::Reference< rendering::XCanvas >& mrCanvas;
1830 const uno::Reference< rendering::XPolyPolygon2D >& mrTextPolygon;
1831 const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon;
1832 const rendering::ViewState& mrViewState;
1835 bool OutlineAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1836 const Subset& rSubset ) const
1838 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction::renderSubset()" );
1839 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction: 0x" << std::hex << this );
1841 if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd )
1842 return true; // empty range, render nothing
1844 #if 1
1845 // TODO(F3): Subsetting NYI for outline text!
1846 return render( rTransformation );
1847 #else
1848 const rendering::StringContext rOrigContext( mxTextLayout->getText() );
1850 if( rSubset.mnSubsetBegin == 0 &&
1851 rSubset.mnSubsetEnd == rOrigContext.Length )
1853 // full range, no need for subsetting
1854 return render( rTransformation );
1857 rendering::RenderState aLocalState( maState );
1858 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1861 // create and setup local Text polygon
1862 // ===================================
1864 uno::Reference< rendering::XPolyPolygon2D > xTextPolygon();
1866 // TODO(P3): Provide an API method for that!
1868 if( !xTextLayout.is() )
1869 return false;
1871 // render everything
1872 // =================
1874 return renderEffectText(
1875 OutlineTextArrayRenderHelper(
1876 xCanvas,
1877 mnOutlineWidth,
1878 xTextLayout,
1879 xTextLines,
1880 rViewState ),
1881 aLocalState,
1882 rViewState,
1883 xCanvas,
1884 maShadowColor,
1885 maShadowOffset,
1886 maReliefColor,
1887 maReliefOffset );
1888 #endif
1891 ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1893 rendering::RenderState aLocalState( maState );
1894 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1896 return calcEffectTextBounds( maOutlineBounds,
1897 ::basegfx::B2DRange( 0,0,
1898 maLinesOverallSize.getX(),
1899 maLinesOverallSize.getY() ),
1900 maReliefOffset,
1901 maShadowOffset,
1902 aLocalState,
1903 mpCanvas->getViewState() );
1906 ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1907 const Subset& /*rSubset*/ ) const
1909 SAL_WARN( "cppcanvas.emf", "OutlineAction::getBounds(): Subset not yet supported by this object" );
1911 return getBounds( rTransformation );
1914 sal_Int32 OutlineAction::getActionCount() const
1916 // TODO(F3): Subsetting NYI for outline text!
1917 return maOffsets.getLength();
1921 // ======================================================================
1923 // Action factory methods
1925 // ======================================================================
1927 /** Create an outline action
1929 This method extracts the polygonal outline from the
1930 text, and creates a properly setup OutlineAction from
1933 ActionSharedPtr createOutline( const ::basegfx::B2DPoint& rStartPoint,
1934 const ::basegfx::B2DSize& rReliefOffset,
1935 const ::Color& rReliefColor,
1936 const ::basegfx::B2DSize& rShadowOffset,
1937 const ::Color& rShadowColor,
1938 const String& rText,
1939 sal_Int32 nStartPos,
1940 sal_Int32 nLen,
1941 const sal_Int32* pDXArray,
1942 VirtualDevice& rVDev,
1943 const CanvasSharedPtr& rCanvas,
1944 const OutDevState& rState,
1945 const Renderer::Parameters& rParms )
1947 // operate on raw DX array here (in logical coordinate
1948 // system), to have a higher resolution
1949 // PolyPolygon. That polygon is then converted to
1950 // device coordinate system.
1952 // #i68512# Temporarily switch off font rotation
1953 // (which is already contained in the render state
1954 // transformation matrix - otherwise, glyph polygons
1955 // will be rotated twice)
1956 const ::Font aOrigFont( rVDev.GetFont() );
1957 ::Font aUnrotatedFont( aOrigFont );
1958 aUnrotatedFont.SetOrientation(0);
1959 rVDev.SetFont( aUnrotatedFont );
1961 // TODO(F3): Don't understand parameter semantics of
1962 // GetTextOutlines()
1963 ::basegfx::B2DPolyPolygon aResultingPolyPolygon;
1964 PolyPolyVector aVCLPolyPolyVector;
1965 const bool bHaveOutlines( rVDev.GetTextOutlines( aVCLPolyPolyVector, rText,
1966 static_cast<sal_uInt16>(nStartPos),
1967 static_cast<sal_uInt16>(nStartPos),
1968 static_cast<sal_uInt16>(nLen),
1969 sal_True, 0, pDXArray ) );
1970 rVDev.SetFont(aOrigFont);
1972 if( !bHaveOutlines )
1973 return ActionSharedPtr();
1975 ::std::vector< sal_Int32 > aPolygonGlyphMap;
1977 // first glyph starts at polygon index 0
1978 aPolygonGlyphMap.push_back( 0 );
1980 // remove offsetting from mapmode transformation
1981 // (outline polygons must stay at origin, only need to
1982 // be scaled)
1983 ::basegfx::B2DHomMatrix aMapModeTransform(
1984 rState.mapModeTransform );
1985 aMapModeTransform.set(0,2, 0.0);
1986 aMapModeTransform.set(1,2, 0.0);
1988 PolyPolyVector::const_iterator aIter( aVCLPolyPolyVector.begin() );
1989 const PolyPolyVector::const_iterator aEnd( aVCLPolyPolyVector.end() );
1990 for( ; aIter!= aEnd; ++aIter )
1992 ::basegfx::B2DPolyPolygon aPolyPolygon;
1994 aPolyPolygon = aIter->getB2DPolyPolygon();
1995 aPolyPolygon.transform( aMapModeTransform );
1997 // append result to collecting polypoly
1998 for( sal_uInt32 i=0; i<aPolyPolygon.count(); ++i )
2000 // #i47795# Ensure closed polygons (since
2001 // FreeType returns the glyph outlines
2002 // open)
2003 const ::basegfx::B2DPolygon& rPoly( aPolyPolygon.getB2DPolygon( i ) );
2004 const sal_uInt32 nCount( rPoly.count() );
2005 if( nCount<3 ||
2006 rPoly.isClosed() )
2008 // polygon either degenerate, or
2009 // already closed.
2010 aResultingPolyPolygon.append( rPoly );
2012 else
2014 ::basegfx::B2DPolygon aPoly(rPoly);
2015 aPoly.setClosed(true);
2017 aResultingPolyPolygon.append( aPoly );
2021 // TODO(F3): Depending on the semantics of
2022 // GetTextOutlines(), this here is wrong!
2024 // calc next glyph index
2025 aPolygonGlyphMap.push_back( aResultingPolyPolygon.count() );
2028 const uno::Sequence< double > aCharWidthSeq(
2029 pDXArray ?
2030 setupDXArray( pDXArray, nLen, rState ) :
2031 setupDXArray( rText,
2032 nStartPos,
2033 nLen,
2034 rVDev,
2035 rState ));
2036 const uno::Reference< rendering::XPolyPolygon2D > xTextPoly(
2037 ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
2038 rCanvas->getUNOCanvas()->getDevice(),
2039 aResultingPolyPolygon ) );
2041 if( rParms.maTextTransformation.is_initialized() )
2043 return ActionSharedPtr(
2044 new OutlineAction(
2045 rStartPoint,
2046 rReliefOffset,
2047 rReliefColor,
2048 rShadowOffset,
2049 rShadowColor,
2050 ::basegfx::tools::getRange(aResultingPolyPolygon),
2051 xTextPoly,
2052 aPolygonGlyphMap,
2053 aCharWidthSeq,
2054 rVDev,
2055 rCanvas,
2056 rState,
2057 *rParms.maTextTransformation ) );
2059 else
2061 return ActionSharedPtr(
2062 new OutlineAction(
2063 rStartPoint,
2064 rReliefOffset,
2065 rReliefColor,
2066 rShadowOffset,
2067 rShadowColor,
2068 ::basegfx::tools::getRange(aResultingPolyPolygon),
2069 xTextPoly,
2070 aPolygonGlyphMap,
2071 aCharWidthSeq,
2072 rVDev,
2073 rCanvas,
2074 rState ) );
2078 } // namespace
2081 // ---------------------------------------------------------------------------------
2083 ActionSharedPtr TextActionFactory::createTextAction( const ::Point& rStartPoint,
2084 const ::Size& rReliefOffset,
2085 const ::Color& rReliefColor,
2086 const ::Size& rShadowOffset,
2087 const ::Color& rShadowColor,
2088 const String& rText,
2089 sal_Int32 nStartPos,
2090 sal_Int32 nLen,
2091 const sal_Int32* pDXArray,
2092 VirtualDevice& rVDev,
2093 const CanvasSharedPtr& rCanvas,
2094 const OutDevState& rState,
2095 const Renderer::Parameters& rParms,
2096 bool bSubsettable )
2098 const ::Size aBaselineOffset( tools::getBaselineOffset( rState,
2099 rVDev ) );
2100 // #143885# maintain (nearly) full precision positioning,
2101 // by circumventing integer-based OutDev-mapping
2102 const ::basegfx::B2DPoint aStartPoint(
2103 rState.mapModeTransform *
2104 ::basegfx::B2DPoint(rStartPoint.X() + aBaselineOffset.Width(),
2105 rStartPoint.Y() + aBaselineOffset.Height()) );
2107 const ::basegfx::B2DSize aReliefOffset(
2108 rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rReliefOffset ) );
2109 const ::basegfx::B2DSize aShadowOffset(
2110 rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rShadowOffset ) );
2112 if( rState.isTextOutlineModeSet )
2114 return createOutline(
2115 aStartPoint,
2116 aReliefOffset,
2117 rReliefColor,
2118 aShadowOffset,
2119 rShadowColor,
2120 rText,
2121 nStartPos,
2122 nLen,
2123 pDXArray,
2124 rVDev,
2125 rCanvas,
2126 rState,
2127 rParms );
2130 // convert DX array to device coordinate system (and
2131 // create it in the first place, if pDXArray is NULL)
2132 const uno::Sequence< double > aCharWidths(
2133 pDXArray ?
2134 setupDXArray( pDXArray, nLen, rState ) :
2135 setupDXArray( rText,
2136 nStartPos,
2137 nLen,
2138 rVDev,
2139 rState ));
2141 // determine type of text action to create
2142 // =======================================
2144 const ::Color aEmptyColor( COL_AUTO );
2146 // no DX array, and no need to subset - no need to store
2147 // DX array, then.
2148 if( !pDXArray && !bSubsettable )
2150 // effects, or not?
2151 if( !rState.textOverlineStyle &&
2152 !rState.textUnderlineStyle &&
2153 !rState.textStrikeoutStyle &&
2154 rReliefColor == aEmptyColor &&
2155 rShadowColor == aEmptyColor )
2157 // nope
2158 if( rParms.maTextTransformation.is_initialized() )
2160 return ActionSharedPtr( new TextAction(
2161 aStartPoint,
2162 rText,
2163 nStartPos,
2164 nLen,
2165 rCanvas,
2166 rState,
2167 *rParms.maTextTransformation ) );
2169 else
2171 return ActionSharedPtr( new TextAction(
2172 aStartPoint,
2173 rText,
2174 nStartPos,
2175 nLen,
2176 rCanvas,
2177 rState ) );
2180 else
2182 // at least one of the effects requested
2183 if( rParms.maTextTransformation.is_initialized() )
2184 return ActionSharedPtr( new EffectTextAction(
2185 aStartPoint,
2186 aReliefOffset,
2187 rReliefColor,
2188 aShadowOffset,
2189 rShadowColor,
2190 rText,
2191 nStartPos,
2192 nLen,
2193 rVDev,
2194 rCanvas,
2195 rState,
2196 *rParms.maTextTransformation ) );
2197 else
2198 return ActionSharedPtr( new EffectTextAction(
2199 aStartPoint,
2200 aReliefOffset,
2201 rReliefColor,
2202 aShadowOffset,
2203 rShadowColor,
2204 rText,
2205 nStartPos,
2206 nLen,
2207 rVDev,
2208 rCanvas,
2209 rState ) );
2212 else
2214 // DX array necessary - any effects?
2215 if( !rState.textOverlineStyle &&
2216 !rState.textUnderlineStyle &&
2217 !rState.textStrikeoutStyle &&
2218 rReliefColor == aEmptyColor &&
2219 rShadowColor == aEmptyColor )
2221 // nope
2222 if( rParms.maTextTransformation.is_initialized() )
2223 return ActionSharedPtr( new TextArrayAction(
2224 aStartPoint,
2225 rText,
2226 nStartPos,
2227 nLen,
2228 aCharWidths,
2229 rCanvas,
2230 rState,
2231 *rParms.maTextTransformation ) );
2232 else
2233 return ActionSharedPtr( new TextArrayAction(
2234 aStartPoint,
2235 rText,
2236 nStartPos,
2237 nLen,
2238 aCharWidths,
2239 rCanvas,
2240 rState ) );
2242 else
2244 // at least one of the effects requested
2245 if( rParms.maTextTransformation.is_initialized() )
2246 return ActionSharedPtr( new EffectTextArrayAction(
2247 aStartPoint,
2248 aReliefOffset,
2249 rReliefColor,
2250 aShadowOffset,
2251 rShadowColor,
2252 rText,
2253 nStartPos,
2254 nLen,
2255 aCharWidths,
2256 rVDev,
2257 rCanvas,
2258 rState,
2259 *rParms.maTextTransformation ) );
2260 else
2261 return ActionSharedPtr( new EffectTextArrayAction(
2262 aStartPoint,
2263 aReliefOffset,
2264 rReliefColor,
2265 aShadowOffset,
2266 rShadowColor,
2267 rText,
2268 nStartPos,
2269 nLen,
2270 aCharWidths,
2271 rVDev,
2272 rCanvas,
2273 rState ) );
2276 #if defined(__GNUC__)
2277 return ActionSharedPtr();
2278 #endif
2283 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */