Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / cppcanvas / source / mtfrenderer / textaction.cxx
blob65d1843e1ae08971db715109bd69caf36b67b645
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 OUString& rText,
193 sal_Int32 nStartPos,
194 sal_Int32 nLen,
195 VirtualDevice& rVDev,
196 const OutDevState& rState )
198 // no external DX array given, create one from given
199 // string
200 ::boost::scoped_array< 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 #if 0 // see #if'ed out use in OutlineAction::renderSubset below:
1767 class OutlineTextArrayRenderHelper : public TextRenderer
1769 public:
1770 OutlineTextArrayRenderHelper( const uno::Reference< rendering::XCanvas >& rCanvas,
1771 const uno::Reference< rendering::XPolyPolygon2D >& rTextPolygon,
1772 const uno::Reference< rendering::XPolyPolygon2D >& rLinePolygon,
1773 const rendering::ViewState& rViewState,
1774 double nOutlineWidth ) :
1775 maFillColor(
1776 ::vcl::unotools::colorToDoubleSequence(
1777 ::Color( COL_WHITE ),
1778 rCanvas->getDevice()->getDeviceColorSpace() )),
1779 mnOutlineWidth( nOutlineWidth ),
1780 mrCanvas( rCanvas ),
1781 mrTextPolygon( rTextPolygon ),
1782 mrLinePolygon( rLinePolygon ),
1783 mrViewState( rViewState )
1787 // TextRenderer interface
1788 virtual bool operator()( const rendering::RenderState& rRenderState ) const
1790 rendering::StrokeAttributes aStrokeAttributes;
1792 aStrokeAttributes.StrokeWidth = mnOutlineWidth;
1793 aStrokeAttributes.MiterLimit = 1.0;
1794 aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
1795 aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
1796 aStrokeAttributes.JoinType = rendering::PathJoinType::MITER;
1798 rendering::RenderState aLocalState( rRenderState );
1799 aLocalState.DeviceColor = maFillColor;
1801 // TODO(P1): implement caching
1803 // background of text
1804 mrCanvas->fillPolyPolygon( mrTextPolygon,
1805 mrViewState,
1806 aLocalState );
1808 // border line of text
1809 mrCanvas->strokePolyPolygon( mrTextPolygon,
1810 mrViewState,
1811 rRenderState,
1812 aStrokeAttributes );
1814 // underlines/strikethrough - background
1815 mrCanvas->fillPolyPolygon( mrLinePolygon,
1816 mrViewState,
1817 aLocalState );
1818 // underlines/strikethrough - border
1819 mrCanvas->strokePolyPolygon( mrLinePolygon,
1820 mrViewState,
1821 rRenderState,
1822 aStrokeAttributes );
1824 return true;
1827 private:
1828 const uno::Sequence< double > maFillColor;
1829 double mnOutlineWidth;
1830 const uno::Reference< rendering::XCanvas >& mrCanvas;
1831 const uno::Reference< rendering::XPolyPolygon2D >& mrTextPolygon;
1832 const uno::Reference< rendering::XPolyPolygon2D >& mrLinePolygon;
1833 const rendering::ViewState& mrViewState;
1835 #endif
1837 bool OutlineAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
1838 const Subset& rSubset ) const
1840 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction::renderSubset()" );
1841 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::OutlineAction: 0x" << std::hex << this );
1843 if( rSubset.mnSubsetBegin == rSubset.mnSubsetEnd )
1844 return true; // empty range, render nothing
1846 #if 1
1847 // TODO(F3): Subsetting NYI for outline text!
1848 return render( rTransformation );
1849 #else
1850 const rendering::StringContext rOrigContext( mxTextLayout->getText() );
1852 if( rSubset.mnSubsetBegin == 0 &&
1853 rSubset.mnSubsetEnd == rOrigContext.Length )
1855 // full range, no need for subsetting
1856 return render( rTransformation );
1859 rendering::RenderState aLocalState( maState );
1860 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1863 // create and setup local Text polygon
1864 // ===================================
1866 uno::Reference< rendering::XPolyPolygon2D > xTextPolygon();
1868 // TODO(P3): Provide an API method for that!
1870 if( !xTextLayout.is() )
1871 return false;
1873 // render everything
1874 // =================
1876 return renderEffectText(
1877 OutlineTextArrayRenderHelper(
1878 xCanvas,
1879 mnOutlineWidth,
1880 xTextLayout,
1881 xTextLines,
1882 rViewState ),
1883 aLocalState,
1884 rViewState,
1885 xCanvas,
1886 maShadowColor,
1887 maShadowOffset,
1888 maReliefColor,
1889 maReliefOffset );
1890 #endif
1893 ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
1895 rendering::RenderState aLocalState( maState );
1896 ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
1898 return calcEffectTextBounds( maOutlineBounds,
1899 ::basegfx::B2DRange( 0,0,
1900 maLinesOverallSize.getX(),
1901 maLinesOverallSize.getY() ),
1902 maReliefOffset,
1903 maShadowOffset,
1904 aLocalState,
1905 mpCanvas->getViewState() );
1908 ::basegfx::B2DRange OutlineAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
1909 const Subset& /*rSubset*/ ) const
1911 SAL_WARN( "cppcanvas.emf", "OutlineAction::getBounds(): Subset not yet supported by this object" );
1913 return getBounds( rTransformation );
1916 sal_Int32 OutlineAction::getActionCount() const
1918 // TODO(F3): Subsetting NYI for outline text!
1919 return maOffsets.getLength();
1923 // ======================================================================
1925 // Action factory methods
1927 // ======================================================================
1929 /** Create an outline action
1931 This method extracts the polygonal outline from the
1932 text, and creates a properly setup OutlineAction from
1935 ActionSharedPtr createOutline( const ::basegfx::B2DPoint& rStartPoint,
1936 const ::basegfx::B2DSize& rReliefOffset,
1937 const ::Color& rReliefColor,
1938 const ::basegfx::B2DSize& rShadowOffset,
1939 const ::Color& rShadowColor,
1940 const OUString& rText,
1941 sal_Int32 nStartPos,
1942 sal_Int32 nLen,
1943 const sal_Int32* pDXArray,
1944 VirtualDevice& rVDev,
1945 const CanvasSharedPtr& rCanvas,
1946 const OutDevState& rState,
1947 const Renderer::Parameters& rParms )
1949 // operate on raw DX array here (in logical coordinate
1950 // system), to have a higher resolution
1951 // PolyPolygon. That polygon is then converted to
1952 // device coordinate system.
1954 // #i68512# Temporarily switch off font rotation
1955 // (which is already contained in the render state
1956 // transformation matrix - otherwise, glyph polygons
1957 // will be rotated twice)
1958 const ::Font aOrigFont( rVDev.GetFont() );
1959 ::Font aUnrotatedFont( aOrigFont );
1960 aUnrotatedFont.SetOrientation(0);
1961 rVDev.SetFont( aUnrotatedFont );
1963 // TODO(F3): Don't understand parameter semantics of
1964 // GetTextOutlines()
1965 ::basegfx::B2DPolyPolygon aResultingPolyPolygon;
1966 PolyPolyVector aVCLPolyPolyVector;
1967 const bool bHaveOutlines( rVDev.GetTextOutlines( aVCLPolyPolyVector, rText,
1968 static_cast<sal_uInt16>(nStartPos),
1969 static_cast<sal_uInt16>(nStartPos),
1970 static_cast<sal_uInt16>(nLen),
1971 sal_True, 0, pDXArray ) );
1972 rVDev.SetFont(aOrigFont);
1974 if( !bHaveOutlines )
1975 return ActionSharedPtr();
1977 ::std::vector< sal_Int32 > aPolygonGlyphMap;
1979 // first glyph starts at polygon index 0
1980 aPolygonGlyphMap.push_back( 0 );
1982 // remove offsetting from mapmode transformation
1983 // (outline polygons must stay at origin, only need to
1984 // be scaled)
1985 ::basegfx::B2DHomMatrix aMapModeTransform(
1986 rState.mapModeTransform );
1987 aMapModeTransform.set(0,2, 0.0);
1988 aMapModeTransform.set(1,2, 0.0);
1990 PolyPolyVector::const_iterator aIter( aVCLPolyPolyVector.begin() );
1991 const PolyPolyVector::const_iterator aEnd( aVCLPolyPolyVector.end() );
1992 for( ; aIter!= aEnd; ++aIter )
1994 ::basegfx::B2DPolyPolygon aPolyPolygon;
1996 aPolyPolygon = aIter->getB2DPolyPolygon();
1997 aPolyPolygon.transform( aMapModeTransform );
1999 // append result to collecting polypoly
2000 for( sal_uInt32 i=0; i<aPolyPolygon.count(); ++i )
2002 // #i47795# Ensure closed polygons (since
2003 // FreeType returns the glyph outlines
2004 // open)
2005 const ::basegfx::B2DPolygon& rPoly( aPolyPolygon.getB2DPolygon( i ) );
2006 const sal_uInt32 nCount( rPoly.count() );
2007 if( nCount<3 ||
2008 rPoly.isClosed() )
2010 // polygon either degenerate, or
2011 // already closed.
2012 aResultingPolyPolygon.append( rPoly );
2014 else
2016 ::basegfx::B2DPolygon aPoly(rPoly);
2017 aPoly.setClosed(true);
2019 aResultingPolyPolygon.append( aPoly );
2023 // TODO(F3): Depending on the semantics of
2024 // GetTextOutlines(), this here is wrong!
2026 // calc next glyph index
2027 aPolygonGlyphMap.push_back( aResultingPolyPolygon.count() );
2030 const uno::Sequence< double > aCharWidthSeq(
2031 pDXArray ?
2032 setupDXArray( pDXArray, nLen, rState ) :
2033 setupDXArray( rText,
2034 nStartPos,
2035 nLen,
2036 rVDev,
2037 rState ));
2038 const uno::Reference< rendering::XPolyPolygon2D > xTextPoly(
2039 ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
2040 rCanvas->getUNOCanvas()->getDevice(),
2041 aResultingPolyPolygon ) );
2043 if( rParms.maTextTransformation.is_initialized() )
2045 return ActionSharedPtr(
2046 new OutlineAction(
2047 rStartPoint,
2048 rReliefOffset,
2049 rReliefColor,
2050 rShadowOffset,
2051 rShadowColor,
2052 ::basegfx::tools::getRange(aResultingPolyPolygon),
2053 xTextPoly,
2054 aPolygonGlyphMap,
2055 aCharWidthSeq,
2056 rVDev,
2057 rCanvas,
2058 rState,
2059 *rParms.maTextTransformation ) );
2061 else
2063 return ActionSharedPtr(
2064 new OutlineAction(
2065 rStartPoint,
2066 rReliefOffset,
2067 rReliefColor,
2068 rShadowOffset,
2069 rShadowColor,
2070 ::basegfx::tools::getRange(aResultingPolyPolygon),
2071 xTextPoly,
2072 aPolygonGlyphMap,
2073 aCharWidthSeq,
2074 rVDev,
2075 rCanvas,
2076 rState ) );
2080 } // namespace
2083 // ---------------------------------------------------------------------------------
2085 ActionSharedPtr TextActionFactory::createTextAction( const ::Point& rStartPoint,
2086 const ::Size& rReliefOffset,
2087 const ::Color& rReliefColor,
2088 const ::Size& rShadowOffset,
2089 const ::Color& rShadowColor,
2090 const OUString& rText,
2091 sal_Int32 nStartPos,
2092 sal_Int32 nLen,
2093 const sal_Int32* pDXArray,
2094 VirtualDevice& rVDev,
2095 const CanvasSharedPtr& rCanvas,
2096 const OutDevState& rState,
2097 const Renderer::Parameters& rParms,
2098 bool bSubsettable )
2100 const ::Size aBaselineOffset( tools::getBaselineOffset( rState,
2101 rVDev ) );
2102 // #143885# maintain (nearly) full precision positioning,
2103 // by circumventing integer-based OutDev-mapping
2104 const ::basegfx::B2DPoint aStartPoint(
2105 rState.mapModeTransform *
2106 ::basegfx::B2DPoint(rStartPoint.X() + aBaselineOffset.Width(),
2107 rStartPoint.Y() + aBaselineOffset.Height()) );
2109 const ::basegfx::B2DSize aReliefOffset(
2110 rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rReliefOffset ) );
2111 const ::basegfx::B2DSize aShadowOffset(
2112 rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize( rShadowOffset ) );
2114 if( rState.isTextOutlineModeSet )
2116 return createOutline(
2117 aStartPoint,
2118 aReliefOffset,
2119 rReliefColor,
2120 aShadowOffset,
2121 rShadowColor,
2122 rText,
2123 nStartPos,
2124 nLen,
2125 pDXArray,
2126 rVDev,
2127 rCanvas,
2128 rState,
2129 rParms );
2132 // convert DX array to device coordinate system (and
2133 // create it in the first place, if pDXArray is NULL)
2134 const uno::Sequence< double > aCharWidths(
2135 pDXArray ?
2136 setupDXArray( pDXArray, nLen, rState ) :
2137 setupDXArray( rText,
2138 nStartPos,
2139 nLen,
2140 rVDev,
2141 rState ));
2143 // determine type of text action to create
2144 // =======================================
2146 const ::Color aEmptyColor( COL_AUTO );
2148 // no DX array, and no need to subset - no need to store
2149 // DX array, then.
2150 if( !pDXArray && !bSubsettable )
2152 // effects, or not?
2153 if( !rState.textOverlineStyle &&
2154 !rState.textUnderlineStyle &&
2155 !rState.textStrikeoutStyle &&
2156 rReliefColor == aEmptyColor &&
2157 rShadowColor == aEmptyColor )
2159 // nope
2160 if( rParms.maTextTransformation.is_initialized() )
2162 return ActionSharedPtr( new TextAction(
2163 aStartPoint,
2164 rText,
2165 nStartPos,
2166 nLen,
2167 rCanvas,
2168 rState,
2169 *rParms.maTextTransformation ) );
2171 else
2173 return ActionSharedPtr( new TextAction(
2174 aStartPoint,
2175 rText,
2176 nStartPos,
2177 nLen,
2178 rCanvas,
2179 rState ) );
2182 else
2184 // at least one of the effects requested
2185 if( rParms.maTextTransformation.is_initialized() )
2186 return ActionSharedPtr( new EffectTextAction(
2187 aStartPoint,
2188 aReliefOffset,
2189 rReliefColor,
2190 aShadowOffset,
2191 rShadowColor,
2192 rText,
2193 nStartPos,
2194 nLen,
2195 rVDev,
2196 rCanvas,
2197 rState,
2198 *rParms.maTextTransformation ) );
2199 else
2200 return ActionSharedPtr( new EffectTextAction(
2201 aStartPoint,
2202 aReliefOffset,
2203 rReliefColor,
2204 aShadowOffset,
2205 rShadowColor,
2206 rText,
2207 nStartPos,
2208 nLen,
2209 rVDev,
2210 rCanvas,
2211 rState ) );
2214 else
2216 // DX array necessary - any effects?
2217 if( !rState.textOverlineStyle &&
2218 !rState.textUnderlineStyle &&
2219 !rState.textStrikeoutStyle &&
2220 rReliefColor == aEmptyColor &&
2221 rShadowColor == aEmptyColor )
2223 // nope
2224 if( rParms.maTextTransformation.is_initialized() )
2225 return ActionSharedPtr( new TextArrayAction(
2226 aStartPoint,
2227 rText,
2228 nStartPos,
2229 nLen,
2230 aCharWidths,
2231 rCanvas,
2232 rState,
2233 *rParms.maTextTransformation ) );
2234 else
2235 return ActionSharedPtr( new TextArrayAction(
2236 aStartPoint,
2237 rText,
2238 nStartPos,
2239 nLen,
2240 aCharWidths,
2241 rCanvas,
2242 rState ) );
2244 else
2246 // at least one of the effects requested
2247 if( rParms.maTextTransformation.is_initialized() )
2248 return ActionSharedPtr( new EffectTextArrayAction(
2249 aStartPoint,
2250 aReliefOffset,
2251 rReliefColor,
2252 aShadowOffset,
2253 rShadowColor,
2254 rText,
2255 nStartPos,
2256 nLen,
2257 aCharWidths,
2258 rVDev,
2259 rCanvas,
2260 rState,
2261 *rParms.maTextTransformation ) );
2262 else
2263 return ActionSharedPtr( new EffectTextArrayAction(
2264 aStartPoint,
2265 aReliefOffset,
2266 rReliefColor,
2267 aShadowOffset,
2268 rShadowColor,
2269 rText,
2270 nStartPos,
2271 nLen,
2272 aCharWidths,
2273 rVDev,
2274 rCanvas,
2275 rState ) );
2278 #if defined(__GNUC__)
2279 return ActionSharedPtr();
2280 #endif
2285 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */